Hauptnavigation mit Dropdown für Unterpunkte

Alles rund um Module und Plugins in CONTENIDO 4.10.
Antworten
McHubi
Beiträge: 1094
Registriert: Do 18. Nov 2004, 23:06
Wohnort: Mettmann
Kontaktdaten:

Hauptnavigation mit Dropdown für Unterpunkte

Beitrag von McHubi » Do 12. Sep 2019, 23:09

Hallo zusammen,

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
Per true werden die "Startpunkte" der Bäume angezeigt, per false nicht.

Code: Alles auswählen

nmd_sd_cat_branches_to_exclude | idcats | 1,2,3
Eine Komma-separierte Liste der idcats die - inklusive ihrer Unter-idcats - nicht angezeigt werden sollen. Das ist eine andere Herangehensweise als bei der navigation_main (bei der die idcats angegeben werden die dargestellt werden sollen) und bringt den Vorteil, dass Navigationspunkte innerhalb eines darzustellenden Baums nicht offline sein müssen um sie auszublenden. Je nachdem was man mit der Navigation vorhat, ist das sehr praktisch. Der Nachteil ist, dass ggf. ein paar mehr idcats hier eingetragen werden müssen - was aber in der Regel nicht die Welt ist.

Code: Alles auswählen

nmd_sd_cat_new_window | idcats | 1,2,3
Eine Komma-separierte Liste der idcats die in einem neuen Fenster geöffnet werden sollen. Bei der navigation_main läuft das auch etwas anders, hier sollte es eigentlich reichen, in den Mandanteneinstellungen articles | show-new-window-checkbox | true zu hinterlegen. Das Ganze funktioniert in der aktuellen 4.10.0 jedoch nicht und es muss zusätzlich die navigation_main mit der Lösung von homtata ergänzt werden (viewtopic.php?f=98&t=34903#p164641) damit die in den Artikeleigenschaften gesetzte Checkbox auch Wirkung zeigt. Soweit ich das sehen kann, benötigt diese Ergänzung jedoch die $categoryHelper, die jede Menge Infos in einem Monster-Array mit sich bringt, die man eigentlich gar nicht benötigt - zumindest nicht in diesem Modul. Da ich auf diesen Datenballast gerne verzichte, ist das Öffnen im neuen Fenster in die Mandanteneinstellungen ausgelagert. Wenn ich damit falsch liege, gerne her mit Infos...

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
************************************************/


// 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 '>';
    }
  echo '<a ';
  if($idcat==$arr_idcat[0]) echo 'class="active" ';
  echo 'href="front_content.php?idcat='.$arr_idcat[0].'" title="'.$arr_idcat[2].'"';
  if(in_array($arr_idcat[0],$arr_idcats_to_open_in_new_window)) echo ' target="_blank" ';
  echo '>'.$arr_idcat[2].'</a>';
  $next_level=$arr_category_tree[$current_category_tree_item][1];
  $current_category_tree_item++;

  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 type="text/javascript">
/* 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>
CSS

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.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;
}
JavaScript

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='+';
      }
  }
Das Symbol für Ein- und Ausklappen in der Modulausgabe und im JS ggf. anpassen. Die Verzögerung beim Hovern des Icons zum Ein- und Ausklappen von Unterpunkten kann im JavaScript angepasst werden. Hier einfach die gegebenen 500 Millisekunden in der function onmouseoverdelay verändern.

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
3) Modul in Vorlage einbinden.

Wer sich das Ganze in Aktion anschauen möchte: https://www.sankt-martin-metzkausen.de

Grüße und viel Spaß mit dem Modul :D

Markus

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.
Zuletzt geändert von McHubi am Mo 16. Sep 2019, 13:34, insgesamt 1-mal geändert.
seamless-design.de
"Geht nicht!" wohnt in der "Will nicht!"-Strasse.

(NEU!) Das Handbuch zur Version 4.10: CONTENIDO für Einsteiger (4.10)

Das Handbuch zur Version 4.9: CONTENIDO für Einsteiger (4.9)

McHubi
Beiträge: 1094
Registriert: Do 18. Nov 2004, 23:06
Wohnort: Mettmann
Kontaktdaten:

Re: Hauptnavigation mit Dropdown für Unterpunkte

Beitrag von McHubi » Mo 16. Sep 2019, 13:17

Delay beim Mouseover des Icons zum Ein- und Ausklappen eingefügt. Dann werden die Unternavigationspunkte nicht beim unbeabsichtigen "Streifen" des Icons aus- oder eingeklappt. Ergänzung ist - wie immer - im Eröffnungspost integriert, dabei wurde die Modul-Ausgabe und der Content des Reiters JavaScript ergänzt.
seamless-design.de
"Geht nicht!" wohnt in der "Will nicht!"-Strasse.

(NEU!) Das Handbuch zur Version 4.10: CONTENIDO für Einsteiger (4.10)

Das Handbuch zur Version 4.9: CONTENIDO für Einsteiger (4.9)

Antworten