Index: branches/2.8.x/CHANGELOG
===================================================================
--- branches/2.8.x/CHANGELOG	(revision 1350)
+++ branches/2.8.x/CHANGELOG	(revision 1351)
@@ -11,6 +11,8 @@
 ! = Update/Change
 
 ------------------------------------- 2.8.2 -------------------------------------
+21 Dec-2010 Dietmar Woellbrink (Luisehahne)
+# XHTML output fixed in show_menu2
 20 Dec-2010 Dietmar Woellbrink (Luisehahne)
 # syntaxfix in initialize.php
 19 Dec-2010 Dietmar Woellbrink (Luisehahne)
Index: branches/2.8.x/wb/admin/interface/version.php
===================================================================
--- branches/2.8.x/wb/admin/interface/version.php	(revision 1350)
+++ branches/2.8.x/wb/admin/interface/version.php	(revision 1351)
@@ -52,6 +52,6 @@
 
 // check if defined to avoid errors during installation (redirect to admin panel fails if PHP error/warnings are enabled)
 if(!defined('VERSION')) define('VERSION', '2.8.2.RC1');
-if(!defined('REVISION')) define('REVISION', '1350');
+if(!defined('REVISION')) define('REVISION', '1351');
 
 ?>
\ No newline at end of file
Index: branches/2.8.x/wb/modules/show_menu2/info.php
===================================================================
--- branches/2.8.x/wb/modules/show_menu2/info.php	(revision 1350)
+++ branches/2.8.x/wb/modules/show_menu2/info.php	(revision 1351)
@@ -1,27 +1,27 @@
-<?php
-/**
- *
- * @category        module
- * @package         show_menu2
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
- * @link			http://www.websitebaker2.org/
- * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.7.0 | 2.8.x
- * @requirements    PHP 5.2.2 and higher
- * @version         $Id$
- * @filesource		$HeadURL$
- * @lastmodified    $Date$
- *
- */
-
-$module_directory = 'show_menu2';
-$module_name = 'show_menu2';
-$module_function = 'snippet';
-$module_version = '4.9.1';
-$module_platform = '2.7 | 2.8.x';
-$module_author = 'Brodie Thiesfield';
-$module_license = 'GNU General Public License';
-$module_description = 'A code snippet for the Website Baker CMS providing a complete replacement for the builtin menu functions. See <a href="http://code.jellycan.com/show_menu2/" target="_blank">http://code.jellycan.com/show_menu2/</a> for details or view the <a href="' .WB_URL .'/modules/show_menu2/README.en.txt" target="_blank">readme</a> file.';
-?>
\ No newline at end of file
+<?php
+/**
+ *
+ * @category        module
+ * @package         show_menu2
+ * @author          WebsiteBaker Project
+ * @copyright       2004-2009, Ryan Djurovich
+ * @copyright       2009-2011, Website Baker Org. e.V.
+ * @link			http://www.websitebaker2.org/
+ * @license         http://www.gnu.org/licenses/gpl.html
+ * @platform        WebsiteBaker 2.8.x
+ * @requirements    PHP 5.2.2 and higher
+ * @version         $Id$
+ * @filesource		$HeadURL$
+ * @lastmodified    $Date$
+ *
+ */
+
+$module_directory = 'show_menu2';
+$module_name = 'show_menu2';
+$module_function = 'snippet';
+$module_version = '4.9.3';
+$module_platform = '2.7 | 2.8.2';
+$module_author = 'Brodie Thiesfield';
+$module_license = 'GNU General Public License';
+$module_description = 'A code snippet for the Website Baker CMS providing a complete replacement for the builtin menu functions. See <a href="http://code.jellycan.com/show_menu2/" target="_blank">http://code.jellycan.com/show_menu2/</a> for details or view the <a href="' .WB_URL .'/modules/show_menu2/README.en.txt" target="_blank">readme</a> file.';
+?>
Index: branches/2.8.x/wb/modules/show_menu2/README.de.txt
===================================================================
--- branches/2.8.x/wb/modules/show_menu2/README.de.txt	(revision 1350)
+++ branches/2.8.x/wb/modules/show_menu2/README.de.txt	(revision 1351)
@@ -1,15 +1,15 @@
 ﻿show_menu2, version 4.9
 =======================
-Ist ein Code-Snippet für das CMS Website Baker. Es stellt einen kompletten 
-Ersatz für die eingebaute Menüfuntionalität zur Verfügung. Alle, für die 
-Erzeugung des Menüs erforderlichen Daten, werden durch eine einzige 
-Datenbankabfrage erzeugt. Durch umfangreiche Anpassungsmöglichkeiten des 
-erzeugten HTML-Code können alle möglichen Menüarten (Listen, Breadcrumbs, 
+Ist ein Code-Snippet für das CMS Website Baker. Es stellt einen kompletten 
+Ersatz für die eingebaute Menüfuntionalität zur Verfügung. Alle, für die 
+Erzeugung des Menüs erforderlichen Daten, werden durch eine einzige 
+Datenbankabfrage erzeugt. Durch umfangreiche Anpassungsmöglichkeiten des 
+erzeugten HTML-Code können alle möglichen Menüarten (Listen, Breadcrumbs, 
 Sitemaps, usw.) erzeugt werden.
 
 ---
-Deutsche Übersetzung von BerndJM. Dies ist eine weitgehend direkte Übersetzung 
-des englischen Originals. Bei Übersetzungs- oder Interpretationsfehlern, bitte 
+Deutsche Übersetzung von BerndJM. Dies ist eine weitgehend direkte Übersetzung 
+des englischen Originals. Bei Übersetzungs- oder Interpretationsfehlern, bitte 
 eine Email an bjm@wwnw.de.
 ---
 
@@ -20,9 +20,9 @@
 1. Die aktuelle Version von http://code.jellycan.com/show_menu2/ herunterladen.
 2. In das Admin-Backend der Website Baker Installation einlogen.
 3. Erweiterungen -> Module aufrufen.
-4. Wenn bereits eine frühere Version von show_menu2 installiert ist, diese über
+4. Wenn bereits eine frühere Version von show_menu2 installiert ist, diese über
    "Modul deinstallieren" auswählen und deinstallieren.
-5. Im Abschnitt "Modul installieren" das im Schritt 1 heruntergeladene zip-File
+5. Im Abschnitt "Modul installieren" das im Schritt 1 heruntergeladene zip-File
    auswählen und installieren.
 
    
@@ -29,28 +29,28 @@
    
 BENUTZUNG VON SHOW_MENU2
 ========================
-Um show_menu2 zu benutzen muss das verwendete Template an den Stellen 
-modifiziert werden, an denen das Menü erscheinen soll. Bitte beachten: Wenn alte 
-Menüaufrufe ersetzt werden, müssen unbedingt auch die entsprechenden neuen 
+Um show_menu2 zu benutzen muss das verwendete Template an den Stellen 
+modifiziert werden, an denen das Menü erscheinen soll. Bitte beachten: Wenn alte 
+Menüaufrufe ersetzt werden, müssen unbedingt auch die entsprechenden neuen 
 Parameter verwendet werden die show_menu2 benötigt.
 
-In den meisten Fällen genügt bereits der Standardaufruf ohne weitere Parameter 
-von show_menu2. In diesem Fall werden die Vorgabewerte verwendet, dies erzeugt 
+In den meisten Fällen genügt bereits der Standardaufruf ohne weitere Parameter 
+von show_menu2. In diesem Fall werden die Vorgabewerte verwendet, dies erzeugt 
 ein Menü das die aktuelle Seite und die Unterseiten der aktuellen Seite anzeigt:
     
     show_menu2();
     
-Bitte beachten: der Aufruf von show_menu2 ist PHP und muss normalerweise in PHP-
-Codezeichen eingeschlossen werden (ausser der Aufruf erfolgt bereits innerhalb 
+Bitte beachten: der Aufruf von show_menu2 ist PHP und muss normalerweise in PHP-
+Codezeichen eingeschlossen werden (ausser der Aufruf erfolgt bereits innerhalb 
 von PHP Code):
 
     <?php show_menu2(); ?>
 
-Dieses Vorgabe Menü erzeugt bereits ein komplettes Menü auf Listenbasis mit 
-etlichen Klassen, die eine leichte Formatierung mittels CSS ermöglichen. Es wird 
-z.B. die Klasse "menu-current" zu dem <li> tag des aktuellen Menüpunktes 
-hinzugefügt. Zusätzlich erhält jeder Menüpunkt der Unterpunkte enthält die 
-Klasse "menu-expand". Das erlaubt es sehr differenzierte CSS Regeln für die 
+Dieses Vorgabe Menü erzeugt bereits ein komplettes Menü auf Listenbasis mit 
+etlichen Klassen, die eine leichte Formatierung mittels CSS ermöglichen. Es wird 
+z.B. die Klasse "menu-current" zu dem <li> tag des aktuellen Menüpunktes 
+hinzugefügt. Zusätzlich erhält jeder Menüpunkt der Unterpunkte enthält die 
+Klasse "menu-expand". Das erlaubt es sehr differenzierte CSS Regeln für die 
 einzelnen Menüpunkte aufzustellen.
 Zum Beispiel:
 
@@ -57,11 +57,11 @@
     li.menu-expand  { font-weight: bold; }
     li.menu-current { background: red; }
 
-Im Abschnitt "HTML-Ausgabe" findet sich eine detaillierte Beschreibung welche 
-Klassen welchem Element zugeordnet werden. Durch die Verwendung von 
-verschiedenen Parametern bei dem show_menu2 Funktionsaufruf lassen sich auch 
-recht umfangreiche und unterschiedliche Menüstrukturen erzeugen. Um 
-beispielsweise nur Menüpunkte aus der obersten Ebene der Menüstruktur 
+Im Abschnitt "HTML-Ausgabe" findet sich eine detaillierte Beschreibung welche 
+Klassen welchem Element zugeordnet werden. Durch die Verwendung von 
+verschiedenen Parametern bei dem show_menu2 Funktionsaufruf lassen sich auch 
+recht umfangreiche und unterschiedliche Menüstrukturen erzeugen. Um 
+beispielsweise nur Menüpunkte aus der obersten Ebene der Menüstruktur 
 darzustellen, könnte man folgenden Aufruf verwenden:
 
     show_menu2(0, SM2_ROOT, SM2_START);
@@ -70,8 +70,8 @@
 
     show_menu2(0, SM2_CURR+1, SM2_CURR+2);
 
-Es gibt jede Menge Möglichkeiten, um die unterschiedlichsten Menüstrukturen zu 
-erzeugen. Zahlreiche Beispiele dazu findet man auf der Demo-Website: http://
+Es gibt jede Menge Möglichkeiten, um die unterschiedlichsten Menüstrukturen zu 
+erzeugen. Zahlreiche Beispiele dazu findet man auf der Demo-Website: http://
 code.jellycan.com/sm2test/
 
 
@@ -84,25 +84,25 @@
 
 
 Q:  Wie kann ich ein sogenanntes Drop-Down Menü erstellen?
-A:  Dies hat nichts mit show_menu2 zu tun. Um ein Drop-Down Menü zu erzeugen muß
-    lediglich der CSS-Code des jeweiligen Templates angepaßt werden. Die nötigen 
-    Anpassungen findet man z.B. im "allcss2" Template aus dem WB Addon     
+A:  Dies hat nichts mit show_menu2 zu tun. Um ein Drop-Down Menü zu erzeugen muß
+    lediglich der CSS-Code des jeweiligen Templates angepaßt werden. Die nötigen 
+    Anpassungen findet man z.B. im "allcss2" Template aus dem WB Addon     
     Repository -> http://addons.websitebaker.org/pages/templates.php
 
 
-Q:  Warum verschwindet das Menü nachdem ich in einer mehrsprachigen WB-Site die 
+Q:  Warum verschwindet das Menü nachdem ich in einer mehrsprachigen WB-Site die 
     Suchfunktion benutzt habe?
-A:  Im verwendeten Template fehlen die notwendigen Zeilen:
-
-    1.  Im WB Admin Backend: Optionen -> Erweiterte Optionen anzeigen ->        
-        Suchoptionen -> Kopfzeile - hier direkt nach dem öffnenden <form> tag 
-        folgende Zeile einfügen:
-       +A:  Im verwendeten Template fehlen die notwendigen Zeilen:
+
+    1.  Im WB Admin Backend: Optionen -> Erweiterte Optionen anzeigen ->        
+        Suchoptionen -> Kopfzeile - hier direkt nach dem öffnenden <form> tag 
+        folgende Zeile einfügen:
+       
         <input type="hidden" name="referrer" value="[REFERRER_ID]" />
 
-    2.  In der index.php des verwendeten Templates folgende Zeile unmittelbar   
-        nach dem öffnenden <form> tag der Suche einfügen:
-
+    2.  In der index.php des verwendeten Templates folgende Zeile unmittelbar   
+        nach dem öffnenden <form> tag der Suche einfügen:
+
         <input type="hidden" name="referrer" value="<?php echo defined('REFERRER_ID')?REFERRER_ID:PAGE_ID;?>" />
 
 
@@ -112,9 +112,9 @@
 
 Q:  Jedesmal wenn eine Seite aufgerufen wird, erzeugt SM2 folgende Warnmeldung:
     "show_menu2 error: $aOptions is invalid. No flags from group 1 supplied!"
-A:  Der Funktion wurden die falschen Werte oder eine falsche Anzahl an 
-    Werten übergeben.
-    Siehe den Abschnitt PARAMETER für die korrekten Flag Werte die dem 
+A:  Der Funktion wurden die falschen Werte oder eine falsche Anzahl an 
+    Werten übergeben.
+    Siehe den Abschnitt PARAMETER für die korrekten Flag Werte die dem 
     $aOptions Parameter zu übergeben sind.    
 
 
@@ -169,9 +169,9 @@
         $aTopMenuOpen   = false
         )
 
-Im Abschnitt "Parameter" findet sich eine detaillierte Beschreibung jedes 
-einzelnen Parameters.
-Jeder Parameter muß absolut korrekt verwendet werden. Folgende Regeln können 
+Im Abschnitt "Parameter" findet sich eine detaillierte Beschreibung jedes 
+einzelnen Parameters.
+Jeder Parameter muß absolut korrekt verwendet werden. Folgende Regeln können 
 dabei helfen:
 
     $aMenu = 0 ist in den meisten Anwendungsfällen der beste Wert.
@@ -180,17 +180,17 @@
     
     $aMaxLevel kann nur Werte erhalten, die mit "SM2_" beginnen.
     
-    $aOptions bis auf einige wenige Spezialfälle sind hier nur Werte die mit 
+    $aOptions bis auf einige wenige Spezialfälle sind hier nur Werte die mit 
     "SM2_" beginnen zulässig.
     
-    Alle weiteren Parameter enthalten die (HTML)Tags die die Ausgabe des Menüs 
+    Alle weiteren Parameter enthalten die (HTML)Tags die die Ausgabe des Menüs 
     steuern.
     
-    Ab $aItemOpen kann jedem Parameter der Wert false übergeben werden um den 
+    Ab $aItemOpen kann jedem Parameter der Wert false übergeben werden um den 
     jeweiligen Vorgabewert zu erhalten.
 
-    Dies kann beispielsweise verwendet werden um eine nummerierte Liste zu 
-    erzeugen, während für die einzelnen Menüpunkte trotzdem die Vorgabewerte 
+    Dies kann beispielsweise verwendet werden um eine nummerierte Liste zu 
+    erzeugen, während für die einzelnen Menüpunkte trotzdem die Vorgabewerte 
     Verwendung finden:
 
         show_menu2(0, SM2_ROOT, SM2_ALL, SM2_ALL, false, false, '<ol>', '</ol>');
@@ -215,7 +215,7 @@
     menu-first      Der erste Punkt eines jeden Menüs oder Untermenüs.
     menu-last       Der letzte Punkt eines jeden Menüs oder Untermenüs.
 
-    Folgende Klassen werden nur hinzugefügt, wenn das SM2_NUMCLASS Flag gesetzt 
+    Folgende Klassen werden nur hinzugefügt, wenn das SM2_NUMCLASS Flag gesetzt 
     ist:
 
     menu-N          Jeder Menüpunkt, wobei das N für die ABSOLUTE Menütiefe, 
@@ -268,14 +268,14 @@
 PARAMETER
 =========
 $aMenu      
-    Nummer des Menüs. Diese ist nützlich um mehrere Menüs auf einer Seite zu    
+    Nummer des Menüs. Diese ist nützlich um mehrere Menüs auf einer Seite zu    
     verwenden.
     Menü Nummer 0 ist das Vorgabemenü der aktuellen Seite, SM2_ALLMENU gibt alle
     im System verwendeten Menüs zurück.
 
 $aStart  
-    Gibt an, ab welcher Ebene die Erzeugung des Menüs beginnen soll. In den     
-    meisten Fällen wird dies die oberste Ebene des anzuzeigenden Menüs sein. Es 
+    Gibt an, ab welcher Ebene die Erzeugung des Menüs beginnen soll. In den     
+    meisten Fällen wird dies die oberste Ebene des anzuzeigenden Menüs sein. Es 
     kann einer der folgenden Werte verwendet werden:
 
         SM2_ROOT+N  Beginnt N Ebenen unterhalb der obersten Ebene, z.B.:
@@ -290,9 +290,9 @@
                                   mit allen Unterebenen
 
         page_id     Verwendet die Seite mit der angegebenen page id als Elternelement.
-                    Alle Untermenüs dieser Seite werden angezeigt. 
-                    (Die page id kann ermittelt werden, wenn man die Seite im 
-                    Admin-Backend editiert, sie steht dann in der Adresszeile des      
+                    Alle Untermenüs dieser Seite werden angezeigt. 
+                    (Die page id kann ermittelt werden, wenn man die Seite im 
+                    Admin-Backend editiert, sie steht dann in der Adresszeile des      
                     Browsers: http://SITE/admin/pages/modify.php?page_id=35
 
 $aMaxLevel   
@@ -379,11 +379,11 @@
                     mit SM2_NOCACHE, sonst zeigt es keine Wirkung.
     
     SM2_NOCACHE     Die aus der Datenbank gelesenen Daten werden bei erneutem Aufruf von
-                    show_menu2 nicht wiederverwendet sondern erneut aus der Datenbank 
+                    show_menu2 nicht wiederverwendet sondern erneut aus der Datenbank 
                     gelesen.
     
     SM2_PRETTY      Bringt die HTML-Ausgabe des Menüs mittels Leerzeichen und
-                    Zeilenumbrüchen in eine gut lesbare Form. Das ist besonders 
+                    Zeilenumbrüchen in eine gut lesbare Form. Das ist besonders 
                     nützlich beim Debuggen der Menüausgabe.
     
     SM2_BUFFER      Gibt den HTML-Code nicht direkt aus, sondern speichert ihn intern
@@ -405,9 +405,18 @@
                     release 4.8, supply this flag to enable hidden pages to
                     become visible when they are active.
 
-    Für diesen Parameter gibt es auch einen erweiterten Modus, bei dem die Optionen
-    als assoziatives Array übergeben werden. Näheres dazu im Abschnitt ERWEITERTE
-    OPTIONEN. Für die meisten Anwendungsfälle wird dies jedoch NICHT benötigt.
+    SM2_XHTML_STRICT	Stellt die XHTML-Kompatibilität der Links sicher indem
+					in per [a] oder [ac] formatierten Links die Targetangabe
+					entfernt und das Argument title="[page_titel]" eingefügt
+					wird. Bei manuell zusammengestellten Links ist der Designer
+					selbst für die XHTML-Konformität zuständig.
+
+	SM2_NO_TITLE	Unterdrückt die Ausgabe des Inhaltes des Title-Attributes
+					bei [a] oder [ac] formatierten links.
+
+    Für diesen Parameter gibt es auch einen erweiterten Modus, bei dem die Optionen
+    als assoziatives Array übergeben werden. Näheres dazu im Abschnitt ERWEITERTE
+    OPTIONEN. Für die meisten Anwendungsfälle wird dies jedoch NICHT benötigt.
     
 $aItemOpen
     Dies legt den Formatstring fest, mit dem jeder einzelne Menüeintrag begonnen
@@ -421,7 +430,7 @@
     verwenden: '<li>[ac][menu_title]</a>'.
     
     Dieser Parameter kann auch als Instanz eine Formatierungklasse für das Menü
-    verwendet werden. Die nähere Beschreibung dazu findet sich im Abschnitt FORMATTER. 
+    verwendet werden. Die nähere Beschreibung dazu findet sich im Abschnitt FORMATTER. 
     Wenn hier ein Formatter angegeben wird, werden alle Argumente
     nach $aItemOpen ignoriert.
 
@@ -455,23 +464,23 @@
     
 
 ERWEITERTE OPTIONEN
-===================
-Der Parameter $aOptions kann auf zweierlei Arten verwendet werden. Zum einen, wie oben 
-im Abschnitt PARAMETER beschrieben, diese Art sollte für die allermeisten 
-Anwendungsfälle ausreichen. Um allerdings in speziellen Fällen die Sonderoptionen 
-ansprechen zu können, müssen die erforderlichen Werte als assoziatives Array 
-bereitgestellt werden.
-Bitte beachten: Die SM2_* Flags sind auch hierbei erforderlich und müßen als 'flags' 
-übergeben werden.
+===================
+Der Parameter $aOptions kann auf zweierlei Arten verwendet werden. Zum einen, wie oben 
+im Abschnitt PARAMETER beschrieben, diese Art sollte für die allermeisten 
+Anwendungsfälle ausreichen. Um allerdings in speziellen Fällen die Sonderoptionen 
+ansprechen zu können, müssen die erforderlichen Werte als assoziatives Array 
+bereitgestellt werden.
+Bitte beachten: Die SM2_* Flags sind auch hierbei erforderlich und müßen als 'flags' 
+übergeben werden.
 
-    'flags'     **ZWINGEND ERFORDELICH** Dies sind die Flags die oben im Abschnitt 
+    'flags'     **ZWINGEND ERFORDELICH** Dies sind die Flags die oben im Abschnitt 
                 PARAMETER unter $aOptions beschrieben wurden.
 
-    'notrim'    Hiermit wird eine Anzahl von Ebenen festegelegt, die relativ bezogen 
-                auf die in $aStart festgelegte Menüebene, immer angezeigt werden. Dies 
-                bewirkt, daß für diese Ebenen das SM2_TRIM Flag ignoriert wird.
-
-Um dieses Array zu verwenden, empfiehlt es sich es erst anzulegen und dann den 
+    'notrim'    Hiermit wird eine Anzahl von Ebenen festegelegt, die relativ bezogen 
+                auf die in $aStart festgelegte Menüebene, immer angezeigt werden. Dies 
+                bewirkt, daß für diese Ebenen das SM2_TRIM Flag ignoriert wird.
+
+Um dieses Array zu verwenden, empfiehlt es sich es erst anzulegen und dann den 
 $aOptions parameter mit dem angelegten Array zu beliefern:
 
     $options = array('flags' => (SM2_TRIM|...), 'notrim' => 1);
@@ -489,15 +498,18 @@
 [li]            <li> tag mit Klasse:   '<li class="[class]">'
 [ul]            <ul> tag mit Klasse:   '<ul class="[class]">'
 [class]         Liste der Klassen für diese Seite
-[menu_title]    Text des Menütitel 
+[menu_title]    Text des Menütitel 
                 (HTML entity escaped ausser das SM2_NOESCAPE Flag ist gesetzt)
-[page_title]    text des Seitentitel 
+[menu_icon_0]	die URL zu einer Bilddatei mit normal - Darstellung (ab WB2.9.0)
+[menu_icon_1]	die URL zu einer Bilddatei mit active/hover - Darstellung (ab WB2.9.0)
+[page_title]    text des Seitentitel 
                 (HTML entity escaped ausser das SM2_NOESCAPE Flag ist gesetzt)
+[page_icon]		die URL zu einer seitenbezogenen Bilddatei (ab WB2.9.0)
 [url]           die URL der Seiten für den <a> tag
 [target]        das Seitenziel für den <a> tag
 [page_id]       die Page ID des aktuellen Menüpunktes.
 [parent]        die Page ID des übergeordneten Menüpunktes.
-[level]         die Seitenebene, 
+[level]         die Seitenebene, 
                 dies ist die gleiche Zahl die im "menu-N" CSS tag verwendet wird.
 [sib]           Anzahl der Geschwister des aktuellen Menüpunktes.
 [sibCount]      Anzahl aller Geschwister in diesem Menü.
@@ -535,7 +547,7 @@
 Wenn mehr als ein Vergleich erforderlich ist, so muss dieser mit den anderen Vergleichen
 mittels || (boolsches oder - OR) oder && (boolsches und - AND) verknüpft werden.    
 
-Ein einzelner Vergleich besteht aus dem linken Operanden, dem Operator und dem rechten 
+Ein einzelner Vergleich besteht aus dem linken Operanden, dem Operator und dem rechten 
 Operanden.
 z.B. X == Y  - hierbei ist X der linke Operand, == der Operator und Y der rechte Operand.
     
@@ -548,6 +560,7 @@
         sib         Überprüfung der Geschwisteranzahl der aktuellen Seite.
         sibCount    Überprüfung der Geamtanzahl der Geschwister im aktuellen Menü.
         id          Überprüfung der page id.
+		target		Überprüfung der Target-Angabe
     
     Operator. Muss einer der folgenden sein:
         <           Kleiner als
@@ -575,6 +588,7 @@
         sib         Eine positive Integerzahl, oder "sibCount" um die Anzahl der
                     Geschwister in diesem Menü zu überprüfen
         sibCount    Eine positive Integerzahl
+		target		Ein String, der eine mögliche Targetangabe darstellt
         
 Folgende Beispiele ergeben "wahr" und der Ausdruck {exp} wird ausgeführt, wenn zutrifft:
     
@@ -587,11 +601,12 @@
     [if(sib==2){exp}]               ist der zweite Eintrag in einem Menü
     [if(sibCount>1){exp}]           ist in einem Menü mit mehr als einem Eintrag
     [if(sibCount!=2){exp}]          ist in einem Menü, das nicht genau 2 Einträge hat
-    [if(level>parent){exp}]         ist in einem Geschwistermenü oder dem Untermenü eines      
+    [if(level>parent){exp}]         ist in einem Geschwistermenü oder dem Untermenü eines      
                                     Geschwistermenüs
     [if(id==parent){exp}]           ist der übergeordnete Punkt der aktuellen id
+	[if(target==_self){exp}]		im Target-Attribut ist der String '_self' enthalten
 
-Wenn eine sonst-Klausel (else) hinzugefügt wird, so wird diese in allen anderen Fällen 
+Wenn eine sonst-Klausel (else) hinzugefügt wird, so wird diese in allen anderen Fällen 
 ausgeführt.
 Zum Beispiel wird "foo" immer dann ausgeführt, wenn die if Überprüfung falsch ergibt, also:
 
@@ -600,10 +615,10 @@
 
 Bei mehrfach Vergleichen wird der Ausdruck "exp" nur ausgeführt, wenn:
 
-    [if(sib == 1 || sib > 3){exp}]  ist der erste Eintrag ODER ist der vierte oder höhere   
+    [if(sib == 1 || sib > 3){exp}]  ist der erste Eintrag ODER ist der vierte oder höhere   
     Eintrag im Menü    
                
-    [if(id == current && class == menu-expand){exp}  ist der aktuelle Eintrag UND hat 
+    [if(id == current && class == menu-expand){exp}  ist der aktuelle Eintrag UND hat 
     Untermenüs
         
 Bitte beachten:
Index: branches/2.8.x/wb/modules/show_menu2/include.php
===================================================================
--- branches/2.8.x/wb/modules/show_menu2/include.php	(revision 1350)
+++ branches/2.8.x/wb/modules/show_menu2/include.php	(revision 1351)
@@ -1,821 +1,840 @@
-<?php
-/**
- *
- * @category        module
- * @package         show_menu2
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
- * @link			http://www.websitebaker2.org/
- * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.7.0 | 2.8.x
- * @requirements    PHP 5.2.2 and higher
- * @version         $Id$
- * @filesource		$HeadURL$
- * @lastmodified    $Date$
- *
- */
-
-define('SM2_ROOT',       -1000);
-define('SM2_CURR',       -2000);
-define('SM2_ALLMENU',       -1);
-define('SM2_START',       1000);
-define('SM2_MAX',         2000);
-define('SM2_ALL',       0x0001); // bit 0 (group 1) (Note: also used for max level!)
-define('SM2_TRIM',      0x0002); // bit 1 (group 1)
-define('SM2_CRUMB',     0x0004); // bit 2 (group 1)
-define('SM2_SIBLING',   0x0008); // bit 3 (group 1)
-define('SM2_NUMCLASS',  0x0010); // bit 4
-define('SM2_ALLINFO',   0x0020); // bit 5
-define('SM2_NOCACHE',   0x0040); // bit 6
-define('SM2_PRETTY',    0x0080); // bit 7
-define('SM2_ESCAPE',    0x0100); // bit 8
-define('SM2_NOESCAPE',       0); // NOOP, unnecessary with WB 2.6.7+
-define('SM2_BUFFER',    0x0200); // bit 9
-define('SM2_CURRTREE',  0x0400); // bit 10
-define('SM2_SHOWHIDDEN', 0x0800); // bit 11
-
-define('_SM2_GROUP_1',  0x000F); // exactly one flag from group 1 is required
-
-
-// Implement support for page_menu and show_menu using show_menu2. If you remove
-// the comments characters from the beginning of the following include, all menu
-// functions in Website Baker will be implemented using show_menu2. While it is
-// commented out, the original WB functions will be used.
-//include('legacy.php');
-
-// This class is the default menu formatter for sm2. If desired, you can 
-// create your own formatter class and pass the object into show_menu2 
-// as $aItemFormat.
-define('SM2_CONDITIONAL','if\s*\(([^\)]+)\)\s*{([^}]*)}\s*(?:else\s*{([^}]*)}\s*)?');
-define('SM2_COND_TERM','\s*(\w+)\s*(<|<=|==|=|=>|>|!=)\s*([\w\-]+)\s*');
-class SM2_Formatter
-{
-    var $output;
-    var $flags;
-    var $itemOpen;
-    var $itemClose;
-    var $menuOpen;
-    var $menuClose;
-    var $topItemOpen;
-    var $topMenuOpen;
-    
-    var $isFirst;
-    var $page;
-    var $url;
-    var $currSib;
-    var $sibCount;
-    var $currClass;
-    var $prettyLevel;
-
-    // output the data
-    function output($aString) {
-        if ($this->flags & SM2_BUFFER) {
-            $this->output .= $aString;
-        }
-        else {
-            echo $aString;
-        }
-    }
-    
-    // set the default values for all of our formatting items
-    function set($aFlags, $aItemOpen, $aItemClose, $aMenuOpen, $aMenuClose, $aTopItemOpen, $aTopMenuOpen) {
-        $this->flags        = $aFlags;
-        $this->itemOpen     = is_string($aItemOpen)    ? $aItemOpen    : '[li][a][menu_title]</a>';
-        $this->itemClose    = is_string($aItemClose)   ? $aItemClose   : '</li>';
-        $this->menuOpen     = is_string($aMenuOpen)    ? $aMenuOpen    : '[ul]';
-        $this->menuClose    = is_string($aMenuClose)   ? $aMenuClose   : '</ul>';
-        $this->topItemOpen  = is_string($aTopItemOpen) ? $aTopItemOpen : $this->itemOpen;
-        $this->topMenuOpen  = is_string($aTopMenuOpen) ? $aTopMenuOpen : $this->menuOpen;
-    }
-
-    // initialize the state of the formatter before anything is output
-    function initialize() {
-        $this->output = '';
-        $this->prettyLevel = 0;
-        if ($this->flags & SM2_PRETTY) {
-            $this->output("\n<!-- show_menu2 -->");
-        }
-    }
-
-    // start a menu     
-    function startList(&$aPage, &$aUrl) {
-        $currClass = '';
-        $currItem = $this->menuOpen;
-        
-        // use the top level menu open if this is the first menu
-        if ($this->topMenuOpen) {
-            $currItem = $this->topMenuOpen;
-            $currClass .= ' menu-top';
-            $this->topMenuOpen = false;
-        }
-        
-        // add the numbered menu class only if requested
-        if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
-            $currClass .= ' menu-'.$aPage['level'];
-        }
-        
-        $this->prettyLevel += 1;
-        
-        // replace all keywords in the output
-        if ($this->flags & SM2_PRETTY) {
-            $this->output("\n".str_repeat(' ',$this->prettyLevel).
-                $this->format($aPage, $aUrl, $currItem, $currClass));
-        }
-        else {
-            $this->output($this->format($aPage, $aUrl, $currItem, $currClass));
-        }
-        
-        $this->prettyLevel += 3;
-    }
-    
-    // start an item within the menu
-    function startItem(&$aPage, &$aUrl, $aCurrSib, $aSibCount) {
-        // generate our class list
-        $currClass = '';
-        if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
-            $currClass .= ' menu-'.$aPage['level'];
-        }
-        if (array_key_exists('sm2_has_child', $aPage)) {
-            // not set if false, so existence = true
-            $currClass .= ' menu-expand';
-        }
-        if (array_key_exists('sm2_is_curr', $aPage)) { 
-            $currClass .= ' menu-current';
-        }
-        elseif (array_key_exists('sm2_is_parent', $aPage)) { 
-            // not set if false, so existence = true
-            $currClass .= ' menu-parent';
-        }
-        elseif (array_key_exists('sm2_is_sibling', $aPage)) {
-            // not set if false, so existence = true
-            $currClass .= ' menu-sibling';
-        }
-        elseif (array_key_exists('sm2_child_level',$aPage)) {
-            // not set if not a child
-            $currClass .= ' menu-child';
-            if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
-                $currClass .= ' menu-child-'.($aPage['sm2_child_level']-1);
-            }
-        }
-        if ($aCurrSib == 1) {
-            $currClass .= ' menu-first';
-        }
-        if ($aCurrSib == $aSibCount) {
-            $currClass .= ' menu-last';
-        }
-
-        // use the top level item if this is the first item
-        $currItem = $this->itemOpen;
-        if ($this->topItemOpen) {
-            $currItem = $this->topItemOpen;
-            $this->topItemOpen = false;
-        }
-
-        // replace all keywords in the output
-        if ($this->flags & SM2_PRETTY) {
-            $this->output("\n".str_repeat(' ',$this->prettyLevel));
-        }
-        $this->output($this->format($aPage, $aUrl, $currItem, $currClass, $aCurrSib, $aSibCount));
-    }
-    
-    // find and replace all keywords, setting the state variables first
-    function format(&$aPage, &$aUrl, &$aCurrItem, &$aCurrClass, 
-        $aCurrSib = 0, $aSibCount = 0) 
-    {
-        $this->page      = &$aPage;
-        $this->url       = &$aUrl;
-        $this->currClass = trim($aCurrClass);
-        $this->currSib   = $aCurrSib;
-        $this->sibCount  = $aSibCount;
-        
-        $item = $this->format2($aCurrItem);
-        
-        unset($this->page);
-        unset($this->url);
-        unset($this->currClass);
-        
-        return $item;
-    }
-    
-    // find and replace all keywords
-    function format2(&$aCurrItem) {
-        if (!is_string($aCurrItem)) return '';
-        return preg_replace(
-            '@\[('.
-                'a|ac|/a|li|/li|ul|/ul|menu_title|page_title|url|target|page_id|'.
-                'parent|level|sib|sibCount|class|description|keywords|'.
-                SM2_CONDITIONAL.
-            ')\]@e', 
-            '$this->replace("\1")', $aCurrItem);
-    }
-    
-    // replace the keywords
-    function replace($aMatch) {
-        switch ($aMatch) {
-        case 'a':
-            return '<a href="'.$this->url.'" target="'.$this->page['target'].'">';
-        case 'ac':
-            return '<a href="'.$this->url.'" target="'.$this->page['target'].'" class="'.$this->currClass.'">';
-        case '/a':
-            return '</a>';
-        case 'li':
-            return '<li class="'.$this->currClass.'">';
-        case '/li':
-            return '</li>';
-        case 'ul':
-            return '<ul class="'.$this->currClass.'">';
-        case '/ul':
-            return '</ul>';
-        case 'url':
-            return $this->url;
-        case 'sib':
-            return $this->currSib;
-        case 'sibCount':
-            return $this->sibCount;
-        case 'class':
-            return $this->currClass;
-        default:
-            if (array_key_exists($aMatch, $this->page)) {
-                if ($this->flags & SM2_ESCAPE) {
-                    return htmlspecialchars($this->page[$aMatch], ENT_QUOTES);
-                }
-                else {
-                    return $this->page[$aMatch];
-                }
-            }
-            if (preg_match('/'.SM2_CONDITIONAL.'/', $aMatch, $rgMatches)) {
-                return $this->replaceIf($rgMatches[1], $rgMatches[2], $rgMatches[3]);
-            }
-        }
-        return "[$aMatch=UNKNOWN]";
-    }
-    
-    // conditional replacement
-    function replaceIf(&$aExpression, &$aIfValue, &$aElseValue) {
-        // evaluate all of the tests in the conditional (we don't do short-circuit
-        // evaluation) and replace the string test with the boolean result
-        $rgTests = preg_split('/(\|\||\&\&)/', $aExpression, -1, PREG_SPLIT_DELIM_CAPTURE);
-        for ($n = 0; $n < count($rgTests); $n += 2) {
-            if (preg_match('/'.SM2_COND_TERM.'/', $rgTests[$n], $rgMatches)) {
-                $rgTests[$n] = $this->ifTest($rgMatches[1], $rgMatches[2], $rgMatches[3]);
-            }
-            else {
-                @error_logs("show_menu2 error: conditional expression is invalid!");
-                $rgTests[$n] = false;
-            }
-        }
-
-        // combine all test results for a final result
-        $ok = $rgTests[0];
-        for ($n = 1; $n+1 < count($rgTests); $n += 2) {
-            if ($rgTests[$n] == '||') {
-                $ok = $ok || $rgTests[$n+1];
-            }
-            else {
-                $ok = $ok && $rgTests[$n+1];
-            }
-        }
-        
-        // return the formatted expression if the test succeeded
-        return $ok ? $this->format2($aIfValue) : $this->format2($aElseValue);
-    }
-
-    // conditional test
-    function ifTest(&$aKey, &$aOperator, &$aValue) {
-        global $wb;
-        
-        // find the correct operand
-        $operand = false;
-        switch($aKey) {
-        case 'class':
-            // we need to wrap the class names in spaces so we can test for a unique
-            // class name that will not match prefixes or suffixes. Same must be done
-            // for the value we are testing.
-            $operand = " $this->currClass "; 
-            break;
-        case 'sib':
-            $operand = $this->currSib;
-            if ($aValue == 'sibCount') {
-                $aValue = $this->sibCount;
-            }
-            break;
-        case 'sibCount':
-            $operand = $this->sibCount;
-            break;
-        case 'level':
-            $operand = $this->page['level'];
-            switch ($aValue) {
-            case 'root':    $aValue = 0; break;
-            case 'granny':  $aValue = $wb->page['level']-2; break;
-            case 'parent':  $aValue = $wb->page['level']-1; break;
-            case 'current': $aValue = $wb->page['level'];   break;
-            case 'child':   $aValue = $wb->page['level']+1; break;
-            }
-            if ($aValue < 0) $aValue = 0;
-            break;
-        case 'id':
-            $operand = $this->page['page_id'];
-            switch ($aValue) {
-            case 'parent':  $aValue = $wb->page['parent'];  break;
-            case 'current': $aValue = $wb->page['page_id']; break;
-            }
-            break;
-        default:
-            return '';
-        }
-
-        // do the test        
-        $ok = false;
-        switch ($aOperator) { 
-        case '<':
-            $ok = ($operand < $aValue); 
-            break;
-        case '<=':
-            $ok = ($operand <= $aValue); 
-            break;
-        case '=':
-        case '==':
-        case '!=':
-            if ($aKey == 'class') {
-                $ok = strstr($operand, " $aValue ") !== FALSE;
-            }
-            else {
-                $ok = ($operand == $aValue); 
-            }
-            if ($aOperator == '!=') {
-                $ok = !$ok;
-            }
-            break;
-        case '>=':
-            $ok = ($operand >= $aValue); 
-        case '>':
-            $ok = ($operand > $aValue); 
-        }
-        
-        return $ok;
-    }
-    
-    // finish the current menu item
-    function finishItem() {
-        if ($this->flags & SM2_PRETTY) {
-            $this->output(str_repeat(' ',$this->prettyLevel).$this->itemClose);
-        }
-        else {
-            $this->output($this->itemClose);
-        }
-    }
-
-    // finish the current menu
-    function finishList() {
-        $this->prettyLevel -= 3;
-        
-        if ($this->flags & SM2_PRETTY) {
-            $this->output("\n".str_repeat(' ',$this->prettyLevel).$this->menuClose."\n");
-        }
-        else {
-            $this->output($this->menuClose);
-        }
-        
-        $this->prettyLevel -= 1;
-    }
-    
-    // cleanup the state of the formatter after everything has been output
-    function finalize() {
-        if ($this->flags & SM2_PRETTY) {
-            $this->output("\n");
-        }
-    }
-
-    // return the output
-    function getOutput() {
-        return $this->output;
-    }
-};
-
-function error_logs($error_str)
-{
-                $log_error = true;
-                if ( ! function_exists('error_log') )
-                        $log_error = false;
-
-                $log_file = @ini_get('error_log');
-                if ( !empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file) )
-                        $log_error = false;
-
-                if ( $log_error )
-                        @error_log($error_str, 0);
-}
-
-function show_menu2(
-    $aMenu          = 0,
-    $aStart         = SM2_ROOT,
-    $aMaxLevel      = -1999, // SM2_CURR+1
-    $aOptions       = SM2_TRIM,
-    $aItemOpen      = false,
-    $aItemClose     = false,
-    $aMenuOpen      = false,
-    $aMenuClose     = false,
-    $aTopItemOpen   = false,
-    $aTopMenuOpen   = false
-    )
-{
-    global $wb;
-
-    // extract the flags and set $aOptions to an array
-    $flags = 0;
-    if (is_int($aOptions)) {
-        $flags = $aOptions;
-        $aOptions = array();
-    }
-    else if (isset($aOptions['flags'])) {
-        $flags = $aOptions['flags'];
-    }
-    else {
-        $flags = SM2_TRIM;
-        $aOptions = array();
-        @error_logs('show_menu2 error: $aOptions is invalid. No flags supplied!');
-    }
-    
-    // ensure we have our group 1 flag, we don't check for the "exactly 1" part, but
-    // we do ensure that they provide at least one.
-    if (0 == ($flags & _SM2_GROUP_1)) {
-        @error_logs('show_menu2 error: $aOptions is invalid. No flags from group 1 supplied!');
-        $flags |= SM2_TRIM; // default to TRIM
-    }
-    
-    // search page results don't have any of the page data loaded by WB, so we load it 
-    // ourselves using the referrer ID as the current page
-    $CURR_PAGE_ID = defined('REFERRER_ID') ? REFERRER_ID : PAGE_ID;
-    if (count($wb->page) == 0 && defined('REFERRER_ID') && REFERRER_ID > 0) {
-        global $database;
-        $sql = 'SELECT * FROM `'.TABLE_PREFIX.'pages` WHERE `page_id` = '.REFERRER_ID.'';
-        $result = $database->query($sql);
-        if ($result->numRows() == 1) {
-            $wb->page = $result->fetchRow();
-        }
-        unset($result);
-    }
-    
-    // fix up the menu number to default to the menu number
-    // of the current page if no menu has been supplied
-    if ($aMenu == 0) {
-        $aMenu = $wb->page['menu'] == '' ? 1 : $wb->page['menu'];
-    } 
-
-    // Set some of the $wb->page[] settings to defaults if not set
-    $pageLevel  = $wb->page['level']  == '' ? 0 : $wb->page['level'];
-    $pageParent = $wb->page['parent'] == '' ? 0 : $wb->page['parent'];
-    
-    // adjust the start level and start page ID as necessary to
-    // handle the special values that can be passed in as $aStart
-    $aStartLevel = 0;
-    if ($aStart < SM2_ROOT) {   // SM2_CURR+N
-        if ($aStart == SM2_CURR) {
-            $aStartLevel = $pageLevel;
-            $aStart = $pageParent;
-        }
-        else {
-            $aStartLevel = $pageLevel + $aStart - SM2_CURR;
-            $aStart = $CURR_PAGE_ID; 
-        }
-    }
-    elseif ($aStart < 0) {   // SM2_ROOT+N
-        $aStartLevel = $aStart - SM2_ROOT;
-        $aStart = 0;
-    }
-
-    // we get the menu data once and store it in a global variable. This allows 
-    // multiple calls to show_menu2 in a single page with only a single call to 
-    // the database. If this variable exists, then we have already retrieved all
-    // of the information and processed it, so we don't need to do it again.
-    if (($flags & SM2_NOCACHE) != 0
-        || !array_key_exists('show_menu2_data', $GLOBALS)
-        || !array_key_exists($aMenu, $GLOBALS['show_menu2_data'])) 
-    {
-        global $database;
-
-        // create an array of all parents of the current page. As the page_trail
-        // doesn't include the theoretical root element 0, we add it ourselves.
-        $rgCurrParents = explode(",", '0,'.$wb->page['page_trail']);
-        array_pop($rgCurrParents); // remove the current page
-        $rgParent = array();
-
-        // if the caller wants all menus gathered together (e.g. for a sitemap)
-        // then we don't limit our SQL query
-        $menuLimitSql = ' AND menu = ' .$aMenu;
-        if ($aMenu == SM2_ALLMENU) {
-            $menuLimitSql = '';
-        }
-
-        // we only load the description and keywords if we have been told to,
-        // this cuts the memory load for pages that don't use them. Note that if
-        // we haven't been told to load these fields the *FIRST TIME* show_menu2
-        // is called (i.e. where the database is loaded) then the info won't
-        // exist anyhow.
-        $fields = 'parent,page_id,menu_title,page_title,link,target,level,visibility,viewing_groups';
-        if (version_compare(WB_VERSION, '2.7', '>=')) { // WB 2.7+
-            $fields .= ',viewing_users';
-        }
-        if ($flags & SM2_ALLINFO) {
-            $fields = '*';
-        }
-
-        // we request all matching rows from the database for the menu that we
-        // are about to create it is cheaper for us to get everything we need
-        // from the database once and create the menu from memory then make 
-        // multiple calls to the database. 
-        $sql = "SELECT $fields FROM ".TABLE_PREFIX.
-               "pages WHERE $wb->extra_where_sql $menuLimitSql ".
-               'ORDER BY level ASC, position ASC';
-        $sql = str_replace('hidden', 'IGNOREME', $sql); // we want the hidden pages
-        $oRowset = $database->query($sql);
-        if (is_object($oRowset) && $oRowset->numRows() > 0) {
-            // create an in memory array of the database data based on the item's parent. 
-            // The array stores all elements in the correct display order.
-            while ($page = $oRowset->fetchRow()) {
-                // ignore all pages that the current user is not permitted to view
-                if(version_compare(WB_VERSION, '2.7', '>=')) { // WB >= 2.7
-                    // 1. hidden pages aren't shown unless they are on the current page
-                    if ($page['visibility'] == 'hidden') {
-                        $page['sm2_hide'] = true;
-                    }
-                    
-                    // 2. all pages with no active sections (unless it is the top page) are ignored
-                    else if (!$wb->page_is_active($page) && $page['link'] != $wb->default_link && !INTRO_PAGE) {
-                        continue;
-                    }
-
-                    // 3. all pages not visible to this user (unless always visible to registered users) are ignored
-                    else if (!$wb->page_is_visible($page) && $page['visibility'] != 'registered') {
-                        continue;
-                    }
-                }
-
-                // ensure that we have an array entry in the table to add this to
-                $idx = $page['parent'];
-                if (!array_key_exists($idx, $rgParent)) {
-                    $rgParent[$idx] = array();
-                }
-
-                // mark our current page as being on the current path
-                if ($page['page_id'] == $CURR_PAGE_ID) {
-                    $page['sm2_is_curr'] = true;
-                    $page['sm2_on_curr_path'] = true;
-                    if ($flags & SM2_SHOWHIDDEN) 
-					{ 
-                        // show hidden pages if active and SHOWHIDDEN flag supplied
-                        unset($page['sm2_hide']); 
-                    }
-                }
-
-                // mark parents of the current page as such
-                if (in_array($page['page_id'], $rgCurrParents)) {
-                    $page['sm2_is_parent'] = true;
-                    $page['sm2_on_curr_path'] = true;
-                    if ($flags & SM2_SHOWHIDDEN) 
-					{
-                        // show hidden pages if active and SHOWHIDDEN flag supplied
-						unset($page['sm2_hide']); // don't hide a parent page                
-                    }
-                }
-                
-                // add the entry to the array                
-                $rgParent[$idx][] = $page;
-            }
-        }    
-        unset($oRowset);
-
-        // mark all elements that are siblings of any element on the current path
-        foreach ($rgCurrParents as $x) {
-            if (array_key_exists($x, $rgParent)) {
-                foreach (array_keys($rgParent[$x]) as $y) {
-                    $mark =& $rgParent[$x][$y];
-                    $mark['sm2_path_sibling'] = true;
-                    unset($mark);
-                }
-            }
-        }
-
-        // mark all elements that have children and are siblings of the current page
-        $parentId = $pageParent;
-        foreach (array_keys($rgParent) as $x) {
-            $childSet =& $rgParent[$x];
-            foreach (array_keys($childSet) as $y) {
-                $mark =& $childSet[$y];
-                if (array_key_exists($mark['page_id'], $rgParent)) {
-                    $mark['sm2_has_child'] = true;
-                }
-                if ($mark['parent'] == $parentId && $mark['page_id'] != $CURR_PAGE_ID) {
-                    $mark['sm2_is_sibling'] = true;
-                }
-                unset($mark);
-            }
-            unset($childSet);
-        }
-        
-        // mark all children of the current page. We don't do this when 
-        // $CURR_PAGE_ID is 0, as 0 is the parent of everything. 
-        // $CURR_PAGE_ID == 0 occurs on special pages like search results
-        // when no referrer is available.s
-        if ($CURR_PAGE_ID != 0) {
-            sm2_mark_children($rgParent, $CURR_PAGE_ID, 1);
-        }
-        
-        // store the complete processed menu data as a global. We don't 
-        // need to read this from the database anymore regardless of how 
-        // many menus are displayed on the same page.
-        if (!array_key_exists('show_menu2_data', $GLOBALS)) {
-            $GLOBALS['show_menu2_data'] = array();
-        }
-        $GLOBALS['show_menu2_data'][$aMenu] =& $rgParent;
-        unset($rgParent);
-    }
-
-    // adjust $aMaxLevel to the level number of the final level that 
-    // will be displayed. That is, we display all levels <= aMaxLevel.
-    if ($aMaxLevel == SM2_ALL) {
-        $aMaxLevel = 1000;
-    }
-    elseif ($aMaxLevel < 0) {   // SM2_CURR+N
-        $aMaxLevel += $pageLevel - SM2_CURR;
-    }
-    elseif ($aMaxLevel >= SM2_MAX) { // SM2_MAX+N
-        $aMaxLevel += $aStartLevel - SM2_MAX;
-        if ($aMaxLevel > $pageLevel) {
-            $aMaxLevel = $pageLevel;
-        }
-    }
-    else {  // SM2_START+N
-        $aMaxLevel += $aStartLevel - SM2_START;
-    }
-
-    // generate the menu
-    $retval = false;
-    if (array_key_exists($aStart, $GLOBALS['show_menu2_data'][$aMenu])) {
-        $formatter = $aItemOpen;
-        if (!is_object($aItemOpen)) {
-            static $sm2formatter;
-            if (!isset($sm2formatter)) {
-                $sm2formatter = new SM2_Formatter;
-            }
-            $formatter = $sm2formatter;
-            $formatter->set($flags, $aItemOpen, $aItemClose, 
-                $aMenuOpen, $aMenuClose, $aTopItemOpen, $aTopMenuOpen);
-        }
-        
-        // adjust the level until we show everything and ignore the SM2_TRIM flag.
-        // Usually this will be less than the start level to disable it.
-        $showAllLevel = $aStartLevel - 1;
-        if (isset($aOptions['notrim'])) {
-            $showAllLevel = $aStartLevel + $aOptions['notrim'];
-        }
-        
-        // display the menu
-        $formatter->initialize();
-        sm2_recurse(
-            $GLOBALS['show_menu2_data'][$aMenu],
-            $aStart,    // parent id to start displaying sub-menus
-            $aStartLevel, $showAllLevel, $aMaxLevel, $flags, 
-            $formatter);
-        $formatter->finalize();
-        
-        // if we are returning something, get the data
-        if (($flags & SM2_BUFFER) != 0) {
-            $retval = $formatter->getOutput();
-        }
-    }
-
-    // clear the data if we aren't caching it
-    if (($flags & SM2_NOCACHE) != 0) {
-        unset($GLOBALS['show_menu2_data'][$aMenu]);
-    }
-    
-    return $retval;
-}
-
-function sm2_mark_children(&$rgParent, $aStart, $aChildLevel)
-{
-    if (array_key_exists($aStart, $rgParent)) {
-        foreach (array_keys($rgParent[$aStart]) as $y) {
-            $mark =& $rgParent[$aStart][$y];
-            $mark['sm2_child_level'] = $aChildLevel;
-            $mark['sm2_on_curr_path'] = true;
-            sm2_mark_children($rgParent, $mark['page_id'], $aChildLevel+1);
-        }
-    }
-}
-
-function sm2_recurse(
-    &$rgParent, $aStart, 
-    $aStartLevel, $aShowAllLevel, $aMaxLevel, $aFlags, 
-    &$aFormatter
-    )
-{
-    global $wb;
-
-    // on entry to this function we know that there are entries for this 
-    // parent and all entries for that parent are being displayed. We also 
-    // need to check if any of the children need to be displayed too.
-    $isListOpen = false;
-    $currentLevel = $wb->page['level'] == '' ? 0 : $wb->page['level'];
-
-    // get the number of siblings skipping the hidden pages so we can pass 
-    // this in and check if the item is first or last
-    $sibCount = 0;
-    foreach ($rgParent[$aStart] as $page) {
-        if (!array_key_exists('sm2_hide', $page)) $sibCount++;
-    }
-    
-    $currSib = 0;
-    foreach ($rgParent[$aStart] as $page) {
-        // skip all hidden pages 
-        if (array_key_exists('sm2_hide', $page)) { // not set if false, so existence = true
-            continue;
-        }
-        
-        $currSib++;
-
-        // skip any elements that are lower than the maximum level
-        $pageLevel = $page['level'];
-        if ($pageLevel > $aMaxLevel) {
-            continue;
-        }
-        
-        // this affects ONLY the top level
-        if ($aStart == 0 && ($aFlags & SM2_CURRTREE)) {
-            if (!array_key_exists('sm2_on_curr_path', $page)) { // not set if false, so existence = true
-                continue;
-            }
-            $sibCount = 1;
-        }
-        
-        // trim the tree as appropriate
-        if ($aFlags & SM2_SIBLING) {
-            // parents, and siblings and children of current only
-            if (!array_key_exists('sm2_on_curr_path', $page)      // not set if false, so existence = true
-                && !array_key_exists('sm2_is_sibling', $page)     // not set if false, so existence = true
-                && !array_key_exists('sm2_child_level', $page)) { // not set if false, so existence = true
-                continue;
-            }
-        }
-        else if ($aFlags & SM2_TRIM) {
-            // parents and siblings of parents
-            if ($pageLevel > $aShowAllLevel  // permit all levels to be shown
-                && !array_key_exists('sm2_on_curr_path', $page)    // not set if false, so existence = true
-                && !array_key_exists('sm2_path_sibling', $page)) {  // not set if false, so existence = true
-                continue;
-            }
-        }
-        elseif ($aFlags & SM2_CRUMB) {
-            // parents only
-            if (!array_key_exists('sm2_on_curr_path', $page)    // not set if false, so existence = true
-                || array_key_exists('sm2_child_level', $page)) {  // not set if false, so existence = true
-                continue;
-            }
-        }
-
-        // depth first traverse
-        $nextParent = $page['page_id'];
-
-        // display the current element if we have reached the start level
-        if ($pageLevel >= $aStartLevel) {
-            // massage the link into the correct form
-            if(!INTRO_PAGE && $page['link'] == $wb->default_link) {
-                $url = WB_URL;
-            }
-            else {
-                $url = $wb->page_link($page['link']);
-            }
-                    
-            // we open the list only when we absolutely need to
-            if (!$isListOpen) {
-                $aFormatter->startList($page, $url);
-                $isListOpen = true;
-            }
-
-            $aFormatter->startItem($page, $url, $currSib, $sibCount);
-        }
-        
-        // display children as appropriate
-        if ($pageLevel + 1 <= $aMaxLevel 
-            && array_key_exists('sm2_has_child', $page)) {  // not set if false, so existence = true
-            sm2_recurse(
-                $rgParent, $nextParent, // parent id to start displaying sub-menus
-                $aStartLevel, $aShowAllLevel, $aMaxLevel, $aFlags, 
-                $aFormatter);
-        }
-        
-        // close the current element if appropriate
-        if ($pageLevel >= $aStartLevel) {
-            $aFormatter->finishItem($pageLevel, $page);
-        }
-    }
-
-    // close the list if we opened one
-    if ($isListOpen) {
-        $aFormatter->finishList();
-    }
-}
-
-?>
\ No newline at end of file
+<?php
+/**
+ *
+ * @category        module
+ * @package         show_menu2
+ * @author          WebsiteBaker Project
+ * @copyright       2004-2009, Ryan Djurovich
+ * @copyright       2009-2010, Website Baker Org. e.V.
+ * @link			http://www.websitebaker2.org/
+ * @license         http://www.gnu.org/licenses/gpl.html
+ * @platform        WebsiteBaker 2.7.0 | 2.8.x
+ * @requirements    PHP 4.4.9 and higher
+ * @version         $Id$
+ * @filesource		$HeadURL$
+ * @lastmodified    $Date$
+ *
+ */
+
+define('SM2_ROOT',          -1000);
+define('SM2_CURR',          -2000);
+define('SM2_ALLMENU',          -1);
+define('SM2_START',          1000);
+define('SM2_MAX',            2000);
+define('SM2_ALL',          0x0001); // bit 0 (group 1) (Note: also used for max level!)
+define('SM2_TRIM',         0x0002); // bit 1 (group 1)
+define('SM2_CRUMB',        0x0004); // bit 2 (group 1)
+define('SM2_SIBLING',      0x0008); // bit 3 (group 1)
+define('SM2_NUMCLASS',     0x0010); // bit 4
+define('SM2_ALLINFO',      0x0020); // bit 5
+define('SM2_NOCACHE',      0x0040); // bit 6
+define('SM2_PRETTY',       0x0080); // bit 7
+define('SM2_ESCAPE',       0x0100); // bit 8
+define('SM2_NOESCAPE',          0); // NOOP, unnecessary with WB 2.6.7+
+define('SM2_BUFFER',       0x0200); // bit 9
+define('SM2_CURRTREE',     0x0400); // bit 10
+define('SM2_SHOWHIDDEN',   0x0800); // bit 11
+define('SM2_XHTML_STRICT', 0x1000); // bit 12
+define('SM2_NO_TITLE',     0x1001); // bit 13
+
+define('_SM2_GROUP_1',  0x000F); // exactly one flag from group 1 is required
+
+
+// Implement support for page_menu and show_menu using show_menu2. If you remove
+// the comments characters from the beginning of the following include, all menu
+// functions in Website Baker will be implemented using show_menu2. While it is
+// commented out, the original WB functions will be used.
+//include('legacy.php');
+
+// This class is the default menu formatter for sm2. If desired, you can 
+// create your own formatter class and pass the object into show_menu2 
+// as $aItemFormat.
+define('SM2_CONDITIONAL','if\s*\(([^\)]+)\)\s*{([^}]*)}\s*(?:else\s*{([^}]*)}\s*)?');
+define('SM2_COND_TERM','\s*(\w+)\s*(<|<=|==|=|=>|>|!=)\s*([\w\-]+)\s*');
+class SM2_Formatter
+{
+    var $output;
+    var $flags;
+    var $itemOpen;
+    var $itemClose;
+    var $menuOpen;
+    var $menuClose;
+    var $topItemOpen;
+    var $topMenuOpen;
+    
+    var $isFirst;
+    var $page;
+    var $url;
+    var $currSib;
+    var $sibCount;
+    var $currClass;
+    var $prettyLevel;
+
+    // output the data
+    function output($aString) {
+        if ($this->flags & SM2_BUFFER) {
+            $this->output .= $aString;
+        }
+        else {
+            echo $aString;
+        }
+    }
+    
+    // set the default values for all of our formatting items
+    function set($aFlags, $aItemOpen, $aItemClose, $aMenuOpen, $aMenuClose, $aTopItemOpen, $aTopMenuOpen) {
+        $this->flags        = $aFlags;
+        $this->itemOpen     = is_string($aItemOpen)    ? $aItemOpen    : '[li][a][menu_title]</a>';
+        $this->itemClose    = is_string($aItemClose)   ? $aItemClose   : '</li>';
+        $this->menuOpen     = is_string($aMenuOpen)    ? $aMenuOpen    : '[ul]';
+        $this->menuClose    = is_string($aMenuClose)   ? $aMenuClose   : '</ul>';
+        $this->topItemOpen  = is_string($aTopItemOpen) ? $aTopItemOpen : $this->itemOpen;
+        $this->topMenuOpen  = is_string($aTopMenuOpen) ? $aTopMenuOpen : $this->menuOpen;
+    }
+
+    // initialize the state of the formatter before anything is output
+    function initialize() {
+        $this->output = '';
+        $this->prettyLevel = 0;
+        if ($this->flags & SM2_PRETTY) {
+            $this->output("\n<!-- show_menu2 -->");
+        }
+    }
+
+    // start a menu     
+    function startList(&$aPage, &$aUrl) {
+        $currClass = '';
+        $currItem = $this->menuOpen;
+        
+        // use the top level menu open if this is the first menu
+        if ($this->topMenuOpen) {
+            $currItem = $this->topMenuOpen;
+            $currClass .= ' menu-top';
+            $this->topMenuOpen = false;
+        }
+        
+        // add the numbered menu class only if requested
+        if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
+            $currClass .= ' menu-'.$aPage['level'];
+        }
+        
+        $this->prettyLevel += 1;
+        
+        // replace all keywords in the output
+        if ($this->flags & SM2_PRETTY) {
+            $this->output("\n".str_repeat(' ',$this->prettyLevel).
+                $this->format($aPage, $aUrl, $currItem, $currClass));
+        }
+        else {
+            $this->output($this->format($aPage, $aUrl, $currItem, $currClass));
+        }
+        
+        $this->prettyLevel += 3;
+    }
+    
+    // start an item within the menu
+    function startItem(&$aPage, &$aUrl, $aCurrSib, $aSibCount) {
+        // generate our class list
+        $currClass = '';
+        if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
+            $currClass .= ' menu-'.$aPage['level'];
+        }
+        if (array_key_exists('sm2_has_child', $aPage)) {
+            // not set if false, so existence = true
+            $currClass .= ' menu-expand';
+        }
+        if (array_key_exists('sm2_is_curr', $aPage)) { 
+            $currClass .= ' menu-current';
+        }
+        elseif (array_key_exists('sm2_is_parent', $aPage)) { 
+            // not set if false, so existence = true
+            $currClass .= ' menu-parent';
+        }
+        elseif (array_key_exists('sm2_is_sibling', $aPage)) {
+            // not set if false, so existence = true
+            $currClass .= ' menu-sibling';
+        }
+        elseif (array_key_exists('sm2_child_level',$aPage)) {
+            // not set if not a child
+            $currClass .= ' menu-child';
+            if (($this->flags & SM2_NUMCLASS) == SM2_NUMCLASS) {
+                $currClass .= ' menu-child-'.($aPage['sm2_child_level']-1);
+            }
+        }
+        if ($aCurrSib == 1) {
+            $currClass .= ' menu-first';
+        }
+        if ($aCurrSib == $aSibCount) {
+            $currClass .= ' menu-last';
+        }
+
+        // use the top level item if this is the first item
+        $currItem = $this->itemOpen;
+        if ($this->topItemOpen) {
+            $currItem = $this->topItemOpen;
+            $this->topItemOpen = false;
+        }
+
+        // replace all keywords in the output
+        if ($this->flags & SM2_PRETTY) {
+            $this->output("\n".str_repeat(' ',$this->prettyLevel));
+        }
+        $this->output($this->format($aPage, $aUrl, $currItem, $currClass, $aCurrSib, $aSibCount));
+    }
+    
+    // find and replace all keywords, setting the state variables first
+    function format(&$aPage, &$aUrl, &$aCurrItem, &$aCurrClass, 
+        $aCurrSib = 0, $aSibCount = 0) 
+    {
+        $this->page      = &$aPage;
+        $this->url       = &$aUrl;
+        $this->currClass = trim($aCurrClass);
+        $this->currSib   = $aCurrSib;
+        $this->sibCount  = $aSibCount;
+        
+        $item = $this->format2($aCurrItem);
+        
+        unset($this->page);
+        unset($this->url);
+        unset($this->currClass);
+        
+        return $item;
+    }
+    
+    // find and replace all keywords
+    function format2(&$aCurrItem) {
+        if (!is_string($aCurrItem)) return '';
+        return preg_replace(
+            '@\[('.
+                'a|ac|/a|li|/li|ul|/ul|menu_title|menu_icon_0|menu_icon_1|'.
+				'page_title|page_icon|url|target|page_id|'.
+                'parent|level|sib|sibCount|class|description|keywords|'.
+                SM2_CONDITIONAL.
+            ')\]@e', 
+            '$this->replace("\1")', $aCurrItem);
+    }
+    
+    // replace the keywords
+    function replace($aMatch) {
+        $retval = '['.$aMatch.'=UNKNOWN]';
+		$retval_1 = '';
+        switch ($aMatch) {
+        case 'a':
+            $retval_1 = '<a href="'.$this->url.'"';
+		case 'ac':
+            $retval = '<a href="'.$this->url.'" class="'.$this->currClass.'"';
+			$retval = ($retval_1 == '') ? $retval : $retval_1;
+			if(!($this->flags & SM2_XHTML_STRICT))
+			{
+				$retval .= ' target="'.$this->page['target'].'"';
+			}
+			$retval .= ' title="'.(($this->flags & SM2_NO_TITLE) ? '&nbsp;' : $this->page['page_title']).'">';
+			break;
+        case '/a':
+            $retval = '</a>'; break;
+        case 'li':
+            $retval = '<li class="'.$this->currClass.'">'; break;
+        case '/li':
+            $retval = '</li>'; break;
+        case 'ul':
+            $retval = '<ul class="'.$this->currClass.'">'; break;
+        case '/ul':
+            $retval = '</ul>'; break;
+        case 'url':
+            $retval = $this->url; break;
+        case 'sib':
+            $retval = $this->currSib; break;
+        case 'sibCount':
+            $retval = $this->sibCount; break;
+        case 'class':
+            $retval = $this->currClass; break;
+        default:
+            if (array_key_exists($aMatch, $this->page)) {
+                if ($this->flags & SM2_ESCAPE) {
+                    $retval = htmlspecialchars($this->page[$aMatch], ENT_QUOTES);
+                }
+                else {
+                    $retval = $this->page[$aMatch];
+                }
+            }
+            if (preg_match('/'.SM2_CONDITIONAL.'/', $aMatch, $rgMatches)) {
+                $retval = $this->replaceIf($rgMatches[1], $rgMatches[2], $rgMatches[3]);
+            }
+        }
+        return $retval;
+    }
+    
+    // conditional replacement
+    function replaceIf(&$aExpression, &$aIfValue, &$aElseValue) {
+        // evaluate all of the tests in the conditional (we don't do short-circuit
+        // evaluation) and replace the string test with the boolean result
+        $rgTests = preg_split('/(\|\||\&\&)/', $aExpression, -1, PREG_SPLIT_DELIM_CAPTURE);
+        for ($n = 0; $n < count($rgTests); $n += 2) {
+            if (preg_match('/'.SM2_COND_TERM.'/', $rgTests[$n], $rgMatches)) {
+                $rgTests[$n] = $this->ifTest($rgMatches[1], $rgMatches[2], $rgMatches[3]);
+            }
+            else {
+                @error_logs("show_menu2 error: conditional expression is invalid!");
+                $rgTests[$n] = false;
+            }
+        }
+
+        // combine all test results for a final result
+        $ok = $rgTests[0];
+        for ($n = 1; $n+1 < count($rgTests); $n += 2) {
+            if ($rgTests[$n] == '||') {
+                $ok = $ok || $rgTests[$n+1];
+            }
+            else {
+                $ok = $ok && $rgTests[$n+1];
+            }
+        }
+        
+        // return the formatted expression if the test succeeded
+        return $ok ? $this->format2($aIfValue) : $this->format2($aElseValue);
+    }
+
+    // conditional test
+    function ifTest(&$aKey, &$aOperator, &$aValue) {
+        global $wb;
+        
+        // find the correct operand
+        $operand = false;
+        switch($aKey) {
+        case 'class':
+            // we need to wrap the class names in spaces so we can test for a unique
+            // class name that will not match prefixes or suffixes. Same must be done
+            // for the value we are testing.
+            $operand = " $this->currClass "; 
+            break;
+		case 'target':
+			$operand = $this->page['target'];
+			break;
+        case 'sib':
+            $operand = $this->currSib;
+            if ($aValue == 'sibCount') {
+                $aValue = $this->sibCount;
+            }
+            break;
+        case 'sibCount':
+            $operand = $this->sibCount;
+            break;
+        case 'level':
+            $operand = $this->page['level'];
+            switch ($aValue) {
+            case 'root':    $aValue = 0; break;
+            case 'granny':  $aValue = $wb->page['level']-2; break;
+            case 'parent':  $aValue = $wb->page['level']-1; break;
+            case 'current': $aValue = $wb->page['level'];   break;
+            case 'child':   $aValue = $wb->page['level']+1; break;
+            }
+            if ($aValue < 0) $aValue = 0;
+            break;
+        case 'id':
+            $operand = $this->page['page_id'];
+            switch ($aValue) {
+            case 'parent':  $aValue = $wb->page['parent'];  break;
+            case 'current': $aValue = $wb->page['page_id']; break;
+            }
+            break;
+        default:
+            return '';
+        }
+
+        // do the test        
+        $ok = false;
+        switch ($aOperator) { 
+        case '<':
+            $ok = ($operand < $aValue); 
+            break;
+        case '<=':
+            $ok = ($operand <= $aValue); 
+            break;
+        case '=':
+        case '==':
+        case '!=':
+            if ($aKey == 'class') {
+                $ok = strstr($operand, " $aValue ") !== FALSE;
+            }
+            else {
+                $ok = ($operand == $aValue); 
+            }
+            if ($aOperator == '!=') {
+                $ok = !$ok;
+            }
+            break;
+        case '>=':
+            $ok = ($operand >= $aValue); 
+        case '>':
+            $ok = ($operand > $aValue); 
+        }
+        
+        return $ok;
+    }
+    
+    // finish the current menu item
+    function finishItem() {
+        if ($this->flags & SM2_PRETTY) {
+            $this->output(str_repeat(' ',$this->prettyLevel).$this->itemClose);
+        }
+        else {
+            $this->output($this->itemClose);
+        }
+    }
+
+    // finish the current menu
+    function finishList() {
+        $this->prettyLevel -= 3;
+        
+        if ($this->flags & SM2_PRETTY) {
+            $this->output("\n".str_repeat(' ',$this->prettyLevel).$this->menuClose."\n");
+        }
+        else {
+            $this->output($this->menuClose);
+        }
+        
+        $this->prettyLevel -= 1;
+    }
+    
+    // cleanup the state of the formatter after everything has been output
+    function finalize() {
+        if ($this->flags & SM2_PRETTY) {
+            $this->output("\n");
+        }
+    }
+
+    // return the output
+    function getOutput() {
+        return $this->output;
+    }
+};
+
+function error_logs($error_str)
+{
+                $log_error = true;
+                if ( ! function_exists('error_log') )
+                        $log_error = false;
+
+                $log_file = @ini_get('error_log');
+                if ( !empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file) )
+                        $log_error = false;
+
+                if ( $log_error )
+                        @error_log($error_str, 0);
+}
+
+function show_menu2(
+    $aMenu          = 0,
+    $aStart         = SM2_ROOT,
+    $aMaxLevel      = -1999, // SM2_CURR+1
+    $aOptions       = SM2_TRIM,
+    $aItemOpen      = false,
+    $aItemClose     = false,
+    $aMenuOpen      = false,
+    $aMenuClose     = false,
+    $aTopItemOpen   = false,
+    $aTopMenuOpen   = false
+    )
+{
+    global $wb;
+
+    // extract the flags and set $aOptions to an array
+    $flags = 0;
+    if (is_int($aOptions)) {
+        $flags = $aOptions;
+        $aOptions = array();
+    }
+    else if (isset($aOptions['flags'])) {
+        $flags = $aOptions['flags'];
+    }
+    else {
+        $flags = SM2_TRIM;
+        $aOptions = array();
+        @error_logs('show_menu2 error: $aOptions is invalid. No flags supplied!');
+    }
+    
+    // ensure we have our group 1 flag, we don't check for the "exactly 1" part, but
+    // we do ensure that they provide at least one.
+    if (0 == ($flags & _SM2_GROUP_1)) {
+        @error_logs('show_menu2 error: $aOptions is invalid. No flags from group 1 supplied!');
+        $flags |= SM2_TRIM; // default to TRIM
+    }
+    
+    // search page results don't have any of the page data loaded by WB, so we load it 
+    // ourselves using the referrer ID as the current page
+    $CURR_PAGE_ID = defined('REFERRER_ID') ? REFERRER_ID : PAGE_ID;
+    if (count($wb->page) == 0 && defined('REFERRER_ID') && REFERRER_ID > 0) {
+        global $database;
+        $sql = 'SELECT * FROM `'.TABLE_PREFIX.'pages` WHERE `page_id` = '.REFERRER_ID.'';
+        $result = $database->query($sql);
+        if ($result->numRows() == 1) {
+            $wb->page = $result->fetchRow();
+        }
+        unset($result);
+    }
+    
+    // fix up the menu number to default to the menu number
+    // of the current page if no menu has been supplied
+    if ($aMenu == 0) {
+        $aMenu = $wb->page['menu'] == '' ? 1 : $wb->page['menu'];
+    } 
+
+    // Set some of the $wb->page[] settings to defaults if not set
+    $pageLevel  = $wb->page['level']  == '' ? 0 : $wb->page['level'];
+    $pageParent = $wb->page['parent'] == '' ? 0 : $wb->page['parent'];
+    
+    // adjust the start level and start page ID as necessary to
+    // handle the special values that can be passed in as $aStart
+    $aStartLevel = 0;
+    if ($aStart < SM2_ROOT) {   // SM2_CURR+N
+        if ($aStart == SM2_CURR) {
+            $aStartLevel = $pageLevel;
+            $aStart = $pageParent;
+        }
+        else {
+            $aStartLevel = $pageLevel + $aStart - SM2_CURR;
+            $aStart = $CURR_PAGE_ID; 
+        }
+    }
+    elseif ($aStart < 0) {   // SM2_ROOT+N
+        $aStartLevel = $aStart - SM2_ROOT;
+        $aStart = 0;
+    }
+
+    // we get the menu data once and store it in a global variable. This allows 
+    // multiple calls to show_menu2 in a single page with only a single call to 
+    // the database. If this variable exists, then we have already retrieved all
+    // of the information and processed it, so we don't need to do it again.
+    if (($flags & SM2_NOCACHE) != 0
+        || !array_key_exists('show_menu2_data', $GLOBALS)
+        || !array_key_exists($aMenu, $GLOBALS['show_menu2_data'])) 
+    {
+        global $database;
+
+        // create an array of all parents of the current page. As the page_trail
+        // doesn't include the theoretical root element 0, we add it ourselves.
+        $rgCurrParents = explode(",", '0,'.$wb->page['page_trail']);
+        array_pop($rgCurrParents); // remove the current page
+        $rgParent = array();
+
+        // if the caller wants all menus gathered together (e.g. for a sitemap)
+        // then we don't limit our SQL query
+        $menuLimitSql = ' AND `menu`='.$aMenu;
+        if ($aMenu == SM2_ALLMENU) {
+            $menuLimitSql = '';
+        }
+
+        // we only load the description and keywords if we have been told to,
+        // this cuts the memory load for pages that don't use them. Note that if
+        // we haven't been told to load these fields the *FIRST TIME* show_menu2
+        // is called (i.e. where the database is loaded) then the info won't
+        // exist anyhow.
+        $fields  = '`parent`,`page_id`,`menu_title`,`page_title`,`link`,`target`,';
+		$fields .= '`level`,`visibility`,`viewing_groups`';
+        if (version_compare(WB_VERSION, '2.7', '>=')) { // WB 2.7+
+            $fields .= ',`viewing_users`';
+        }
+		if(version_compare(WB_VERSION, '2.9.0', '>=')) {
+            $fields .= ',`menu_icon_0`,`menu_icon_1`,`page_icon`';
+		}
+        if ($flags & SM2_ALLINFO) {
+            $fields = '*';
+        }
+
+        // we request all matching rows from the database for the menu that we
+        // are about to create it is cheaper for us to get everything we need
+        // from the database once and create the menu from memory then make 
+        // multiple calls to the database. 
+        $sql  = 'SELECT '.$fields.' FROM `'.TABLE_PREFIX.'pages` ';
+		$sql .= 'WHERE '.$wb->extra_where_sql.' '.$menuLimitSql.' ';
+		$sql .= 'ORDER BY `level` ASC, `position` ASC';
+        $sql = str_replace('hidden', 'IGNOREME', $sql); // we want the hidden pages
+        $oRowset = $database->query($sql);
+        if (is_object($oRowset) && $oRowset->numRows() > 0) {
+            // create an in memory array of the database data based on the item's parent. 
+            // The array stores all elements in the correct display order.
+            while ($page = $oRowset->fetchRow()) {
+                // ignore all pages that the current user is not permitted to view
+                if(version_compare(WB_VERSION, '2.7', '>=')) { // WB >= 2.7
+                    // 1. hidden pages aren't shown unless they are on the current page
+                    if ($page['visibility'] == 'hidden') {
+                        $page['sm2_hide'] = true;
+                    }
+                    
+                    // 2. all pages with no active sections (unless it is the top page) are ignored
+                    else if (!$wb->page_is_active($page) && $page['link'] != $wb->default_link && !INTRO_PAGE) {
+                        continue;
+                    }
+
+                    // 3. all pages not visible to this user (unless always visible to registered users) are ignored
+                    else if (!$wb->page_is_visible($page) && $page['visibility'] != 'registered') {
+                        continue;
+                    }
+                }
+
+                // ensure that we have an array entry in the table to add this to
+                $idx = $page['parent'];
+                if (!array_key_exists($idx, $rgParent)) {
+                    $rgParent[$idx] = array();
+                }
+
+                // mark our current page as being on the current path
+                if ($page['page_id'] == $CURR_PAGE_ID) {
+                    $page['sm2_is_curr'] = true;
+                    $page['sm2_on_curr_path'] = true;
+                    if ($flags & SM2_SHOWHIDDEN) 
+					{ 
+                        // show hidden pages if active and SHOWHIDDEN flag supplied
+                        unset($page['sm2_hide']); 
+                    }
+                }
+
+                // mark parents of the current page as such
+                if (in_array($page['page_id'], $rgCurrParents)) {
+                    $page['sm2_is_parent'] = true;
+                    $page['sm2_on_curr_path'] = true;
+                    if ($flags & SM2_SHOWHIDDEN) 
+					{
+                        // show hidden pages if active and SHOWHIDDEN flag supplied
+						unset($page['sm2_hide']); // don't hide a parent page                
+                    }
+                }
+                
+                // add the entry to the array                
+                $rgParent[$idx][] = $page;
+            }
+        }    
+        unset($oRowset);
+
+        // mark all elements that are siblings of any element on the current path
+        foreach ($rgCurrParents as $x) {
+            if (array_key_exists($x, $rgParent)) {
+                foreach (array_keys($rgParent[$x]) as $y) {
+                    $mark =& $rgParent[$x][$y];
+                    $mark['sm2_path_sibling'] = true;
+                    unset($mark);
+                }
+            }
+        }
+
+        // mark all elements that have children and are siblings of the current page
+        $parentId = $pageParent;
+        foreach (array_keys($rgParent) as $x) {
+            $childSet =& $rgParent[$x];
+            foreach (array_keys($childSet) as $y) {
+                $mark =& $childSet[$y];
+                if (array_key_exists($mark['page_id'], $rgParent)) {
+                    $mark['sm2_has_child'] = true;
+                }
+                if ($mark['parent'] == $parentId && $mark['page_id'] != $CURR_PAGE_ID) {
+                    $mark['sm2_is_sibling'] = true;
+                }
+                unset($mark);
+            }
+            unset($childSet);
+        }
+        
+        // mark all children of the current page. We don't do this when 
+        // $CURR_PAGE_ID is 0, as 0 is the parent of everything. 
+        // $CURR_PAGE_ID == 0 occurs on special pages like search results
+        // when no referrer is available.s
+        if ($CURR_PAGE_ID != 0) {
+            sm2_mark_children($rgParent, $CURR_PAGE_ID, 1);
+        }
+        
+        // store the complete processed menu data as a global. We don't 
+        // need to read this from the database anymore regardless of how 
+        // many menus are displayed on the same page.
+        if (!array_key_exists('show_menu2_data', $GLOBALS)) {
+            $GLOBALS['show_menu2_data'] = array();
+        }
+        $GLOBALS['show_menu2_data'][$aMenu] =& $rgParent;
+        unset($rgParent);
+    }
+
+    // adjust $aMaxLevel to the level number of the final level that 
+    // will be displayed. That is, we display all levels <= aMaxLevel.
+    if ($aMaxLevel == SM2_ALL) {
+        $aMaxLevel = 1000;
+    }
+    elseif ($aMaxLevel < 0) {   // SM2_CURR+N
+        $aMaxLevel += $pageLevel - SM2_CURR;
+    }
+    elseif ($aMaxLevel >= SM2_MAX) { // SM2_MAX+N
+        $aMaxLevel += $aStartLevel - SM2_MAX;
+        if ($aMaxLevel > $pageLevel) {
+            $aMaxLevel = $pageLevel;
+        }
+    }
+    else {  // SM2_START+N
+        $aMaxLevel += $aStartLevel - SM2_START;
+    }
+
+    // generate the menu
+    $retval = false;
+    if (array_key_exists($aStart, $GLOBALS['show_menu2_data'][$aMenu])) {
+        $formatter = $aItemOpen;
+        if (!is_object($aItemOpen)) {
+            static $sm2formatter;
+            if (!isset($sm2formatter)) {
+                $sm2formatter = new SM2_Formatter;
+            }
+            $formatter = $sm2formatter;
+            $formatter->set($flags, $aItemOpen, $aItemClose, 
+                $aMenuOpen, $aMenuClose, $aTopItemOpen, $aTopMenuOpen);
+        }
+        
+        // adjust the level until we show everything and ignore the SM2_TRIM flag.
+        // Usually this will be less than the start level to disable it.
+        $showAllLevel = $aStartLevel - 1;
+        if (isset($aOptions['notrim'])) {
+            $showAllLevel = $aStartLevel + $aOptions['notrim'];
+        }
+        
+        // display the menu
+        $formatter->initialize();
+        sm2_recurse(
+            $GLOBALS['show_menu2_data'][$aMenu],
+            $aStart,    // parent id to start displaying sub-menus
+            $aStartLevel, $showAllLevel, $aMaxLevel, $flags, 
+            $formatter);
+        $formatter->finalize();
+        
+        // if we are returning something, get the data
+        if (($flags & SM2_BUFFER) != 0) {
+            $retval = $formatter->getOutput();
+        }
+    }
+
+    // clear the data if we aren't caching it
+    if (($flags & SM2_NOCACHE) != 0) {
+        unset($GLOBALS['show_menu2_data'][$aMenu]);
+    }
+    
+    return $retval;
+}
+
+function sm2_mark_children(&$rgParent, $aStart, $aChildLevel)
+{
+    if (array_key_exists($aStart, $rgParent)) {
+        foreach (array_keys($rgParent[$aStart]) as $y) {
+            $mark =& $rgParent[$aStart][$y];
+            $mark['sm2_child_level'] = $aChildLevel;
+            $mark['sm2_on_curr_path'] = true;
+            sm2_mark_children($rgParent, $mark['page_id'], $aChildLevel+1);
+        }
+    }
+}
+
+function sm2_recurse(
+    &$rgParent, $aStart, 
+    $aStartLevel, $aShowAllLevel, $aMaxLevel, $aFlags, 
+    &$aFormatter
+    )
+{
+    global $wb;
+
+    // on entry to this function we know that there are entries for this 
+    // parent and all entries for that parent are being displayed. We also 
+    // need to check if any of the children need to be displayed too.
+    $isListOpen = false;
+    $currentLevel = $wb->page['level'] == '' ? 0 : $wb->page['level'];
+
+    // get the number of siblings skipping the hidden pages so we can pass 
+    // this in and check if the item is first or last
+    $sibCount = 0;
+    foreach ($rgParent[$aStart] as $page) {
+        if (!array_key_exists('sm2_hide', $page)) $sibCount++;
+    }
+    
+    $currSib = 0;
+    foreach ($rgParent[$aStart] as $page) {
+        // skip all hidden pages 
+        if (array_key_exists('sm2_hide', $page)) { // not set if false, so existence = true
+            continue;
+        }
+        
+        $currSib++;
+
+        // skip any elements that are lower than the maximum level
+        $pageLevel = $page['level'];
+        if ($pageLevel > $aMaxLevel) {
+            continue;
+        }
+        
+        // this affects ONLY the top level
+        if ($aStart == 0 && ($aFlags & SM2_CURRTREE)) {
+            if (!array_key_exists('sm2_on_curr_path', $page)) { // not set if false, so existence = true
+                continue;
+            }
+            $sibCount = 1;
+        }
+        
+        // trim the tree as appropriate
+        if ($aFlags & SM2_SIBLING) {
+            // parents, and siblings and children of current only
+            if (!array_key_exists('sm2_on_curr_path', $page)      // not set if false, so existence = true
+                && !array_key_exists('sm2_is_sibling', $page)     // not set if false, so existence = true
+                && !array_key_exists('sm2_child_level', $page)) { // not set if false, so existence = true
+                continue;
+            }
+        }
+        else if ($aFlags & SM2_TRIM) {
+            // parents and siblings of parents
+            if ($pageLevel > $aShowAllLevel  // permit all levels to be shown
+                && !array_key_exists('sm2_on_curr_path', $page)    // not set if false, so existence = true
+                && !array_key_exists('sm2_path_sibling', $page)) {  // not set if false, so existence = true
+                continue;
+            }
+        }
+        elseif ($aFlags & SM2_CRUMB) {
+            // parents only
+            if (!array_key_exists('sm2_on_curr_path', $page)    // not set if false, so existence = true
+                || array_key_exists('sm2_child_level', $page)) {  // not set if false, so existence = true
+                continue;
+            }
+        }
+
+        // depth first traverse
+        $nextParent = $page['page_id'];
+
+        // display the current element if we have reached the start level
+        if ($pageLevel >= $aStartLevel) {
+            // massage the link into the correct form
+            if(!INTRO_PAGE && $page['link'] == $wb->default_link) {
+                $url = WB_URL;
+            }
+            else {
+                $url = $wb->page_link($page['link']);
+            }
+                    
+            // we open the list only when we absolutely need to
+            if (!$isListOpen) {
+                $aFormatter->startList($page, $url);
+                $isListOpen = true;
+            }
+
+            $aFormatter->startItem($page, $url, $currSib, $sibCount);
+        }
+        
+        // display children as appropriate
+        if ($pageLevel + 1 <= $aMaxLevel 
+            && array_key_exists('sm2_has_child', $page)) {  // not set if false, so existence = true
+            sm2_recurse(
+                $rgParent, $nextParent, // parent id to start displaying sub-menus
+                $aStartLevel, $aShowAllLevel, $aMaxLevel, $aFlags, 
+                $aFormatter);
+        }
+        
+        // close the current element if appropriate
+        if ($pageLevel >= $aStartLevel) {
+            $aFormatter->finishItem($pageLevel, $page);
+        }
+    }
+
+    // close the list if we opened one
+    if ($isListOpen) {
+        $aFormatter->finishList();
+    }
+}
+
+?>
