<?php
if (!defined('PmWiki')) exit() ;


/****************************************************************** 
	parseMenu.php
	version 2022-12-29

    A Wiki-Page Menu Building Recipe for PmWiki skins

    Written for PmWiki in 2022 by Kirk Siqveland - www.SnippetsPub.com


	  	Copyright 2022 Kirk Siqveland - Edmonds, WA USA
	    Kirk@SnippetsPub.com  www.SnippetsPub.com   

    This recipe (software) is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

*******************************************************************/

##	FEATURES:
# 	- Uses editable Wiki Pages to build Navigation Menus
#		- Self-Compiles menu html code from wiki pages
#		-- Pages can be decorated without changing the Menus
#		-- allowing the page itself to be used for navigation.
#		- Hides secondary level Menus
#		- Navigation Wiki Pages May be used for Responsive design
#		- - when building the menus Markup ignores non-menu text.
#		- One page Works for both Horizontal and Vertical Menus.
#		- - layout is all in the CSS (see included code)
#		- Allows Splicing of Site and Group Navigation Pages

##  This file requires CSS files to establish function
##  and to provide the decorative style to match your skin

##  The Responsive parseMenu project requires three files:
##  #  parseMenu.php  (this file)
##  #  navbar_function.css
##  #  navbar_style.css.php  (CSS using PHP for Variables)
## 
##  For instructions see the included HowTo.txt or the 
##  www.pmwiki.org/wiki/Cookbook/ResponsiveMenus page

##
##	This recipe allows a PmWiki Skin to easily be modified to use
##  Menus built from particular wiki pages i.e. {Group}.{Page}
##
##  Like other functions in PmWiki, you may specify a Group Specific
##  Menu, or if that page does not exist, a default Site-Wide Menu
##  will be used.
   


/******************************************************************
												H O W   T O :

 Modify your Skin template, inserting a new div where you want the
 menu, setting  -  class="NavMenu"  -
 then add Code inside the <div> to use this MarkUp including
 at least one wiki-page address, the second is used in case the
 first wiki-page doesn't exist.

 * Example CODE:
      <div class="NavMenu">  
        <!--markup:(:parseMenu $Group.NavBar $SiteGroup.NavBar :)-->
      </div>    
*****************************************************************/ 


	function parseMenu($args){ 
	global $SiteGroup ;
	$fluff = true ;
	## Example Navigation page entry:

  // * [[$SiteGroup/NavBar?GroupNav={$Group}/GroupNav | Nav Menu ]]

	#- The Asterix flags it as a visible menu item w/ level one
	#- Normal pmwiki markup makes it a link named "Nav Menu".
	#- the link passes the $_GET var "GroupNav" with a second
	#- page address to be appended to the first when building
	#- this menu. Here the "{$Group}" Markup-Variable looks for
	#- the "GroupNav" page in whatever Group you are currently in.
	#- If we can't find that, we use /$SiteGroup/GroupNav instead.

		// $uri   = explode("/",$_SERVER['REQUEST_URI']) ;
		// $Group = $uri[1] ;

		// $pagename=$GLOBALS['MarkupToHTML']['pagename'];
		// $group = PageVar($pagename, '$Group');


		## Split the provided args so we can extract each/any
			$ArgsArr  = explode(" ", $args[1])   ;
			## Sanitize:
			$WikiPage = strtok($ArgsArr[0], "?") ; 		

			if(!PageExists($WikiPage)){       //look for Group Page
				$WikiPage  = strtok($ArgsArr[1], "?") ; // Sanitize
			}
			$arrayPage = ReadPage($WikiPage) ;

		## Allow bypass of Menu Builder using Markup -- (:Splash ...  :) 
		## to display an image instead of a menu
			$Splash = substr(trim($arrayPage['text']), 0,8) ;		
			if( $Splash === '(:Splash' || $Splash === '(:splash'){
					$trimString = substr(trim($arrayPage['text']), 9) ;
					return rtrim( $trimString, ":)") ;
			}else{
			 	## Otherwise we break down the page line by line and look for menu items.				
				## Split the line into an array using New-Line as the delimiter		
					$pullText  = str_replace("\r", "", $arrayPage['text']) ;//drop Chr(13)
					$LineItems = explode("\n", $pullText) ;

					## Mark the end position with a dummy marker:
						array_push($LineItems,"@ EOA");			

						
					## Start Building our Menu structure:
						$FullBar = "<ul class='menu'><li>" ;

					## Now we handle each array item to find its Menu Level:
						foreach($LineItems as $LI){

							## Allow Decoration Text etc. before and after our Menu
							if(stripos($LI, ":Menu:")!== false) {$fluff = false ; }
							if($fluff) continue ;		
							if(stripos($LI, ":MenuEnd:")!== false) break ; 


							## Skip Comment or Markup Lines while building the Menu
								$firstChar = substr($LI, 1,1);
								if ( $firstChar === '!'||
									   $firstChar === '('||
									   $firstChar === '%'){
									continue;
								}

								## Skip Markup line but with special handling
								if ( $firstChar === ':'){
									if(strpos($LI, ':include') !== false){
									if(strpos($LI, '{$Group}') !== false){
										preg_match('/\\(:include (.*?):\\)/', $LI, $matches);
										$testDir = str_replace("{\$Group}", "$Group", $matches[1]) ;
										if(!PageExists($testDir)){ $Group = "$SiteGroup" ; }
									}
									}
									continue;
								}

								## Peel off the List Level Markup e.g. "** "  for second level List Items
								## This requires the use of a space between the Asterisks and the menu Item.
										$exLI = explode(" ",trim($LI)) ;				
									if(count($exLI) > 1){

										$liLevel = $exLI[0] ;

										## Now remove the Markup and put the rest back together to get the Menu Item
											$liTag 	 = implode(" ", array_slice($exLI,1)) ;
											## insert a horizontal rule if indicated with "----"
										  if(trim($liTag)==="----"){ $liTag = '<hr class="hrli"/>' ; }
										  if(trim($liTag)==="____"){ $liTag = '<div class="spacer"></div>' ; }
										  if(trim($liTag)==="(:hr:)"){ $liTag = '<hr class="hrli"/>' ; }
										  if(trim($liTag)==="(:spacer:)"){ $liTag = '<div class="spacer"></div>' ; }								  

										##---------------------------------------------------------------
											## Replace the Variable '{$Group}' with the actual Group Name.
											## If that Page Doesn't exist, replace '{$Group}' with "Site"
												if(strpos($LI, '{$Group}') !== false){
													preg_match('/{\$Group}(.*?) /', $LI, $matches);
													if(!PageExists("$Group$matches[1]")){
														$Group = "Site" ;
													}
													$liTag   = str_replace("{\$Group}", "$Group", $liTag) ;
												}
										##-------------------------------------------------------------
												
										## Define our DropLevel,  0 = top level Menu item
											$DropLI  = 0 ;

										## Don't process until we have read in the first and second items to compare.
										if(isset($prevLevel)){  
											## calculate the Menu level 
											#- For Simplicity This currently only works with One Drop-Level									

											## Start by identifying the level * = 1, ** = 2 
												$urCT = strlen(trim($prevLevel)) ;
												$liCT = strlen(trim($liLevel))   ;			

											## Parse the line and build the Menu String:
											## we are actually working with the previous list item
												if( $liTag === "EOA" ){
													while($DropLI > 0){ $FullBar .= "</ul></li>" ; }
													$FullBar   .= $urTag . "</li></ul>" ;
												}elseif( $liCT == $urCT ){					
													$FullBar   .= $urTag . "</li><li>" ;					
												}elseif( $liCT  > $urCT ){
													$FullBar   .= $urTag . "<ul class='Dropli'><li>" ;
													$DropLI++ ;
												}elseif( $liCT  < $urCT ){
													$FullBar   .= $urTag . "</li></ul>" ;
													while($DropLI > 0){ $FullBar .= "</li></ul>" ; }
													$FullBar   .= "<li>" ;
												}
										}	

										## Roll current item into the "Previous" position
										$urTag = $liTag ;

										## Roll current drop-level to the "Previous" level
										$prevLevel = $liLevel ;
									}
						} // for each

					return $FullBar;
				}
		} // MakeFlatMenu()

## the Markup itself:
  Markup(	'parseMenu', 
  				'inline', 
  				'/\\(:parseMenu(?s).(.*?):\\)/', 
  				"parseMenu" 
  );

## This hides the "Splash" markup which bypasses the Parse function.
## For example to insert a picture instead of a Menu for certain groups:
## the wiki page would use the Splash markup to bypass the Menu builder.
/*  (:Splash https://www.mydomain.org/pmwiki/media/welcome_image.png :)   */
  Markup(	'SplashMenu', 
  				'inline', 
  				'/\\(:Splash (.*?):\\)/', 
  				"$1" 
  );

## Menu Horizontal-Rule Markup:
  Markup(	'menuHR', 
  				'inline', 
  				'/\*(.*?)\\(:hr:\\)/', 
  				"<hr class='hrli'/>"
  ); 

## Menu Empty-line or "Spacer" Markup:
  Markup(	'menuSpacer', 
  				'inline', 
  				'/\*(.*?)\\(:spacer:\\)/', 
  				"" 
  );  

## By Using MenuStart and MenuEnd Markup
## We can have decorated pages which include the actual menu as well
  Markup(	'menuStart', 
  				'style', 
  				'/\\(:Menu:\\)/', 
  				"<div class='menublock'>" 
  );
  Markup(	'menuEnd', 
  				'style', 
  				'/\\(:MenuEnd:\\)/', 
  				"</div>" 
  );  



## The SpliceNav Markup allows the Splicing of Menu Pages so 
## you can have a Site Navigation Menu page and also have
## {Group} Navigation Pages, which can be combined.
## Using the (:SpliceNav:) Markup you can add/splice the 
## {Group} Navigation page to the bottom of the 
## Site Navigation page ( for Responsive Themes)

## NB!: This requires passing the spliced page link as part of the URL
## using a $_GET var
## e.g.: ?GroupNav=Group/Page   with the link address. 
## For example I have a {Group}/MiniNav page with one Link - /*
//		* [[Site/NavBar?GroupNav={$Group}/GroupNav | Nav Menu ]]
## This splices the current {Group}/GroupNav page onto Site/NavBar page

	function SpliceNav(){
		if(isset($_GET['GroupNav'])){
			if(PageExists($_GET['GroupNav'])){
				return "(:include ".$_GET['GroupNav']." :)" ;
			}else{
				$outLink = str_replace($Group, "Site", $_GET['GroupNav']) ;			
				if(PageExists($outLink)){ return "(:include $outLink:)" ;	}
			}
		}
	}
  Markup(	'SpliceNav', 
  				'fulltext', 
  				'/\\(:SpliceNav:\\)/', 
  				"SpliceNav" 
  );


## And finally menu-page markup to insert a menu horizontal rule:
## (applied late to only change list items)
Markup('lihrrule','style','/----/','<hr class="lihr" />');


/* CSS
Added to your skin, or to your pub/css/local.css

.hrli, .lihr {
  margin-left:      0px ;
  width:            80% ;
  max-width:      180px ;
  border:             0 ;
  height:             0 ;
  border-bottom: 1px solid ;  
}
.hrli { 
  margin-left:     40px ;}


  /*