in der Regel wird das beim Beispiel-Mandanten mitgelieferte Modul navigation_main für die Generierung der Hauptnavigation verwendet. Da ist an sich nichts dran auszusetzen, allerdings führt jeder Klick zu einem Seitenaufruf des angeklickten Navigationspunktes. In mobilen Ansichten ist das Ganze aber oftmals unkomfortabel - insbesondere wenn man zu einem Navigationspunkt eines tieferen Levels gelangen möchten. Um in Level 3 zu gelangen, muss bei der navigation_main also auch 3 Mal eine Seite geladen werden:
Level 1 -> Level 2 -> Level 3
Ein direkter Zugriff auf Level 3 ohne Zwischenseiten ist also nicht möglich und genau hier setzt mein Modul navigation_main_dropdown_sd an. Es fügt jedem Navigationspunkt mit Unterpunkten zusätzlich zum Link eine Schaltfläche (im Code unten je nach Zustand ein + oder -) hinzu mit der die Unterpunkte auf- und zugeklappt werden können. So lässt sich der Baum
Level 1 - Level 2
erst einmal aufklappen um dann erst auf Level 3 zu klicken.
Das Ganze basiert auf der Datenbanktabelle con_cat_tree und ist im Grunde eine Sitemap die entsprechend aufbereitet wird. Dabei gibt es drei Mandanteneinstellungen zu berücksichtigen:
Code: Alles auswählen
nmd_sd_show_level_0_cats | true_or_false | true
Code: Alles auswählen
nmd_sd_cat_branches_to_exclude | idcats | 1,2,3
Code: Alles auswählen
nmd_sd_cat_new_window | idcats | 1,2,3
Die navigation_main_dropdown_sd berücksichtigt natürlich ob eine Kategorie on- oder offline ist und stellt nur online-Kategorien dar. Zusätzlich werden geschützte Kategorien nur den Frontend-Usern angezeigt, die eingelogged sind und der passenden Gruppe angehören.
Das Ein- und Ausblenden der (Unter-)Kategoriegruppen erfolgt per JavaScript. Damit die Navigation auch ohne aktiviertem JavaScript funktioniert, werden erst einmal alle Kategorien (die nicht mit den Mandanteneinstellungen ausgeschlossen wurden) initial angezeigt und dann alle Gruppen per JS ausgeblendet, die nicht im aktuellen Kategoriepfad des gerade aufgerufenen Webartikels liegen. Ist JS deaktiviert, wird die Navigation also zur Sitemap und bleibt nutzbar.
Was ist zu tun?
1) Modul navigation_main_dropdown_sd anlegen mit
Modul-Ausgabe
Code: Alles auswählen
<?php
/***********************************************
* CONTENIDO MODUL - OUTPUT
*
* Modulname : navigation_main_dropdown_sd
* Author(s) : Seamless-Design Markus Hübner
* Copyright : Markus Hübner
* Created : 09/2019
* Modified : 2019-09-16: Added a delay for hovering icon to unfold/fold subcategories
* : 2019-11-15: Added onfoucusin and onfocusout JS events to improve usability of navigation for keyboard usage
* : 2020-02-28: fixed AMR issues generating URLs from idcats, using idart instead
************************************************/
// assert framework initialization
defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
/* general configuration begin */
//client settings begin
$show_level_0=getEffectiveSetting('nmd_sd_show_level_0_cats', 'true_or_false', 'true'); // true or false - if false, the root of every category tree will not be shown
$nmd_sd_cat_branches_to_exclude = getEffectiveSetting('nmd_sd_cat_branches_to_exclude', 'idcats', '23,24,25');
$nmd_sd_cat_new_window = getEffectiveSetting('nmd_sd_cat_new_window', 'idcats', '23,24,25');
$arr_idcats_to_exclude_from_nav=explode(",",$nmd_sd_cat_branches_to_exclude); //entries: comma separated idcats of branch starts, will be completed with other idcats within those branches
$arr_idcats_to_open_in_new_window=explode(",",$nmd_sd_cat_new_window);
//client settings end
$symbol_unfold="+"; // needs to be changed within js-file too, if you want to alter it
$symbol_fold="-";
$title_symbol_fold_unfold=mi18n("fold unfold");
/* general configuration end */
/* category branches to exclude begin */
$arr_idcats_to_exclude_from_nav_complete_branches=array();
$exclude="false";
$query = "SELECT * FROM con_cat_tree ORDER BY idtree";
$result = cRegistry::getDb();
$result->query($query);
while($result->nextRecord())
{
$arr=$result->toArray();
if($level_branch_start>=$arr['level']) $exclude="false";
if(in_array($arr['idcat'],$arr_idcats_to_exclude_from_nav))
{
$level_branch_start=$arr['level'];
$exclude="true";
}
if($exclude=="true") $arr_idcats_to_exclude_from_nav_complete_branches[]=$arr['idcat'];
}
$arr_idcats_to_exclude_from_nav=$arr_idcats_to_exclude_from_nav_complete_branches;
/* category branches to exclude end */
/* locked categories begin */
$id_feu=$auth->auth["uid"];
$arr_visitor_fe_group_allowed_cat_ids=array();
if($id_feu!="nobody")
{
//echo '$id_feu: '.$id_feu.'<br/>';
/*
if you can log in but are logged out if you click on any cat, session handling does not work properly
have a look at https://forum.contenido.org/viewtopic.php?f=98&t=36725#p169105 where the solution is
to exchange in file class.session.php in line 90:
originial: session_set_cookie_params(0, $path);
with
new: session_set_cookie_params(0, '/');
*/
$query = "SELECT idfrontendgroup FROM con_frontendgroupmembers WHERE idfrontenduser='$id_feu'";
$result = cRegistry::getDb();
$result->query($query);
while($result->nextRecord())
{
$arr_fe_groups=$result->toArray();
}
$visitor_fe_group=$arr_fe_groups['idfrontendgroup'];
$query = "SELECT item FROM con_frontendpermissions WHERE idfrontendgroup='$visitor_fe_group'";
$result = cRegistry::getDb();
$result->query($query);
while($result->nextRecord())
{
$arr_result=$result->toArray();
$arr_visitor_fe_group_allowed_cat_ids[]=$arr_result[item];
}
}
/* locked categories end */
/* build navigation category tree begin */
$arr_category_tree=array();
$cat_tree_entry=1;
$query = "SELECT * FROM con_cat_tree ORDER BY idtree";
$result = cRegistry::getDb();
$result->query($query);
while($result->nextRecord())
{
$arr=$result->toArray();
if(!in_array($arr['idcat'],$arr_idcats_to_exclude_from_nav))
{
$query2 = "SELECT * FROM con_cat_lang WHERE idcat='$arr[idcat]' AND idlang='$lang'";
$result2 = cRegistry::getDb();
$result2->query($query2);
while($result2->nextRecord())
{
$arr2=$result2->toArray();
}
$cat_can_be_shown="false"; // will be set to true if category is online and not for logged in users only. if category is locked, there will be a check if user is logged in and allowed to view category
if($arr2['visible']=="1" AND $arr2['public']=="1") $cat_can_be_shown="true";
if($arr2['visible']=="1" AND $arr2['public']=="0")
{
if(in_array('__GLOBAL__',$arr_visitor_fe_group_allowed_cat_ids)) $cat_can_be_shown="true";
}
if($cat_can_be_shown=="true")
{
$arr_category_tree[]=array($arr['idcat'],$arr['level'],$arr2['name']);
$arr_category_tree_idcats_only[]=$arr['idcat'];
}
}
}
/* build navigation category tree end */
/* rendering navigation begin */
$current_level="";
$pre_level="";
$id_number=0;
$current_category_tree_item=1;
$arr_blocks_to_collapse_initially=array();
$arr_category_tree_idcats_and_nav_block_ids=array();
echo '<div class="nav_main_dropdown_box">';
foreach($arr_category_tree AS $arr_idcat)
{
$current_level=$arr_idcat[1];
if($pre_level=="" OR $pre_level<$current_level)
{
echo '<ul id="nav_block_id_'.$id_number.'" class="nav_level_'.$current_level.'">';
echo '<li';
if($current_level==0 AND $show_level_0=="false") echo ' class="hide_li" ';
echo '>';
if($current_level>1) $arr_blocks_to_collapse_initially[]=$id_number;
$id_number++;
}
if($pre_level==$current_level)
{
echo '<li';
if($current_level==0 AND $show_level_0=="false") echo ' class="hide_li" ';
echo '>';
}
if($pre_level>$current_level)
{
$i=0;
$level_diff=$pre_level-$current_level;
while($i<$level_diff)
{
echo '</ul>';
$i++;
}
echo '<li';
if($current_level==0 AND $show_level_0=="false") echo ' class="hide_li" ';
echo '>';
}
$next_level=$arr_category_tree[$current_category_tree_item][1];
$current_category_tree_item++;
/* AMR has problems with generating URLs from some idcats. this part here tries to fix that with defining front_content-URL with start idarts instead */
/* extracting start idart begin */
$query3 = "SELECT startidartlang FROM con_cat_lang WHERE idcat='$arr_idcat[0]' AND idlang='$lang'";
$result3 = cRegistry::getDb();
$result3->query($query3);
while($result3->nextRecord())
{
$arr3=$result3->toArray();
}
$start_idart_from_current_idcat=$arr3['startidartlang'];
/* extracting start idart end */
echo '<a ';
if($idcat==$arr_idcat[0]) echo 'class="active" ';
echo 'href="front_content.php?idart='.$start_idart_from_current_idcat.'" title="'.$arr_idcat[2].'"';
if(in_array($arr_idcat[0],$arr_idcats_to_open_in_new_window)) echo ' target="_blank" ';
if($next_level>$current_level AND $current_level>0)
{
echo ' onmouseover="javascript: onmouseoverdelay(\''.$id_number.'\');" onmouseout="javascript: myStopFunction();" onfocusin="javascript: onmouseoverdelay(\''.$id_number.'\');" onfocusout="javascript: myStopFunction();"';
}
echo '>'.$arr_idcat[2].'</a>';
if($next_level>$current_level AND $current_level>0)
{
echo ' <span title="'.$title_symbol_fold_unfold.'" class="open_close_next_level" onclick="javascript: open_close_next_level(\''.$id_number.'\');" onmouseover="javascript: onmouseoverdelay(\''.$id_number.'\');" onmouseout="javascript: myStopFunction();" id="open_close_'.$id_number.'">'.$symbol_fold.'</span></li>';
$arr_category_tree_idcats_and_nav_block_ids[$arr_idcat[0]]=$id_number;
}
else echo '</li>';
$pre_level=$current_level;
}
echo '</ul>';
echo '</div>';
/* rendering navigation end */
/* collecting parentids for current idcat begin */
function get_parentid($current_idcat)
{
$query = "SELECT parentid FROM con_cat WHERE idcat='$current_idcat'";
$result = cRegistry::getDb();
$result->query($query);
while($result->nextRecord())
{
$arr=$result->toArray();
}
return $arr['parentid'];
}
$parentid_item="";
$idcat_to_check=$idcat;
$arr_parentid_collection=array();
while($parentid_item!="0")
{
$parentid_item=get_parentid($idcat_to_check);
$idcat_to_check=$parentid_item;
if($parentid_item!="0") $arr_parentid_collection[]=$parentid_item;
}
// building array of nav_block_ids to be unfolded begin
$arr_nav_block_ids_to_unfold=array();
foreach($arr_parentid_collection AS $element)
{
$arr_nav_block_ids_to_unfold[]=$arr_category_tree_idcats_and_nav_block_ids[$element];
}
array_pop($arr_nav_block_ids_to_unfold);
// building array of nav_block_ids to be unfolded end
/* collecting parentids for current idcat end */
$arr_blocks_to_collapse_initially=array_diff($arr_blocks_to_collapse_initially, $arr_nav_block_ids_to_unfold); // erases blocks, which would be unfolded afterwards from array with blocks which are collapsed initially. instead of close and open, they stay opened
?>
<script>
/* collapsing categories with subcategories initially begin */
var array_blocks_to_collapse_initially = [<?php echo '"'.implode('","',$arr_blocks_to_collapse_initially).'"' ?>];
array_blocks_to_collapse_initially.forEach(function(entry) {
document.getElementById('nav_block_id_'+entry).style.maxHeight=0+'px';
document.getElementById('nav_block_id_'+entry).style.overflow='hidden';
document.getElementById('open_close_'+entry).innerHTML='<?php echo $symbol_unfold; ?>';
});
/* collapsing categories with subcatgories initially end */
</script>
Code: Alles auswählen
div.nav_main_dropdown_box a {
text-decoration: none;
color: #000000;
font-size: 2em;
transition: 0.5s;
}
div.nav_main_dropdown_box a:hover,
div.nav_main_dropdown_box a:focus,
div.nav_main_dropdown_box a.active {
color: #ff0000;
transition: 0.5s;
}
div.nav_main_dropdown_box ul {
list-style-type: none;
padding-left: 0em;
}
ul.nav_level_0 {
margin-left: 0em;
list-style-type: none;
}
ul.nav_level_1 {
margin-left: 0.5em;
}
ul.nav_level_2 {
margin-left: 1em;
}
ul.nav_level_3 {
margin-left: 1.5em;
}
ul.nav_level_4 {
margin-left: 2em;
}
li.hide_li {
display: none;
}
span.open_close_next_level {
cursor: pointer;
font-size: 1.5em;
padding-left: 0.1em;
width: 2em;
text-align: center;
cursor: pointer;
}
Code: Alles auswählen
var myVar;
function onmouseoverdelay(var_nav_block_id_number) {
myVar=setTimeout(function() {
open_close_next_level(var_nav_block_id_number);
}, 500);
}
function myStopFunction() {
clearTimeout(myVar);
}
function open_close_next_level(var_nav_block_id_number) {
myStopFunction();
var var_status_block=document.getElementById('nav_block_id_'+var_nav_block_id_number).style.maxHeight;
if(var_status_block=="0px")
{
document.getElementById('nav_block_id_'+var_nav_block_id_number).style.maxHeight=1000+'px';
document.getElementById('nav_block_id_'+var_nav_block_id_number).style.transition=1.5+'s';
document.getElementById('open_close_'+var_nav_block_id_number).innerHTML='-';
}
else
{
document.getElementById('nav_block_id_'+var_nav_block_id_number).style.maxHeight=0+'px';
document.getElementById('nav_block_id_'+var_nav_block_id_number).style.overflow='hidden';
document.getElementById('nav_block_id_'+var_nav_block_id_number).style.transition=0.5+'s';
document.getElementById('open_close_'+var_nav_block_id_number).innerHTML='+';
}
}
2) Mandanteneinstellungen eintragen
Code: Alles auswählen
nmd_sd_show_level_0_cats | true_or_false | true
nmd_sd_cat_branches_to_exclude | idcats | 1,2,3
nmd_sd_cat_new_window | idcats | 1,2,3
Wer sich das Ganze in Aktion anschauen möchte: https://www.sankt-martin-metzkausen.de
Grüße und viel Spaß mit dem Modul

Markus
Edit 28.02.2020: Die Links in den Navigationspunkten wurden bisher nur über die jeweilige idcat der Kategorien erzeugt. Advanced Mod Rewrite hatte jedoch - die Ursache konnte ich nicht herausfinden - bei der einen oder anderen Kategorie damit Probleme und erzeugte lediglich ein "/". Jetzt wird auf die idart des Startartikels in der jeweiligen Kategorie verlinkt und das Umschreiben klappt fehlerlos.
Edit 15.11.2019: Onfocusin und onfocusout-JS-Events eingefügt um die Usability der Navigation bei Verwendung mit Tastatur zu erhöhen. Die CSS-Klassen wurden auch entsprechend ergänzt.
EDIT 16.09.2019: Delay beim Mouseover des Icons zum Ein- und Ausklappen eingefügt. Dann werden die Unternavigationspunkte nicht beim unbeabsichtigen "Streifen" des Icons aus- oder eingeklappt.