View Single Post
  #1  
Old 03-02-2003, 07:13 PM
 
dealsondeals dealsondeals is offline
 

eXpert
  
Join Date: Dec 2002
Location: Dallas, Texas, USA
Posts: 231
 

Default Sliding Menu that displays categories and sub-categories

Here is way to have a sliding menu that displays categories and sub-categories dynamically. This method utilizes javascript. You change your categories in admin and it will automatically reflect these changes. Unlimited amount of main categories will be displayed. However, you will only be able to nest up to 3 sub-levels underneath each main categories, i.e.:

MAIN
SUB-1
SUB-2
SUB-3

To see an example go here:
http://www.deals-on-deals.com/xcart/customer/

For this version of the sliding menu, I am utilize images as background for each category and sub-category. If you want or need these images let me know and I'll email them to you.

If you wish to have text-only, in categories.tpl below set "slideMenu.useImages = 0" instead of "1".

Also very important, you are already aware that categories.tpl is referenced in the left-hand column of home.tpl, I would recommend either clearing the contents of the left-hand column to contain only categories.tpl or place some items like authbox.tpl above categories.tpl or place them elsewhere on the page. Why you ask? Because this menu slides and will slide down over content that is there and believe me it looks insightly when that happens.

So here goes:


Backup-up then replace your categories. tpl (located at skin1/customer/categories.tpl) with the following:
Quote:
{* $Id: categories.tpl,v 1.16 2002/10/21 07:06:43 zorg Exp $ *}
<script language="JavaScript" src="../skin1/slidemenu.js" type="text/javascript">
</script>

<script language="JavaScript">
{literal}
slideMenu = new createSlideMenu("slideMenu")

//Variables to set:
slideMenu.menuy=95 //The top placement of the menu.
slideMenu.menux=5 //The left placement of the menu
slideMenu.useImages = 1 //Are you using images or not? Yes - 1, No - 0
slideMenu.pxspeed=20 //The pixel speed of the animation
slideMenu.timspeed=25 //The timer speed of the animation
slideMenu.inset = 10 //How much the selected items should pop to the left
slideMenu.arrow = 0 //Set this to className that has font-family:webdings
//if you want to use the arrow feature. Note:
//This ONLY works on DOM capable browsers, and with
//useImages set to 0 - It's basically just a test I did.
//I hope to improve it later on.

//Needed dummy classes - leave in the stylesheet!
slideMenu.bgClass = "slideMenuBG"
slideMenu.txtClass = "slideMenuText"
$ip = '../skin1/images/menu/';

slideMenu.level[0] = new slideMenu_makeLevel(
left = 0,
width = 138,
height = 21,
between = 5,
className = "clSlideMenu",
classNameA = "clA0",
regImage = $ip+"level0_regular.gif",
roundImg = $ip+"level0_round.gif",
roundImg2 = "",
subImg = "",
subRound= "")

slideMenu.level[1] = new slideMenu_makeLevel(10,127,20,2,"clSlideMenu","clA 1",$ip+"level1_regular.gif",$ip+"level1_round2.gif ",$ip+"level1_round.gif",$ip+"level1_sub.gif", $ip+"level1_sub_round.gif")
slideMenu.level[2] = new slideMenu_makeLevel(21,118,18,2,"clSlideMenu","clA 2",$ip+"level2_regular.gif",$ip+"level2_round2.gif ",$ip+"level2_round.gif",$ip+"level2_sub.gif", $ip+"level2_sub_round.gif")
slideMenu.level[3] = new slideMenu_makeLevel(33,108,20,2,"clSlideMenu","clA 3",$ip+"level3_regular.gif",$ip+"level3_round2.gif ",$ip+"level3_round.gif",$ip+"level3_sub.gif", $ip+"level3_sub_round.gif")
slideMenu.level[4] = new slideMenu_makeLevel(40,107,19,2,"clSlideMenu","clA 4",$ip+"level4_regular.gif",$ip+"level4_round2.gif ",$ip+"level4_round.gif",$ip+"level4_sub.gif", $ip+"level4_sub_round.gif")

//Image preload --- leave this
for(var i=0;i<slideMenu.level;i++){
var l = slideMenu.level[i]
new preLoadBackgrounds(l.regImage,l.roundImg,l.roundIm g2,l.subImg,l.subRound)
}
{/literal}

{php}

function find_idx($a, $label)
{
while( list($k,$v) = each($a) ){
if( isset($v['label']) && $v['label'] == $label )
return $k;
}
return -1;
}

function cmp($a, $b)
{
if( $a['orderby'] == $b['orderby'] ) return 0;
return ($a['orderby'] < $b['orderby'] ) ? -1 : 1;
}

function sort_cat(&$list)
{
while( list($k,$v) = each($list) ){
if( isset($v['sub']) )
usort(&$v['sub'],'cmp');
}
usort($list,'cmp');
}

function preparelist($list)
{
$r = array();
$c = false;
$cnt = 1;
while (list ($k, $v) = each ($list) ){
$l = split('/',$v['category']);
// init tree
$p = & $r;
for( $i=0; $i<sizeof($l); $i++ ){
$idx = find_idx($p,$l[$i]);
$lastest = ( $i == sizeof($l)-1 );
if( $idx == -1 ) {
if( $lastest ){
if( isset($p[0]) && isset($p[0]['orderby']) && $p[0]['orderby'] > $v['order_by']){
array_unshift($p, array( 'label'=>$l[$i] ) );
$idx = 0;
}
else {
array_push($p, array( 'label'=>$l[$i] ) );
$idx = sizeof($p)-1;
}
}
else {
array_push($p, array( 'label'=>$l[$i] ) );
$idx = sizeof($p)-1;
}
}
$p = & $p[$idx];
if( $lastest )
$p['orderby'] = $v['order_by'];
// set url
if( $lastest )
$p['url'] = $v['categoryid'];
else {
if( !isset( $p['sub'] ) )
$p['sub'] = array();
$p = & $p['sub'];
}
}
$cnt++;
}
return $r;
}

function fill_menu($menu,$level)
{
switch( $level ){
case '0': $l = 'top'; break;
case '1': $l = 'sub'; break;
default: $l = 'sub'.$level; break;
}
while ( list($idx,$cnt) = each($menu) ){
$item = $menu[$idx]; $label = addslashes($item['label']);
if( isset($item['sub']) ){
print "slideMenu.makeMenu('$l',\"$label\");\n";
fill_menu($item['sub'],$level+1);
}
else
print "slideMenu.makeMenu('$l',\"$label\",'home.php?cat= ".$item['url']."');\n";
}
}

$list = preparelist($allcategories);
sort_cat(&$list);

fill_menu($list,0);
print "slideMenu.init();\n\n";
{/php}
</SCRIPT>

<TABLE border=0 cellPadding=5 cellSpacing=0 width=100%>
<!-- <TR>
<TD height=26 width=26 valign=center>[img]{$ImagesDir}/dingbats_categorie.gif[/img]</TD>
<TD height=26 valign=center width="80%"><FONT class=VertMenuTitle>{$lng.lbl_categories}</FONT></TD>
</TR> -->
<tr><td colspan=2 nowrap>
{if $config.General.root_categories eq "Y"}
{/if}
</td></tr>
</TABLE>

Next add the following to the bottom of skin1.css:
(Note that you can change the text colors of the main level and sub levels by specifying it below in A.clA0,A.clA1,A.clA2,A.clA3,A.clA4 and setting the hover and visited properties for each of those)
Quote:
/* slide menu */
div.clSlideMenu{ /* All slideMenu2 DIV elements */
position:absolute;
overflow:hidden;
width:150;
height:22;
}
A.clA0{ /* All top level links */
font-family:Verdana, Helvetica, Helv;
color:Black;
font-size:12px;
text-decoration:none;
font-weight:bold;

}
A.clA1{ /* All sub level links */
font-family:Verdana, Helvetica, Helv;
font-size:10px; font-weight:bold;
text-decoration:none;
color:Black
}
A.clA2{ /* All sub2 level links */
font-family:Verdana, Helvetica, Helv;
font-size:10px; font-weight:bold;
text-decoration:none;
color:Navy
}
A.clA3{ /* All sub3 level links */
font-family:Verdana, Helvetica, Helv;
font-size:10px;
font-weight:bold;
text-decoration:none;
color:Green
}
A.clA4{ /* All sub4 level links */
font-family:Verdana, Helvetica, Helv;
font-size:10px;
font-weight:bold; text-decoration:none;
color:Navy
}
a.clA0:hover{color: #FFCC00; text-decoration:underline;}
a.clA0:visited{color: #99CCFF; text-decoration:underline;}
a.clA1:hover{color: #FFCCAA; text-decoration:underline;}
a.clA1:visited{color: Black; text-decoration:underline;}
a.clA2:hover{color: #CC00; text-decoration:underline;}
a.clA2:visited{color: Green; text-decoration:underline;}
a.clA3:hover{color: #FFCC00; text-decoration:underline;}
a.clA3:visited{color: #99CCFF; text-decoration:underline;}
a.clA4:hover{color: #FFCC00; text-decoration:underline;}
a.clA4:visited{color: #99CCFF; text-decoration:underline;}

/* NEEDED STYLES */
div.slideMenuBG{position:absolute; left:0; top:0; z-index:1}
div.slideMenuText{position:absolute; left:2; top:2; z-index:200;}
/* NEEDED ----- This class should be named like this:
#NAME_OF_YOUR_MENUcont
*/
#slideMenucont{position:absolute; height:600; width:200; visibility:hidden;}

This is the javascript that makes it all work. This script was created byThomas Bratti of dhtmlcentral.com. Use any text editor, i.e. notepad,vi and create a file called "slidemenu.js" paste the contents below into it. Then place this file in: xcart/skin1/
Quote:
/************************************************** **********************************
Making cross-browser objects
************************************************** **********************************/
function makeMenuObj(obj,nest){
nest=(!nest) ? "":'document.'+nest+'.'
this.evnt = document.getElementById?document.getElementById(ob j):document.all?document.all[obj]:document.layers?eval(nest+'document.'+obj):0;
this.css = this.evnt.style?this.evnt.style:this.evnt;
this.ref=document.layers?this.evnt.document:docume nt;
this.x=this.css.left||this.evnt.offsetLeft;
this.y=this.css.top||this.evnt.offsetTop;
this.hideIt=b_hideIt; this.showIt=b_showIt; this.movey=b_movey
this.moveIt=b_moveIt; this.moveBy=b_moveBy; this.status=0;
this.bgImg=b_bgImg; this.obj = obj + "Object"; eval(this.obj + "=this");
this.clipTo=b_clipTo;
return this
}
function b_showIt(){this.css.visibility="visible"; this.status=1}
function b_hideIt(){this.css.visibility="hidden"; this.status=0}
function b_movey(y){this.y=y; this.css.top=this.y}
function b_moveIt(x,y){this.x=x; this.y=y; this.css.left=this.x;this.css.top=this.y}
function b_moveBy(x,y){this.x=this.x+x; this.y=this.y+y; this.css.left=this.x;this.css.top=this.y}
function b_bgImg(img){
if(document.getElementById) document.getElementById(this.id+"_img").src = img
else if(document.layers) this.ref.layers[0].document.images[0].src = img
else document.images[this.id+"_img"].src = img
}
function b_clipTo(t,r,b,l,w){if(document.layers){this.css.c lip.top=t;this.css.clip.right=r
this.css.clip.bottom=b;this.css.clip.left=l
}else{this.css.clip="rect("+t+"px,"+r+"px,"+b+"px, "+l+"px)"; if(w){this.css.pixelWidth=this.css.width=r; this.css.pixelHeight=this.css.height=b}}}
/************************************************** ******************************
Initiating page, making objects..
************************************************** ******************************/
createSlideMenu.prototype.init = function(){
document.write("</div>")
this.cont=new makeMenuObj(this.name+'cont')
this.cont.moveIt(this.menux,this.menuy)
var yy = 0, el //Make top menus
for(var j=0;j<this.topmenus.length;j++){
el = this.menus[this.topmenus[j]]
el.o = new makeMenuObj(this.name+"_"+el.num,this.name+"cont")
el.o.moveIt(this.l[0].left,yy); el.top = j; el.origy = yy
el.o.id = el.id; el.o.status=1;
el.o.h = this.l[0].height; el.img = this.l[0].regImage
yy+=el.o.h + this.l[0].between; el.o.clipTo(0,this.l[0].width,el.o.h,0,1)
if(j!=this.topmenus.length-1) el.nexttop = this.topmenus[el.top+1]
this.loop(el.num,j)
}
this.cont.showIt(); this.cont = null; this.level = null;
}
createSlideMenu.prototype.loop = function(num,j){
var el = this.menus[num],temp,p,h,w,y,img
for(var i=0;i<el.childs.length;i++){
temp = el.childs[i]
w = this.l[temp.lev].width; h = this.l[temp.lev].height
y = el.o.y+el.o.h + h*i + this.l[temp.lev].between*i + this.l[temp.lev].between
temp.o = new makeMenuObj(this.name+"_"+temp.num,this.name+"cont ")
temp.o.hideIt(); temp.o.clipTo(0,w,h,0,1)
temp.o.moveIt(this.l[temp.lev].left,y)
el.endy =y+h; temp.origy = y
temp.o.zIndex=temp.num
temp.o.h = h; temp.top = j
temp.chnum = i; temp.o.id = temp.id
if(this.useImages){ //Setting bgimage
img=""
if(temp.childs.length>0){ //With subs
if(i==el.childs.length-1) img=this.l[temp.lev].subRound
else img=this.l[temp.lev].subImg
}else if(i==el.childs.length-1){
img=this.l[temp.lev].roundImg2
}
if(img){
temp.o.bgImg(img); temp.img = img
}else temp.img = this.l[temp.lev].regImage
}
p = this.menus[temp.parent] //Setting the next elements
if(temp.chnum != p.childs.length-1){ //Not the last el
temp.nextel = p.childs[temp.chnum+1].num
temp.nexttop = temp.lev==1?p.nexttop:p.nextel
}else{ //Last el, so we only have nexttop
temp.nexttop = p.nextel
if(temp.nexttop==-1) temp.nexttop = p.nexttop
}
if(temp.childs.length>0){
this.loop(temp.num,j) //Recursive call
}
}
}

/************************************************** ******************************
Moving all objects in the array after a provided array number
************************************************** ******************************/
createSlideMenu.prototype.moveItems = function(px,num){
for(i=num;i<this.menus.length;i++){
if(this.menus[i].o.status){ //Moving all visible menus
this.menus[i].o.movey(this.menus[i].o.y+px)
}
}
}
/************************************************** ******************************
Switch menu function.
************************************************** ******************************/
createSlideMenu.prototype.switchMenu = function(num){
if(this.going) return
var m = this.menus[num]
if(m.childs.length==0) return
this.going = 1
var y=m.o.y+ m.o.h +this.l[m.lev].between
var clnum = m.num, olev = m.lev, onext = m.nextel
if(this.active[0]>-1){
var n = -1
if(m.lev>0){
if(this.active[m.lev]>-1) n=this.active[m.lev]
else n=this.active[m.lev-1]
}else n = this.active[0]
m = this.menus[n]
if(m.lev == 0 && olev==0) y = m.nexttop!=-1?this.menus[m.nexttop].origy:-1
else if(clnum!=m.num){
var ny = m.o.y + m.o.h + this.l[m.lev].between
if(clnum>m.num && olev==m.lev) y = Math.min(ny,y)
else if(onext==m.num) y = Math.max(ny,y)
}
}
this.moveUp(m.nextel!=-1?m.nextel:m.nexttop,num,y)
}
/************************************************** ******************************
Move items up
************************************************** ******************************/
createSlideMenu.prototype.moveUp = function(top,num,y){
var move = 0, m, yy=0;
if(this.active[0]>-1 && top>-1){
m = this.menus[top]
if(m.o.y>y){
if((m.o.y-this.pxspeed)<y) yy = -(((m.o.y-y)))
else yy=-this.pxspeed; this.moveItems(yy,top)
move=1
}
}
if(move) setTimeout(this.name+".moveUp("+top+","+num+","+y+ ")",this.timspeed)
else{
m = this.menus[num]
for(var i=m.lev;i<this.active.length;i++){ //Reset images - actives et cetera
if(this.active[i]>-1){
temp = this.menus[this.active[i]]
temp.o.moveIt(temp.o.x-this.inset,temp.o.y)
if(this.useImages) temp.o.bgImg(temp.img) //Change bg
if(this.arrow) temp.ar.replaceChild(document.createTextNode("4"), temp.ar.childNodes[0])
ch = temp.childs
for(var j=0;j<ch.length;j++){
ch[j].o.hideIt(); ch[j].o.movey(ch[j].origy)
}
this.active[i] = -1
}
}
//Then open the current one, if childs
if(m.childs.length == 0){this.going = 0; return}
for(i=0;i<m.childs.length;i++){ //Show all
m.childs[i].o.showIt()
y = m.childs[i].o.y + m.childs[i].o.h
}
y+=this.l[m.lev].between
if(m.lev>0 && m.chnum!=this.menus[m.parent].childs.length-1){
yy=y; y = this.menus[m.parent].endy + this.l[m.lev].between
}
m.o.moveIt(m.o.x+this.inset,m.o.y) //Inset current item:
if(this.useImages) m.o.bgImg(this.l[m.lev].roundImg) //Change bg
this.active[m.lev] = num //Set active
if(this.arrow) m.ar.replaceChild(document.createTextNode("6"),m.a r.childNodes[0])
if(m.nexttop>-1 || m.nextel>-1) this.moveDown(m.nexttop,m.nextel,y,yy) //Then start moving all other elements down
else this.going=0
}
}
/************************************************** ******************************
Move items down
************************************************** ******************************/
createSlideMenu.prototype.moveDown = function(top,num,y,yyy){
var m = this.menus[top],yy
if(m && m.o.y<y){
if((m.o.y+this.pxspeed)>y) yy = y-m.o.y
else yy=this.pxspeed
this.moveItems(yy,top)
setTimeout(this.name+".moveDown("+top+","+num+","+ y+","+yyy+")",this.timspeed)
}else if(num>-1){
this.moveDown(num,-1,yyy,0)
}else this.going=0
}
/************************************************** ******************************
Slide menu object
************************************************** ******************************/
function createSlideMenu(name){
document.write('<div id="'+name+'cont">') //The cont div start
this.name = name
this.menus = new Array()
this.curr = 0
this.lasttype = new Array()
this.writesubsonly = 0
this.level = new Array()
this.l = new Array()
this.topmenus = new Array()
this.active = new Array()
return this
}
/************************************************** ******************************
Function to create the objects and the divs
************************************************** ******************************/
createSlideMenu.prototype.makeMenu = function(type,text,lnk,target,end){
var str="",tg="",parent,m,cl
m = this.menus[this.curr] = new Object()
this.lasttype[type] = this.curr; if(!lnk) lnk="#"
m.lev = 0; m.type = type; m.childs = new Array()
m.num = this.curr; m.parent = -1; m.nextel = -1
m.nexttop = -1; parent = 0
//DEBUGGING::::::
m.text = text

if(type.indexOf("sub")>-1){ //Find parent type
if(type.length == 3){ //sub
parent = "top"; m.lev = 1
}else{
parent = type.substr(3,1) //sub2+
m.lev = parent; parent--
if(parent==1){
parent = "sub"; m.lev = 2
}else parent = "sub"+parent
}
}
if(m.lev>=this.l.length){//Level control (same as CM4)
var p1,p2=0;
if(m.lev>=this.level.length) p1=this.l[this.level.length-1];
else p1=this.level[m.lev];
this.l[m.lev]=new Array();
if(!p2) p2=this.l[m.lev-1]
if(m.lev!=0 && p1){
for(i in p1){ //Copying an entire object
if(p1[i]==null) this.l[m.lev][i]=p2[i];
else this.l[m.lev][i]=p1[i]
}
}else{
this.l[m.lev]=this.level[0];
}
this.level[m.lev]=p1=p2=null
}
this.active[m.lev] = -1
if(parent){ //Find parent element
m.parent = this.lasttype[parent]
parent = this.menus[this.lasttype[parent]]
parent.childs[parent.childs.length] = m
if(this.arrow && parent.childs.length==1){str='<span class="'+this.arrow+'">4</span>'
if(document.getElementById && document.getElementById(parent.id).childNodes){
parent.ar = document.getElementById(parent.id).childNodes[this.useImage?1:0].childNodes[0]
parent.ar.innerHTML = str+parent.ar.innerHTML; parent.ar=parent.ar.childNodes[0]} else this.arrow=""
}
}else this.topmenus[this.topmenus.length] = this.curr
if(!this.writesubsonly || type!="top"){
cl = this.l[m.lev].className
m.id = id = this.name + "_" + this.curr
str= '<div id="'+id+'" class="'+cl+'">' //main div start
if(this.useImages){
str+='<div class="'+this.bgClass+'">'//bgdiv
str+='[img]'+this.l[m.lev].regImage+'[/img]'
str+='</div>' //bgdiv
}
if(target) tg =' target="'+target+'" '
str+='<div class="'+this.txtClass+'"> '+text+'
</div>\n'
str+="</div>\n\n" //main div end
document.write(str)
}
this.curr++
}

/************************************************** ******************************
Level object
************************************************** ******************************/
function slideMenu_makeLevel(){
var c=this, a=arguments;
c.left=a[0]||0; c.width=a[1]||null; c.height=a[2]||null;
c.between=a[3]||null; c.className=a[4]||null; c.classNameA=a[5]||null;
c.regImage=a[6]||null; c.roundImg=a[7]||null; c.roundImg2=a[8]||null;
c.subImg=a[9]||null; c.subRound=a[10]||null; return c
}
/************************************************** ******************************
Preloading images
************************************************** ******************************/
function preLoadBackgrounds(){
for(i=0;i<arguments.length;i++){
this[i]=new Image()
this[i].src=arguments[i]
}
return this
}


Enjoy,

Glen
__________________
Never understimate stupidity.
--------
X-Cart Version: 3.5.2
Hosting:mind-in-design.net
Configuration: Virtual Dedicated Server || Intel Pentium 4 2.4 GHZ CPU || 1024MB PC2100 DDR RAM || Linux || PHP 4.3.2 || MySQL server 4.0.14
Reply With Quote