[interchange-cvs] interchange - heins modified lib/Vend/Menu.pm

interchange-core@icdevgroup.org interchange-core@icdevgroup.org
Thu Sep 12 01:20:01 2002


User:      heins
Date:      2002-09-12 05:19:35 GMT
Modified:  lib/Vend Menu.pm
Log:
* Make variable and function names remappable (prefixed with mv_ by default)
  to 1) avoid namespace collisions with other stuff and 2) allow multiple
  trees and flyouts on the same page.

* Add auto-menu feature. If no menu name is passed (basically, you
  put [menu] [/menu] in the page), it looks for a menu based on
  the page name and directory name. It keeps looking above until
  it finds one, then builds a menu out of the first it finds.

  This allows a single menu to automatically apply for all pages in
  a directory.

  Example:

	Menus in:
	  include/menus/about/whoweare.txt
	  include/menus/about.txt

    Pages in question:

  	  pages/about/index.html        Gets about.txt for menu
  	  pages/about/who/index.html    Gets about/who.txt for menu
  	  pages/about/why/index.html    Gets about.txt for menu

* Add logged_in transform, that has three states:

	empty    Displayed for both non-member and member
	1        Displayed for member only
	0        Displayed for non-member only

* Change open tree variable to only pass open leaves instead of a
  possibly-huge binary string.

Revision  Changes    Path
2.15      +258 -158  interchange/lib/Vend/Menu.pm


rev 2.15, prev_rev 2.14
Index: Menu.pm
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/interchange/lib/Vend/Menu.pm,v
retrieving revision 2.14
retrieving revision 2.15
diff -u -r2.14 -r2.15
--- Menu.pm	20 Aug 2002 02:43:56 -0000	2.14
+++ Menu.pm	12 Sep 2002 05:19:35 -0000	2.15
@@ -1,6 +1,6 @@
 # Vend::Menu - Interchange payment processing routines
 #
-# $Id: Menu.pm,v 2.14 2002/08/20 02:43:56 mheins Exp $
+# $Id: Menu.pm,v 2.15 2002/09/12 05:19:35 mheins Exp $
 #
 # Copyright (C) 2002 Mike Heins, <mike@perusion.net>
 #
@@ -21,7 +21,7 @@
=20
 package Vend::Menu;
=20
-$VERSION =3D substr(q$Revision: 2.14 $, 10);
+$VERSION =3D substr(q$Revision: 2.15 $, 10);
=20
 use Vend::Util;
 use strict;
@@ -139,6 +139,16 @@
 		}
 		return $status;
 	},
+	logged_in =3D> sub {
+		my ($row, $fields) =3D @_;
+		return 1 if ref($fields) ne 'ARRAY';
+		my $status =3D 1;
+		for(@$fields) {
+			next if ! length($row->{$_});
+			$status =3D $status && (! $::Vend::Session->{logged_in} ^ $row->{$_});
+		}
+		return $status;
+	},
 	depends_on =3D> sub {
 		my ($row, $fields) =3D @_;
 		return 1 if ref($fields) ne 'ARRAY';
@@ -378,8 +388,10 @@
 	my @out;
 	my $fdiv =3D $name . "_flyout";
=20
+	my $vpf =3D $opt->{js_prefix} ||=3D 'mv_';
+
 	$template =3D <<EOF if $template !~ /\S/;
-{MV_LEVEL:}<div>{PAGE?}{MV_SPACER}<a id=3D"{CODE}" href=3D"{PAGE}" onMouse=
Over=3D"mousein(this)" onMouseOut=3D"mouseout(this)" TITLE=3D"{DESCRIPTION}=
" class=3D"$opt->{link_class}">{NAME}</A>{/PAGE?}{PAGE:}{MV_SPACER}{NAME}{/=
MV_SPACER}{/PAGE:}</div>{/MV_LEVEL:}
+{MV_LEVEL:}<div>{PAGE?}{MV_SPACER}<a id=3D"{CODE}" href=3D"{PAGE}" onMouse=
Over=3D"${vpf}mousein(this)" onMouseOut=3D"${vpf}mouseout(this)" TITLE=3D"{=
DESCRIPTION}" class=3D"$opt->{link_class}">{NAME}</A>{/PAGE?}{PAGE:}{MV_SPA=
CER}{NAME}{/MV_SPACER}{/PAGE:}</div>{/MV_LEVEL:}
 EOF
=20
 	$opt->{cursor_type} ||=3D 'hand';
@@ -395,11 +407,11 @@
=20
 	$opt->{anchor_down} =3D is_yes($opt->{anchor_down}) || 0;
=20
-
 	push @out, <<EOF;
 <script language=3D"JavaScript1.3">
-var timeoutCode =3D -1;
-var lines =3D new Array;
+var ${vpf}timeoutCode =3D -1;
+var ${vpf}mydiv =3D '$fdiv';
+var ${vpf}lines =3D new Array;
 EOF
=20
 	my %o =3D (
@@ -408,6 +420,7 @@
 			master      =3D> 'parent_fld',
 			subordinate =3D> 'code',
 			autodetect  =3D> '1',
+			js_prefix	=3D> $vpf,
 			sort        =3D> $opt->{sort} || 'code',
 			full        =3D> '1',
 			spacing     =3D> '4',
@@ -445,23 +458,26 @@
 	my %seen;
 	my @levels =3D grep !$seen{$_}++, map { $_->{mv_level} } @$rows;
 	@levels =3D sort { $a <=3D> $b } @levels;
+	my $last =3D $#levels || 0;
 	shift @levels;
=20
 	push @out, <<EOF;
-var anchor_down =3D $opt->{anchor_down};
-var last_level =3D $levels[$#levels];
-var link_class =3D '$opt->{link_class}';
-var link_class_open =3D '$opt->{link_class_open}';
-var link_class_closed =3D '$opt->{link_class_closed}';
-var link_style =3D '$opt->{link_style}';
-var link_style_open =3D '$opt->{link_style_open}';
-var link_style_closed =3D '$opt->{link_style_closed}';
+var ${vpf}anchor_down =3D $opt->{anchor_down};
+var ${vpf}last_level =3D $last;
+var ${vpf}link_class =3D '$opt->{link_class}';
+var ${vpf}link_class_open =3D '$opt->{link_class_open}';
+var ${vpf}link_class_closed =3D '$opt->{link_class_closed}';
+var ${vpf}link_style =3D '$opt->{link_style}';
+var ${vpf}link_style_open =3D '$opt->{link_style_open}';
+var ${vpf}link_style_closed =3D '$opt->{link_style_closed}';
 EOF
-	push @out, <<EOF;
+	push @out, <<EOF unless $opt->{no_emit_code};
=20
-	function menu_link (idx) {
+// CLIP HERE
+// If you want to move these functions to the HEAD
+	function ${vpf}menu_link (idx) {
=20
-		var l =3D lines[ idx ];
+		var l =3D ${vpf}lines[ idx ];
=20
 		if(l =3D=3D undefined) {
 			alert("Bad idx=3D" + idx + ", no line there.");
@@ -469,26 +485,26 @@
 		}
=20
 		var out =3D '<DIV';
-		if(l[MV_CHILDREN] > 0) {
+		if(l[${vpf}MV_CHILDREN] > 0) {
 			out =3D out + ' id=3D"' + l[0] + '"';
-			out =3D out + ' onMouseOver=3D"mousein(this,' + l[MV_LEVEL] + ')"';
+			out =3D out + ' onMouseOver=3D"${vpf}mousein(this,' + l[${vpf}MV_LEVEL]=
 + ')"';
 		}
 		out +=3D '>';
-		var tstyle =3D link_style;
-		var tclass =3D link_class;
-		if(l[PAGE]) {
-			out =3D out + '<a href=3D"' + l[ PAGE ] + '"';
+		var tstyle =3D ${vpf}link_style;
+		var tclass =3D ${vpf}link_class;
+		if(l[${vpf}PAGE]) {
+			out =3D out + '<a href=3D"' + l[ ${vpf}PAGE ] + '"';
 			if(tclass)
 				out =3D out + ' class=3D"' + tclass + '"';
 			if(tstyle)
 				out =3D out + ' style=3D"' + tstyle + '"';
-			if(l[DESCRIPTION])
-				out =3D out + ' title=3D"' + l[ DESCRIPTION ] + '"';
+			if(l[${vpf}DESCRIPTION])
+				out =3D out + ' title=3D"' + l[ ${vpf}DESCRIPTION ] + '"';
 			out =3D out + '>';
-			out =3D out + l[ NAME ] + '</a>';
+			out =3D out + l[ ${vpf}NAME ] + '</a>';
 		}
 		else {
-			out =3D out + l[ NAME ];
+			out =3D out + l[ ${vpf}NAME ];
 		}
 	// alert("build idx=3D" + idx + " into: " + out);
 		out +=3D '</div>';
@@ -496,29 +512,27 @@
 		return out;
 	}
=20
-	var mydiv =3D '$fdiv';
-
-	function mousein (obj,level) {
-		if( browserType() =3D=3D "other" )
+	function ${vpf}mousein (obj,level) {
+		if( ${vpf}browserType() =3D=3D "other" )
 			return;
=20
 		if(level =3D=3D undefined)=20
 			level =3D 0;
 		level++;
=20
-		var divname =3D mydiv + level;
+		var divname =3D ${vpf}mydiv + level;
 		var fod =3D document.getElementById( divname );
 		if(fod =3D=3D undefined)=20
 			return;
 		fod.style.display =3D 'none';
-		clearTimeout( timeoutCode );
-		timeoutCode =3D -1;
+		clearTimeout( ${vpf}timeoutCode );
+		${vpf}timeoutCode =3D -1;
=20
 		var html =3D "";
=20
 		var idx =3D -1;
-		for(var j =3D 0; j < lines.length; j++) {
-			if(lines[j][0] =3D=3D obj.id) {
+		for(var j =3D 0; j < ${vpf}lines.length; j++) {
+			if(${vpf}lines[j][0] =3D=3D obj.id) {
 				idx =3D j;
 				break;
 			}
@@ -527,14 +541,17 @@
 		if(idx < 0)=20
 			return;
=20=09
-		var currentlevel =3D lines[idx][MV_LEVEL];
+		var l =3D ${vpf}lines[idx];
+		var currentlevel =3D l[${vpf}MV_LEVEL];
 		if(currentlevel =3D=3D undefined)
 			currentlevel =3D 0;
=20
-		menuClear(currentlevel);
+		${vpf}menuClear(currentlevel);
+		if(l[${vpf}MV_CHILDREN] < 1)=20
+			return;
=20
-		var x =3D getRightX( obj ) + 1;
-		var y =3D getTopX( obj );
+		var x =3D ${vpf}getRightX( obj ) + 1;
+		var y =3D ${vpf}getTopX( obj );
 		var menu =3D fod.style;
 		menu.left =3D x + "px";
 		menu.top =3D y + "px";
@@ -543,21 +560,21 @@
 		var i;
 		for( i =3D idx + 1; ; i++ )
 		{
-			var l =3D lines[i];
-// alert("running link for level=3D" + l[MV_LEVEL] + ", line=3D" + l);
-			if(l =3D=3D undefined || l[MV_LEVEL] < level)
+			var l =3D ${vpf}lines[i];
+// alert("running link for level=3D" + l[${vpf}MV_LEVEL] + ", line=3D" + l=
);
+			if(l =3D=3D undefined || l[${vpf}MV_LEVEL] < level)
 				break;
-			if(l[MV_LEVEL] =3D=3D level)
-				html +=3D menu_link(i);
+			if(l[${vpf}MV_LEVEL] =3D=3D level)
+				html +=3D ${vpf}menu_link(i);
 		}
 		fod.innerHTML =3D html;
 	}
=20
-	function getRightX( obj )
+	function ${vpf}getRightX( obj )
 	{
 		var pos =3D 0;
-		if( browserType() =3D=3D "ie" )
-			if(anchor_down =3D=3D 1)=20
+		if( ${vpf}browserType() =3D=3D "ie" )
+			if(${vpf}anchor_down =3D=3D 1)=20
 				pos =3D obj.getBoundingClientRect().left + 2;
 			else
 				pos =3D obj.getBoundingClientRect().right - 2;
@@ -569,17 +586,17 @@
 				x =3D x.offsetParent;
 			}
 			pos =3D n + obj.offsetLeft;
-			if(anchor_down !=3D 1)
+			if(${vpf}anchor_down !=3D 1)
 				pos +=3D obj.offsetWidth;
 		}
 		return pos;
 	}
=20
-	function getTopX( obj )
+	function ${vpf}getTopX( obj )
 	{
 		var pos =3D 0;
-		if( browserType() =3D=3D "ie" )
-			if(anchor_down)=20
+		if( ${vpf}browserType() =3D=3D "ie" )
+			if(${vpf}anchor_down)=20
 				pos =3D obj.getBoundingClientRect().bottom + 2;
 			else
 				pos =3D obj.getBoundingClientRect().top - 2;
@@ -591,68 +608,72 @@
 				x =3D x.offsetParent;
 			}
 			pos =3D n + obj.offsetTop;
-			if(anchor_down)
+			if(${vpf}anchor_down)
 				pos +=3D obj.offsetHeight;
 		}
 		return pos;
 	}
=20=09
-	function mouseout( obj, level )
+	function ${vpf}mouseout( obj, level )
 	{
-		if( browserType() =3D=3D "other" )
+		if( ${vpf}browserType() =3D=3D "other" )
 			return;
=20
 		if(level =3D=3D undefined)=20
 			level =3D 0;
 		level++;
-		timeoutCode =3D setTimeout( "menuClear();", 1000 );
+		${vpf}timeoutCode =3D setTimeout( "${vpf}menuClear();", 1000 );
 	}
=20
-	function menuClear(level)
+	function ${vpf}menuClear(level)
 	{
 		if (level =3D=3D undefined)
 			level =3D 0;
 		level++;
-		for( var i =3D level; i <=3D last_level; i++) {
-			var thisdiv =3D mydiv + i;
+		for( var i =3D level; i <=3D ${vpf}last_level; i++) {
+			var thisdiv =3D ${vpf}mydiv + i;
 			var fod =3D document.getElementById( thisdiv );
 			if(fod !=3D undefined)
 				fod.style.display =3D 'none';
 		}
-		clearTimeout( timeoutCode );
-		timeoutCode =3D -1;
+		clearTimeout( ${vpf}timeoutCode );
+		${vpf}timeoutCode =3D -1;
 	}
=20
-	function menuBusy()
+	function ${vpf}menuBusy()
 	{
-		clearTimeout( timeoutCode );
-		timeoutCode =3D -1;
+		clearTimeout( ${vpf}timeoutCode );
+		${vpf}timeoutCode =3D -1;
 	}
=20
-	var clientType =3D "unknown";
+	var ${vpf}clientType =3D "unknown";
=20
-	function browserType()
+	function ${vpf}browserType()
 	{
-		if( clientType !=3D "unknown"  )
-			return clientType;
+		if( ${vpf}clientType !=3D "unknown"  )
+			return ${vpf}clientType;
=20=09
-		clientType =3D "other";
+		${vpf}clientType =3D "other";
 		if (document.all) {
 			if( document.getElementById )
-		  		clientType =3D "ie";
+		  		${vpf}clientType =3D "ie";
 		}
 		else if (document.layers) {
 		}
 		else if (document.getElementById) {
-			clientType =3D "ns6";
+			${vpf}clientType =3D "ns6";
 		}
 		else
 		{
 		}
=20
-		return clientType;
+		return ${vpf}clientType;
 	}
=20
+// END CLIP
+EOF
+
+	push @out, <<EOF;
 </script>
 EOF
=20
@@ -663,7 +684,7 @@
 						display:none;
 						$opt->{flyout_style}
 					"
-		 OnMouseOver=3D"menuBusy();" OnMouseOut=3D"mouseout();"></DIV>
+		 OnMouseOver=3D"${vpf}menuBusy();" OnMouseOut=3D"${vpf}mouseout();"></DI=
V>
 EOF
 	}
=20
@@ -697,13 +718,14 @@
 	my @out;
 	# out 0
=20
+	my $vpf =3D $opt->{js_prefix} ||=3D 'mv_';
 	$opt->{toggle_class} ||=3D '';
-	$opt->{explode_url} ||=3D "javascript:do_explode(); void(0)";
-	$opt->{collapse_url} ||=3D "javascript:do_collapse(); void(0)";
+	$opt->{explode_url} ||=3D "javascript:${vpf}do_explode(); void(0)";
+	$opt->{collapse_url} ||=3D "javascript:${vpf}do_collapse(); void(0)";
 	$opt->{header_template} ||=3D <<EOF;
 <P>
 <a href=3D"{EXPLODE_URL}" {LINK_STYLE?} style=3D"{LINK_STYLE}"{/LINK_STYLE=
?} {LINK_CLASS?} class=3D"{LINK_CLASS}"{/LINK_CLASS?}>Explode tree</A><br>
-<a href=3D"{COLLAPSE_URL} {LINK_STYLE?} style=3D"{LINK_STYLE}"{/LINK_STYLE=
?} {LINK_CLASS?} class=3D"{LINK_CLASS}"{/LINK_CLASS?}">Collapse tree</A>
+<a href=3D"{COLLAPSE_URL}" {LINK_STYLE?} style=3D"{LINK_STYLE}"{/LINK_STYL=
E?} {LINK_CLASS?} class=3D"{LINK_CLASS}"{/LINK_CLASS?}">Collapse tree</A>
 </P>
 EOF
=20
@@ -718,11 +740,11 @@
 	$opt->{div_style} ||=3D '';
 	push @out, <<EOF;
=20
-<div id=3Dtreebox style=3D"visibility: Visible">
+<div id=3D${vpf}treebox style=3D"visibility: Visible">
 Test.
 </div>
 <script language=3D"JavaScript1.3">
-var lines =3D new Array;
+var ${vpf}lines =3D new Array;
 EOF
=20
 	my %o =3D (
@@ -733,6 +755,7 @@
 			autodetect  =3D> '1',
 			sort        =3D> $opt->{sort} || 'code',
 			iterator    =3D> \&tree_line,
+			js_prefix	=3D> $vpf,
 			full        =3D> '1',
 			spacing     =3D> '4',
 			_transform   =3D> $opt->{_transform},
@@ -750,72 +773,79 @@
 	else {
 		$CGI::values{open} =3D $::Scratch->{dhtml_tree_open};
 	}
-	my $out =3D '  var openstatus =3D [';
-	$out .=3D  join ",", split //, $CGI::values{open};
+	my $out =3D "  var ${vpf}openstatus =3D [";
+	my @open =3D  split /,/, $CGI::values{open};
+	my @o;
+
+	my %hsh =3D (map { ($_, 1) } @open);
+
+	for(0 .. $open[$#open]) {
+		push @o, ($hsh{$_} ? 1 : 0);
+	}
+	$out .=3D join ",", @o;
 	$out .=3D "];\n";
-	$out .=3D " var explode =3D ";
+	$out .=3D " var ${vpf}explode =3D ";
 	$out .=3D $CGI::values{explode} ? 1 : 0;
 	$out .=3D ";\n";
-	$out .=3D " var collapse =3D ";
+	$out .=3D " var ${vpf}collapse =3D ";
 	$out .=3D $CGI::values{collapse} ? 1 : 0;
 	$out .=3D ";\n";
=20
 	push @out, $out;
=20
 	push @out, <<EOF;
-var next_level =3D 0;
-var openstring =3D '';
-var link_class =3D '$opt->{link_class}';
-var link_class_open =3D '$opt->{link_class_open}';
-var link_class_closed =3D '$opt->{link_class_closed}';
-var link_style =3D '$opt->{link_style}';
-var link_style_open =3D '$opt->{link_style_open}';
-var link_style_closed =3D '$opt->{link_style_closed}';
-var toggle_class =3D '$opt->{toggle_class}';
-toggle_anchor_clear =3D '$opt->{toggle_anchor_clear}';
-toggle_anchor_closed =3D '$opt->{toggle_anchor_closed}';
-toggle_anchor_open =3D '$opt->{toggle_anchor_open}';
-var treebox =3D document.getElementById('treebox');
+var ${vpf}next_level =3D 0;
+var ${vpf}openstring =3D '';
+var ${vpf}link_class =3D '$opt->{link_class}';
+var ${vpf}link_class_open =3D '$opt->{link_class_open}';
+var ${vpf}link_class_closed =3D '$opt->{link_class_closed}';
+var ${vpf}link_style =3D '$opt->{link_style}';
+var ${vpf}link_style_open =3D '$opt->{link_style_open}';
+var ${vpf}link_style_closed =3D '$opt->{link_style_closed}';
+var ${vpf}toggle_class =3D '$opt->{toggle_class}';
+var ${vpf}toggle_anchor_clear =3D '$opt->{toggle_anchor_clear}';
+var ${vpf}toggle_anchor_closed =3D '$opt->{toggle_anchor_closed}';
+var ${vpf}toggle_anchor_open =3D '$opt->{toggle_anchor_open}';
+var ${vpf}treebox =3D document.getElementById('${vpf}treebox');
 EOF
=20
-	push @out, <<'EOF';
-function tree_link (idx) {
+	push @out, <<EOF unless $opt->{no_emit_code};
+function ${vpf}tree_link (idx) {
=20
 	var out =3D '';
=20
-	var l =3D lines[idx];
+	var l =3D ${vpf}lines[idx];
=20
 	if(l =3D=3D undefined) {
 		alert("Bad idx=3D" + idx + ", no line there.");
 		return;
 	}
=20
-	if(l[MV_LEVEL] > next_level)
+	if(l[${vpf}MV_LEVEL] > ${vpf}next_level)
 		return '';
-		// return 'next_level=3D' + next_level + ', mv_level=3D' + l[MV_LEVEL] +=
 '<br>';
-// alert("line is " + l);
+
 	var i;
-	var needed =3D l[MV_LEVEL];
+	var needed =3D l[${vpf}MV_LEVEL];
 	for(i =3D 1; i <=3D needed; i++)
 		out =3D out + '&nbsp;&nbsp;&nbsp;&nbsp;';
=20
-	var tstyle =3D link_style;
-	var tclass =3D link_class;
-	if(l[MV_CHILDREN] > 0) {
-		if(openstatus[idx] =3D=3D 1) {
-			tclass =3D link_class_open;
-			tstyle =3D link_style_open;
-			tanchor =3D toggle_anchor_open;
-			next_level =3D l[MV_LEVEL] + 1;
+	var tstyle =3D ${vpf}link_style;
+	var tclass =3D ${vpf}link_class;
+	if(l[${vpf}MV_CHILDREN] > 0) {
+		if(${vpf}openstatus[idx] =3D=3D 1) {
+			tclass =3D ${vpf}link_class_open;
+			tstyle =3D ${vpf}link_style_open;
+			tanchor =3D ${vpf}toggle_anchor_open;
+			${vpf}next_level =3D l[${vpf}MV_LEVEL] + 1;
 		}
 		else {
-			tclass =3D link_class_closed;
-			tstyle =3D link_style_closed;
-			tanchor =3D toggle_anchor_closed;
-			next_level =3D l[MV_LEVEL];
+			tclass =3D ${vpf}link_class_closed;
+			tstyle =3D ${vpf}link_style_closed;
+			tanchor =3D ${vpf}toggle_anchor_closed;
+			${vpf}next_level =3D l[${vpf}MV_LEVEL];
 		}
=20
-		out =3D out + '<a href=3D"javascript:toggit(' + idx + ');void(0)"';
+		out =3D out + '<a href=3D"javascript:${vpf}toggit(' + idx + ');void(0)"';
 		if(tclass)
 			out =3D out + ' class=3D"' + tclass + '"';
 		if(tstyle)
@@ -825,77 +855,93 @@
 		out =3D out + '</a>';
 	}
 	else {
-		out =3D out + toggle_anchor_clear;
-		next_level =3D l[MV_LEVEL];
+		out =3D out + ${vpf}toggle_anchor_clear;
+		next_level =3D l[${vpf}MV_LEVEL];
 	}
=20
-	if(l[PAGE]) {
-		out =3D out + '<a href=3D"' + l[PAGE] + openstring + '"';
+	if(l[${vpf}PAGE]) {
+		out =3D out + '<a href=3D"' + l[${vpf}PAGE] + ${vpf}openstring + '"';
 		if(tclass)
 			out =3D out + ' class=3D"' + tclass + '"';
 		if(tstyle)
 			out =3D out + ' style=3D"' + tstyle + '"';
-		if(l[DESCRIPTION])
-			out =3D out + ' title=3D"' + l[DESCRIPTION] + '"';
+		if(l[${vpf}DESCRIPTION])
+			out =3D out + ' title=3D"' + l[${vpf}DESCRIPTION] + '"';
 		out =3D out + '>';
-		out =3D out + l[NAME] + '</a>';
+		out =3D out + l[${vpf}NAME] + '</a>';
 	}
 	else {
-		out =3D out + l[NAME];
+		out =3D out + l[${vpf}NAME];
 	}
-	// out =3D out + ' level=3D' + l[MV_LEVEL] + ' children=3D' + l[MV_CHILDR=
EN];
-	// out =3D out + ' needed=3D' + needed + ", next_level=3D" + next_level;
 	out =3D out + '<br>';
=20
 	return out;
 }
-function toggit (idx) {
=20
-	var l =3D lines[idx];
+function ${vpf}toggit (idx) {
+
+	var l =3D ${vpf}lines[idx];
 	if(l =3D=3D undefined) {
 		alert("bad index " + idx);
 		return;
 	}
-	if(l[MV_CHILDREN] < 1) {
+	if(l[${vpf}MV_CHILDREN] < 1) {
 		alert("nothing to toggle at index " + idx);
 		return;
 	}
=20
-	openstatus[idx] =3D openstatus[idx] =3D=3D 1 ? 0 : 1;
-	openstring =3D openstatus.join('');
-	openstring =3D openstring.replace(/0+$/, '');
-	rewrite_tree();
+	${vpf}openstatus[idx] =3D ${vpf}openstatus[idx] =3D=3D 1 ? 0 : 1;
+	${vpf}gen_openstring();
+	${vpf}rewrite_tree();
 }
-function do_explode () {
-	for(var i =3D 0; i < lines.length; i++)
-		openstatus[i] =3D 1;
-	rewrite_tree();
+function ${vpf}gen_openstring () {
+	${vpf}openstring =3D '';
+	for(var p =3D 0; p < ${vpf}openstatus.length; p++) {
+		if(${vpf}openstatus[p])
+			${vpf}openstring +=3D p + ',';
+	}
+	${vpf}openstring =3D ${vpf}openstring.replace(/,+\$/, '');
+	return;
 }
-function do_collapse () {
-	for(var i =3D 0; i < lines.length; i++)
-		openstatus[i] =3D 0;
-	rewrite_tree();
+function ${vpf}do_explode () {
+	for(var i =3D 0; i < ${vpf}lines.length; i++)
+		${vpf}openstatus[i] =3D 1;
+	${vpf}gen_openstring();
+	${vpf}rewrite_tree();
 }
-function rewrite_tree () {
+function ${vpf}do_collapse () {
+	for(var i =3D 0; i < ${vpf}lines.length; i++)
+		${vpf}openstatus[i] =3D 0;
+	${vpf}gen_openstring();
+	${vpf}rewrite_tree();
+}
+function ${vpf}rewrite_tree () {
 	var thing =3D '';
-	for(i =3D 0; i < lines.length; i++) {
-		thing =3D thing + tree_link(i);
+	for(i =3D 0; i < ${vpf}lines.length; i++) {
+		thing =3D thing + ${vpf}tree_link(i);
 	}
-	treebox.innerHTML =3D thing;
-	next_level =3D 0;
+	${vpf}treebox.innerHTML =3D thing;
+	${vpf}next_level =3D 0;
 }
-if(collapse =3D=3D 1 || explode =3D=3D 1) {
-	openstatus.length =3D 0;
+
+// END CLIP
+
+EOF
+
+	push @out, <<EOF;
+
+if(${vpf}collapse =3D=3D 1 || ${vpf}explode =3D=3D 1) {
+	${vpf}openstatus.length =3D 0;
 }
-for( var i =3D 0; i < lines.length; i++) {
-	if(openstatus[i] =3D=3D undefined)
-		openstatus[i] =3D explode;
+for( var i =3D 0; i < ${vpf}lines.length; i++) {
+	if(${vpf}openstatus[i] =3D=3D undefined)
+		${vpf}openstatus[i] =3D ${vpf}explode;
 }
-collapse =3D 0;
-explode =3D 0;
-openstring =3D openstatus.join('');
-openstring =3D openstring.replace(/0+$/, '');
-rewrite_tree();
+
+${vpf}collapse =3D 0;
+${vpf}explode =3D 0;
+${vpf}gen_openstring();
+${vpf}rewrite_tree();
 </script>
 EOF
=20
@@ -989,8 +1035,9 @@
 	my $fields;
=20
 	if (! defined $opt->{loopinc}) {
+		my $vpf =3D $opt->{js_prefix} || 'mv_';
 		$opt->{loopinc} =3D 0;
-		$opt->{loopname} ||=3D 'lines';
+		$opt->{loopname} ||=3D $vpf . 'lines';
 		$fields =3D [qw/	code
 							parent_fld
 							mv_level
@@ -1019,7 +1066,7 @@
 		}
 		push @$fields, 'open';
 		for(my $i =3D 1; $i < @$fields; $i++) {
-			push @out, "var \U$fields->[$i]\E =3D $i;";
+			push @out, "var $vpf\U$fields->[$i]\E =3D $i;";
 		}
 		pop @$fields;
 		$opt->{loopfields} =3D $fields;
@@ -1132,6 +1179,59 @@
 sub menu {
 	my ($name, $opt, $template) =3D @_;
=20=09
+	if(! $name and ! $opt->{list}) {
+		# Auto menu for pages
+		if($::Scratch->{mv_menu}) {
+			my @names=3D qw/code page form anchor description/;
+			my $i =3D 0;
+			my %hash =3D map { ( $_, $i++) } @names;
+			my $code =3D '000';
+			my @rows;
+			my @items =3D split m{(?:</li\s*>)\s*<li>\s*}i, $::Scratch->{mv_menu};
+			for(@items) {
+				my ($page, $anchor, $form, $desc);
+				m{
+					<a \s+
+						(?:[^>]+\s+)?
+						title \s*=3D\s*
+						(["']) # mandatory quote
+							([^"'>\s]+)
+						\1      # end quote
+					}isx and $desc =3D $2;
+				m{
+					<a \s+
+						(?:[^>]+\s+)?
+						href \s*=3D\s*
+						(["']?) # possible quote
+							([^"'>\s]+)
+						\1      # end quote}isx
+					and $page =3D $2;
+				($page, $form) =3D split /\?/, $page, 2
+					if $page;
+				s{<a\s+.*?>}{}is;
+				s{</a>}{}i;
+				push @rows, [ $code++, $page, $form, $anchor, $desc ];
+			}
+			$opt->{list} =3D [ \@rows, \%hash, \@names ];
+
+		}
+		else {
+			my $page_name =3D $Global::Variable->{MV_PAGE};
+			my $dir =3D Vend::Tags->var('MV_MENU_DIRECTORY', 2) || 'include/menus';
+			while($page_name =3D~ s:/[^/]+$::) {
+				my $fn =3D "$dir/$page_name.txt";
+#::logDebug("page name=3D$page_name, testing for $fn");
+				if(-f $fn) {
+					$opt->{file} =3D $fn;
+					last;
+				}
+			}
+			if(! $opt->{file} and -f "$dir/default.txt") {
+				$opt->{file} =3D "$dir/default.txt";
+			}
+		}
+	}
+
 	$opt->{dhtml_browser} =3D dhtml_browser()
 		unless defined $opt->{dhtml_browser};
 	$opt->{menu_type} ||=3D 'simple';
@@ -1245,7 +1345,7 @@
 		return dhtml_flyout($name,$opt,$template);
 	}
 	elsif($opt->{menu_type} eq 'simple') {
-		if($opt->{search}) {
+		if($opt->{search} || $opt->{list}) {
 			## Do nothing
 		}
 		elsif(! $opt->{file}) {