PDA

View Full Version : Animated Collapsible DIV v2.2 Cookie?



ThunderLee
06-27-2009, 12:36 AM
1) Script Title: Animated Collapsible DIV v2.2

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

3) Describe problem:

How can I use cookies with this script? So if users expand/collapse a table and they close the browser and go back onto my website I want the table to be how they left it, how do I set this? I have looked through the script and found this:
(in animatedcollapse.js)


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
},

setCookie:function(name, value, days){
if (typeof days!="undefined"){ //if set persistent cookie
var expireDate = new Date()
expireDate.setDate(expireDate.getDate()+days)
document.cookie = name+"="+value+"; path=/; expires="+expireDate.toGMTString()
}
else //else if this is a session only cookie
document.cookie = name+"="+value+"; path=/"
},

How do I get it to work? (My website uses sessions for login and I want this to use cookies to remember the table state)

Thanks ;)..

EDIT:

Sorry, how could I also do it if I click the plus (Then my table expands) then when the tables expanded to show a minus, then when I collapse it shows a plus again? (See my site for example)

(My site: www.m3diaserver.com) Clicking the plus boxs makes the tables expand/collapse

ddadmin
06-28-2009, 12:37 AM
To enable persistent cookies (so they last longer than just the browser session), inside the .js file, try finding the two lines below, and add to them the code in red:


this.setCookie('acopendivids', opendivids, 5)
this.setCookie('acgroupswithpersist', groupswithpersist, 5)

Where 5 means persist for 5 days here.


how could I also do it if I click the plus (Then my table expands) then when the tables expanded to show a minus, then when I collapse it shows a plus again? (See my site for example)

You'll need to use the ontoggle() (http://www.dynamicdrive.com/dynamicindex17/animatedcollapse_suppliment.htm) event handler to do this, since you're basically talking about manipulating the src of an arbitrary image on the page depending on the state of a collapsible DIV. Assuming each image associated with the DIV carries the ID "divid-image", where divid is the ID of your collapsible DIV, your ontoggle() code may look something like this:


animatedcollapse.ontoggle=function($, divobj, state){
document.getElementById(divobj.id+"-image").src=(state=="block")? "collapse.jpg" : "expand.jpg"
}

ThunderLee
06-28-2009, 09:44 PM
Hi thanks for the reply, I still can't get the cookie to work and as for the session cookie that didn't work anyway..

Full animatedcollapse.js



var animatedcollapse={
divholders: {}, //structure: {div.id, div.attrs, div.$divref}
divgroups: {}, //structure: {groupname.count, groupname.lastactivedivid}
statusholders: {}, //structure: {[statuselement.id, stype, [opensrc, closedsrc]], $target}
lastactiveingroup: {}, //structure: {lastactivediv.id}

show:function(divids){ //public method
if (typeof divids=="object"){
for (var i=0; i<divids.length; i++)
this.showhide(divids[i], "show")
}
else
this.showhide(divids, "show")
},

hide:function(divids){ //public method
if (typeof divids=="object"){
for (var i=0; i<divids.length; i++)
this.showhide(divids[i], "hide")
}
else
this.showhide(divids, "hide")
},

toggle:function(divid){ //public method
if (typeof divid=="object")
divid=divid[0]
this.showhide(divid, "toggle")
},

addDiv:function(divid, attrstring){ //public function
this.divholders[divid]=({id: divid, $divref: null, attrs: attrstring})
this.divholders[divid].getAttr=function(name){ //assign getAttr() function to each divholder object
var attr=new RegExp(name+"=([^,]+)", "i") //get name/value config pair (ie: width=400px,)
return (attr.test(this.attrs) && parseInt(RegExp.$1)!=0)? RegExp.$1 : null //return value portion (string), or 0 (false) if none found
}
this.currentid=divid //keep track of current div object being manipulated (in the event of chaining)
return this
},

showhide:function(divid, action){
var $divref=this.divholders[divid].$divref //reference collapsible DIV
if (this.divholders[divid] && $divref.length==1){ //if DIV exists
var targetgroup=this.divgroups[$divref.attr('groupname')] //find out which group DIV belongs to (if any)
if ($divref.attr('groupname') && targetgroup.count>1 && (action=="show" || action=="toggle" && $divref.css('display')=='none')){ //If current DIV belongs to a group
if (targetgroup.lastactivedivid && targetgroup.lastactivedivid!=divid) //if last active DIV is set
this.slideengine(targetgroup.lastactivedivid, 'hide') //hide last active DIV within group first
this.slideengine(divid, 'show')
targetgroup.lastactivedivid=divid //remember last active DIV
}
else{
this.slideengine(divid, action)
}
}
},

slideengine:function(divid, action){
var $divref=this.divholders[divid].$divref
if (this.divholders[divid] && $divref.length==1){ //if this DIV exists
var animateSetting={height: action}
if ($divref.attr('fade'))
animateSetting.opacity=action
$divref.animate(animateSetting, $divref.attr('speed')? parseInt($divref.attr('speed')) : 500, function(){
if (animatedcollapse.ontoggle){
try{
animatedcollapse.ontoggle(jQuery, $divref.get(0), $divref.css('display'))
}
catch(e){
alert("An error exists inside your \"ontoggle\" function:\n\n"+e+"\n\nAborting execution of function.")
}
}
})
return false
}
},

generatemap:function(){
var map={}
for (var i=0; i<arguments.length; i++){
if (arguments[i][1]!=null){ //do not generate name/value pair if value is null
map[arguments[i][0]]=arguments[i][1]
}
}
return map
},

init:function(){
var ac=this
jQuery(document).ready(function($){
animatedcollapse.ontoggle=animatedcollapse.ontoggle || null
var urlparamopenids=animatedcollapse.urlparamselect() //Get div ids that should be expanded based on the url (['div1','div2',etc])
var persistopenids=ac.getCookie('acopendivids') //Get list of div ids that should be expanded due to persistence ('div1,div2,etc')
var groupswithpersist=ac.getCookie('acgroupswithpersist') //Get list of group names that have 1 or more divs with "persist" attribute defined
if (persistopenids!=null) //if cookie isn't null (is null if first time page loads, and cookie hasnt been set yet)
persistopenids=(persistopenids=='nada')? [] : persistopenids.split(',') //if no divs are persisted, set to empty array, else, array of div ids
groupswithpersist=(groupswithpersist==null || groupswithpersist=='nada')? [] : groupswithpersist.split(',') //Get list of groups with divs that are persisted
jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object
this.$divref=$('#'+this.id)
if ((this.getAttr('persist') || jQuery.inArray(this.getAttr('group'), groupswithpersist)!=-1) && persistopenids!=null){ //if this div carries a user "persist" setting, or belong to a group with at least one div that does
var cssdisplay=(jQuery.inArray(this.id, persistopenids)!=-1)? 'block' : 'none'
}
else{
var cssdisplay=this.getAttr('hide')? 'none' : null
}
if (urlparamopenids[0]=="all" || jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains the single array element "all", or this div's ID
cssdisplay='block' //set div to "block", overriding any other setting
}
else if (urlparamopenids[0]=="none"){
cssdisplay='none' //set div to "none", overriding any other setting
}
this.$divref.css(ac.generatemap(['height', this.getAttr('height')], ['display', cssdisplay]))
this.$divref.attr(ac.generatemap(['groupname', this.getAttr('group')], ['fade', this.getAttr('fade')], ['speed', this.getAttr('speed')]))
if (this.getAttr('group')){ //if this DIV has the "group" attr defined
var targetgroup=ac.divgroups[this.getAttr('group')] || (ac.divgroups[this.getAttr('group')]={}) //Get settings for this group, or if it no settings exist yet, create blank object to store them in
targetgroup.count=(targetgroup.count||0)+1 //count # of DIVs within this group
if (jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains this div's ID
targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded). Overrides other settings
targetgroup.overridepersist=1 //Indicate to override persisted div that would have been expanded
}
if (!targetgroup.lastactivedivid && this.$divref.css('display')!='none' || cssdisplay=="block" && typeof targetgroup.overridepersist=="undefined") //if this DIV was open by default or should be open due to persistence
targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded)
this.$divref.css({display:'none'}) //hide any DIV that's part of said group for now
}
}) //end divholders.each
jQuery.each(ac.divgroups, function(){ //loop through each group
if (this.lastactivedivid && urlparamopenids[0]!="none") //show last "active" DIV within each group (one that should be expanded), unless url param="none"
ac.divholders[this.lastactivedivid].$divref.show()
})
if (animatedcollapse.ontoggle){
jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object and fire ontoggle event
animatedcollapse.ontoggle(jQuery, this.$divref.get(0), this.$divref.css('display'))
})
}
/* //reserved for future implementation
var $allcontrols=$('a[rel]').filter('[@rel^="collapse["], [@rel^="expand["], [@rel^="toggle["]') //get all elements on page with rel="collapse[]", "expand[]" and "toggle[]"
$allcontrols.each(function(){ //loop though each control link
this._divids=this.getAttribute('rel').replace(/(^\w+)|(\s+)/g, "").replace(/[\[\]']/g, "") //cache value 'div1,div2,etc' within identifier[div1,div2,etc]
$(this).click(function(){ //assign click behavior to each control link
var relattr=this.getAttribute('rel')
var divids=(this._divids=="")? [] : this._divids.split(',') //convert 'div1,div2,etc' to array
if (divids.length>0){
animatedcollapse[/expand/i.test(relattr)? 'show' : /collapse/i.test(relattr)? 'hide' : 'toggle'](divids) //call corresponding public function
return false
}
}) //end control.click
})// end control.each
*/
$(window).bind('unload', function(){
ac.uninit()
})
}) //end doc.ready()
},

uninit:function(){
var opendivids='', groupswithpersist=''
jQuery.each(this.divholders, function(){
if (this.$divref.css('display')!='none'){
opendivids+=this.id+',' //store ids of DIVs that are expanded when page unloads: 'div1,div2,etc'
}
if (this.getAttr('group') && this.getAttr('persist'))
groupswithpersist+=this.getAttr('group')+',' //store groups with which at least one DIV has persistance enabled: 'group1,group2,etc'
})
opendivids=(opendivids=='')? 'nada' : opendivids.replace(/,$/, '')
groupswithpersist=(groupswithpersist=='')? 'nada' : groupswithpersist.replace(/,$/, '')
this.setCookie('acopendivids', opendivids, 180)
this.setCookie('acgroupswithpersist', groupswithpersist, 180)
},

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
},

setCookie:function(name, value, days){
if (typeof days!="undefined"){ //if set persistent cookie
var expireDate = new Date()
expireDate.setDate(expireDate.getDate()+days)
document.cookie = name+"="+value+"; path=/; expires="+expireDate.toGMTString()
}
else //else if this is a session only cookie
document.cookie = name+"="+value+"; path=/"
},

urlparamselect:function(){
window.location.search.match(/expanddiv=([\w\-_,]+)/i) //search for expanddiv=divid or divid1,divid2,etc
return (RegExp.$1!="")? RegExp.$1.split(",") : []
}

}

Also where do I put


animatedcollapse.ontoggle=function($, divobj, state){
document.getElementById(divobj.id+"-image").src=(state=="block")? "collapse.jpg" : "expand.jpg"
}

Do I replace this with the function on my image that makes the div collapse/expand? If so it didn't work..

ThunderLee
06-30-2009, 10:56 PM
Bump... Hello? Little help here! (Sorry for impatience but I need this script to work for my site)

ThunderLee
07-06-2009, 01:25 PM
I'm still waiting for help please!!!! >;(

ddadmin
07-07-2009, 01:16 AM
The script was just updated to v2.4 a few days ago,which should make it easy to implement #2 of your request. for #1, what I had posted above should work already. Attached is the latest version of the .js file with the 5 days persistence changes added in.

For #2 and based on the latest file, just make use of the new "data-openimage" and "data-closedimage" attributes when defining your toggler image link. For example:


<a href="#" rel="toggle[cat]" data-openimage="collapse.jpg" data-closedimage="expand.jpg"><img src="collapse.jpg" border="0" /></a> <a href="javascript:animatedcollapse.show('cat')">Slide Down</a> || <a href="javascript:animatedcollapse.hide('cat')">Slide Up</a>

This is explained on the script page.

ThunderLee
07-07-2009, 02:30 PM
Although I updated I got the images to work perfect but I'm stil having problems with the cookies, I have tried my website on 3 different computers with different browsers and it still doesn't seem to work..

What information do I need to give you for you to be able to help me?

ddadmin
07-08-2009, 06:39 AM
Hmm the modified .js file works for me. In both IE8 and FF3, the persistence lasts beyond the browser session as a result (closing and reopening the browser). Are you saying before the changes, the persistence works but only per session, but with the changes, it doesn't work period?

darksider
12-31-2009, 03:22 AM
I have also been experiencing a similar bug with v2.4 and persisting the collapse state.

Basically, I'm using several instances of animatedcollapse on several different web pages, all with differing persist settings.

The issue arises when visiting a page containing ac controls that do not persist, the cookie is deleted and the settings for any other ac instances are lost.

As a quick fix, I got around the issue by appending the 'document.location' to the cookie name, which results in a cookie per page where acs live. Not exactly ideal.
And it doesn't solve the issue of acs in the same page with differing persist settings.

Anyway, I haven't finished trying to sort this out. So hopefully, I can report back a 'Proper Solution' soon.

Code changes with 'document.location' added to Cookie name:
-----------------
getCookie:function(Name){
var re = new RegExp(Name + document.location + "=[^;]*", "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
},

setCookie:function(name, value, days){
if (typeof days!="undefined"){ //if set persistent cookie
var expireDate = new Date()
expireDate.setDate(expireDate.getDate()+days)
document.cookie = name + document.location + "=" + value + "; path=/; expires=" + expireDate.toGMTString()
}
else //else if this is a session only cookie
document.cookie = name + document.location + "=" + value + "; path=/"
},

ddadmin
12-31-2009, 08:01 AM
Darksider, does the problem still occur if the cookies are reverted back to the default "session only", versus the modified "x days"? In general though it shouldn't make any difference, as long as each unique ac div on your site (not just page, but across all pages on your site) is uniquely identified with a unique ID attribute value. If a ac div on pageA and a ac div on pageB both use the same ID attribute value, the script treats those two DIVs as the same, and any changes to one of the DIVs will affect the other when the corresponding page loads.

Anyhow, this might be an issue better demonstrated with a URL to the actual problem page.

darksider
07-14-2010, 11:34 PM
Hi guys,
It's been awhile, but I finally managed to spend some time on this issue.
I LOVE the animated collapse script. And (as a .Net programmer) have encapsulated the ac behaviour in a nice reusable web control.

I was having a lot of trouble with the whole 'persist' behaviour. And finally tracked down what the issue was:
Within the setCookie() method, while persisting divids, the js overwrites the old value for 'acopendivids' - which means, when persisting divs for a given page, you will lose any other values that were persisted.

I have gotten around this issue, by checking divids when resaving the cookie value.
My updated setCookie() logic is as follows:
It's a bit clunky, but it works.

setCookie: function(name, value, days) {

//This code contains a fix for persisting ac state
var cVals = this.getCookie(name);
var cookieValue = '';
if (cVals) {
var vals = cVals.split(",");
for (i = 0; i < vals.length; i++) {
var addthisId = false;
var checkId = vals[i];
if (checkId != "" && (checkId != "nada")) {
var checkElem = document.getElementById(checkId);
if (checkElem) {
if (value.indexOf(checkId) >= 0) {
addthisId = true;
}
}
else {
//checkId not on this page, leave
addthisId = true;
}
}
if (addthisId) {
cookieValue += checkId + ",";
}
}
}
else {
cookieValue = value;
}

if (cookieValue.indexOf(value) < 0) {
cookieValue += value
}

if (typeof days != "undefined") { //if set persistent cookie
var expireDate = new Date()
expireDate.setDate(expireDate.getDate() + days)
//document.cookie = name + "=" + value + "; path=/; expires=" + expireDate.toGMTString()
document.cookie = name + "=" + cookieValue + "; path=/; expires=" + expireDate.toGMTString()
}
else { //else if this is a session only cookie
//document.cookie = name + "=" + value + "; path=/";
document.cookie = name + "=" + cookieValue + "; path=/";
}
},

darksider
11-24-2010, 08:20 PM
Hi all,
I love the animated collapse control and use it a lot. But I've run into issues when using ac on pages where an asynchronous postback occurs. Basically, the ac script keeps re-initializing every async postback, so the toggle keeps occurring multiple times. e.g. 3 async postbacks will cause 3 toggles.

The fix:
Adjust your init() function in the animatedcollapse.js file thus:



init: function () {
var isInAsyncPostBack = false;
try {
var sm = Sys.WebForms.PageRequestManager.getInstance();
if (sm != null) {
isInAsyncPostBack = sm.get_isInAsyncPostBack();
}
}
catch (err) { }
if (!isInAsyncPostBack) {
var ac = this
jQuery(document).ready(function ($) {
animatedcollapse.ontoggle = animatedcollapse.ontoggle || null
var urlparamopenids = animatedcollapse.urlparamselect() //Get div ids that should be expanded based on the url (['div1','div2',etc])
var persistopenids = ac.getCookie('acopendivids') //Get list of div ids that should be expanded due to persistence ('div1,div2,etc')
var groupswithpersist = ac.getCookie('acgroupswithpersist') //Get list of group names that have 1 or more divs with "persist" attribute defined
if (persistopenids != null) //if cookie isn't null (is null if first time page loads, and cookie hasnt been set yet)
persistopenids = (persistopenids == 'nada') ? [] : persistopenids.split(',') //if no divs are persisted, set to empty array, else, array of div ids
groupswithpersist = (groupswithpersist == null || groupswithpersist == 'nada') ? [] : groupswithpersist.split(',') //Get list of groups with divs that are persisted
jQuery.each(ac.divholders, function () { //loop through each collapsible DIV object
this.$divref = $('#' + this.id)
if ((this.getAttr('persist') || jQuery.inArray(this.getAttr('group'), groupswithpersist) != -1) && persistopenids != null) { //if this div carries a user "persist" setting, or belong to a group with at least one div that does
var cssdisplay = (jQuery.inArray(this.id, persistopenids) != -1) ? 'block' : 'none'
}
else {
var cssdisplay = this.getAttr('hide') ? 'none' : null
}
if (urlparamopenids[0] == "all" || jQuery.inArray(this.id, urlparamopenids) != -1) { //if url parameter string contains the single array element "all", or this div's ID
cssdisplay = 'block' //set div to "block", overriding any other setting
}
else if (urlparamopenids[0] == "none") {
cssdisplay = 'none' //set div to "none", overriding any other setting
}
this.$divref.css(ac.generatemap(['height', this.getAttr('height')], ['display', cssdisplay]))
this.$divref.attr(ac.generatemap(['groupname', this.getAttr('group')], ['fade', this.getAttr('fade')], ['speed', this.getAttr('speed')]))
if (this.getAttr('group')) { //if this DIV has the "group" attr defined
var targetgroup = ac.divgroups[this.getAttr('group')] || (ac.divgroups[this.getAttr('group')] = {}) //Get settings for this group, or if it no settings exist yet, create blank object to store them in
targetgroup.count = (targetgroup.count || 0) + 1 //count # of DIVs within this group
if (jQuery.inArray(this.id, urlparamopenids) != -1) { //if url parameter string contains this div's ID
targetgroup.lastactivedivid = this.id //remember this DIV as the last "active" DIV (this DIV will be expanded). Overrides other settings
targetgroup.overridepersist = 1 //Indicate to override persisted div that would have been expanded
}
if (!targetgroup.lastactivedivid && this.$divref.css('display') != 'none' || cssdisplay == "block" && typeof targetgroup.overridepersist == "undefined") //if this DIV was open by default or should be open due to persistence
targetgroup.lastactivedivid = this.id //remember this DIV as the last "active" DIV (this DIV will be expanded)
this.$divref.css({ display: 'none' }) //hide any DIV that's part of said group for now
}
}) //end divholders.each
jQuery.each(ac.divgroups, function () { //loop through each group
if (this.lastactivedivid && urlparamopenids[0] != "none") //show last "active" DIV within each group (one that should be expanded), unless url param="none"
ac.divholders[this.lastactivedivid].$divref.show()
})
if (animatedcollapse.ontoggle) {
jQuery.each(ac.divholders, function () { //loop through each collapsible DIV object and fire ontoggle event
animatedcollapse.ontoggle(jQuery, this.$divref.get(0), this.$divref.css('display'))
})
}
//Parse page for links containing rel attribute
var $allcontrols = $('a[rel]').filter('[rel^="collapse["], [rel^="expand["], [rel^="toggle["]') //get all elements on page with rel="collapse[]", "expand[]" and "toggle[]"
$allcontrols.each(function () { //loop though each control link
this._divids = this.getAttribute('rel').replace(/(^\w+)|(\s+)/g, "").replace(/[\[\]']/g, "") //cache value 'div1,div2,etc' within identifier[div1,div2,etc]
if (this.getElementsByTagName('img').length == 1 && ac.divholders[this._divids]) { //if control is an image link that toggles a single DIV (must be one to one to update status image)
animatedcollapse.preloadimage(this.getAttribute('data-openimage'), this.getAttribute('data-closedimage')) //preload control images (if defined)
$togglerimage = $(this).find('img').eq(0).data('srcs', { open: this.getAttribute('data-openimage'), closed: this.getAttribute('data-closedimage') }) //remember open and closed images' paths
ac.divholders[this._divids].$togglerimage = $(this).find('img').eq(0) //save reference to toggler image (to be updated inside slideengine()
ac.divholders[this._divids].$togglerimage.attr('src', (ac.divholders[this._divids].$divref.css('display') == "none") ? $togglerimage.data('srcs').closed : $togglerimage.data('srcs').open)
}
$(this).click(function () { //assign click behavior to each control link
var relattr = this.getAttribute('rel')
var divids = (this._divids == "") ? [] : this._divids.split(',') //convert 'div1,div2,etc' to array
if (divids.length > 0) {
animatedcollapse[/expand/i.test(relattr) ? 'show' : /collapse/i.test(relattr) ? 'hide' : 'toggle'](divids) //call corresponding public function
return false
}
}) //end control.click
})// end control.each

$(window).bind('unload', function () {
ac.uninit()
})
}) //end doc.ready()
} //end isInAsyncPostBack
},