dieses Modul zäumt das Thema "Accordion" mal von einer anderen Seite auf. Die Inhalte passen sich responsiv dem zur Verfügung stehenden Platz an und sind über das Backend flexibel sortierbar. Vom Grundprinzip her ist es mit einer zweistufigen FAQ vergleichbar. Es gibt eine übergeordnete Kopfnavigation mit den jeweiligen Themen, die beim Anklicken den darunter liegenden Fragen-/Themenbereich öffnen. Dort sind neben einem möglichen Einleitungstext Infoboxen hinterlegt, die sich entsprechend öffnen und schließen lassen. Die Anzahl der Themen und Fragen ist unbegrenzt, die Sortierung kann nach dem Sortierschlüssel oder Backend-Title der Webartikel erfolgen, in denen die Daten hinterlegt sind.
Im Frontend schaut das Ganze dann zum Beispiel bei vier Hauptthemen und ein paar Infoboxen so aus: INSTALLATION
1) Modul und Dateien
Als erstes das Modul anlegen und zwei Grafiken nach Wahl (oder die im nächsten Post verwenden) zum Öffnen/Schließen der Infoboxen (Dateiname fi_item_question_open.gif und fi_item_question_close.gif) nach upload/bullets hochladen. Wenn ein anderes Verzeichnis oder andere Dateien gewünscht sind, entsprechend die JS-Funktion fi_box_answer_show_hide sowie die CSS-Klasse div.fi_box_show_answer im Modulreiter CSS in punkto backgroundImage anpassen. Gleiches gilt für den Button button-arrow-up.png unterhalb des Infoboxenbereichs, der ein Hochspringen zur Hauptnavigation des Moduls ermöglicht. Wer hier etwas anpassen möchte, kann dies in der CSS-Klasse div.button_back_to_themes machen.
2) Informationsquelle schaffen
Die in den Infoboxen, Einleitungstexten und der "Kopfnavigation des Moduls" hinterlegten Texte und Bilder werden über Kategorien und Artikel gesteuert. Als erstes hierzu die Kategorien anlegen, passend zum Screenshot also:
Startseite
---Nähere Informationen
------Thema 1
------Thema 2
------Thema 3
------...
Der Name der Kategorie entspricht später dem Text, der unter den Bildern in der Kopfnavigation erscheint. Da "Thema 1 bis ..." nur ihres Namens wegen gebraucht werden und sonst lediglich Container für Informationsartikel sind, sollten sie offline geschaltet sein.
3) Vorlage für Artikel mit Informationen anlegen
Das Modul holt sich die für die Darstellung benötigten Infos aus den Standardmodulen content_image, content_header_first und content_text bzw. den dort hintelegten CMS-types CMS_IMGEDITOR[1], CMS_HTMLHEAD[1] und CMS_HTML[1] per cApiArticleLanguage. Insofern eine Vorlage mit diesen drei Modulen anlegen und darauf achten, dass die Nummerierung in den CMS-types stimmt. Anderenfalls muss die Modulausgabe angepasst werden.
4) Artikel anlegen
Alle Artikel in den Kategorien "Thema 1 bis ..." basieren auf der gerade angelegten Vorlage. Der Startartikel in der jeweiligen Kategorie muss jetzt zumindest mit dem Bild versorgt werden, dass in der Kopfnavigation des Moduls angezeigt werden soll. Die Überschrift und der Text des Artikels, der in der Ausgabereihenfolge zuerst dargestellt wird, bilden - wenn gewünscht - den Einleitungstext des Bereichs, der die Infoboxen beinhaltet. Alle weiteren Artikel benötigen lediglich die Headline und den Text. Innerhalb des Textes sind keine Grenzen gesetzt, hier können also auch Bilder und alle sonst üblichen Inhalte vorkommen. Beim Anlegen der Artikel - für die spätere Sortierung - auf den Backendtitle und/oder den Sortierschlüssel im Artikelreiter "Eigenschaften" achten.
5) Weitere Vorlage erstellen
...die das Modul "floating information" beinhaltet oder bestehende Vorlage ergänzen.
6) Artikel für die Anzeige der Moduls erstellen
Webartikel anlegen der auf der Vorlage basiert, die das Modul beinhaltet. Über den Artikelreiter "Konfiguration" gib es drei Stellschrauben um das Modul einzurichten:
Gewünschte Reihenfolge der idcats:
Hier einfach die idcats der Kategorien eintragen, die die Webartikel mit den Daten für die Infoboxen beinhalten. Hier also die idcats von "Thema 1 bis ...". Dabei die idcats mit einem # voneinander trennen. Die Reihenfolge der Eintragung bestimmt die Reihenfolge im Frontend.
Sortierung der Infoblöcke nach:
Entweder Backend-Title oder Sortierschlüssel
Sortierung auf-/absteigend:
Erklärt sich selbst
Fertig.
Wie kann die Anzahl der Elemente pro Zeile in der Kopfnavigation und bei den Infoboxen angepasst werden?
Im Augenblick ist die Anzahl der Hauptnavigationspunkte und Infoboxen in der "Desktopansicht" auf 4 pro Zeile festgelegt, was sich - je nach Breite des zur Verfügung stehenden Platzes - verringert. Die Anordnung der einzelnen Elemente erfolgt per Flexbox und die Breakpoints werden anhand von em-Weiten festgelegt. Um diese Breakpoints anzupassen sowie die Anzahl der Bilder/Punkte der Kopfnavigation die CSS-Klasse div.fi_boxes_theme_item in punkto width verändern. Die Infoboxen selbst können per width über die CSS-Klasse fi_box für die jeweiligen Breakpoints definiert werden. Zu finden ist das alles im Modulreiter "CSS".
Wie kann die Optik angepasst werden?
Auch hier geht der Weg über den Modulreiter "CSS". Um die korrekte Stellschraube herauszufinden, lohnt sich ein Blick in die Modulausgabe und die dort verwendeten CSS-Klassen.
Tipp:
Eine onsite-Search wird natürlich auch innerhalb der Artikel, die rein für die Ablage der Daten für die Infoboxen gebraucht werden, Suchtreffer generieren und hierauf verlinken. Schön aussehen wird das dann beim Öffnen wegen der abgespeckten Vorlage in den meisten Fällen nicht und wenn eine "normale Vorlage" in der üblichen Seitenoptik verwendet wird, dann ist die Information auch schnell "aus dem Zusammenhang gerissen". Um das zu vermeiden, kann im Artikelreiter "Eigenschaften" das Häkchen bei "Suchbar" entfernt werden. Dann wird natürlich nichts mehr gefunden, was letztlich auch nicht Sinn und Zweck sein kann. Die Lösung liegt jetzt darin, das Häkchen bei "Suchbar" aktiviert zu lassen, aber unter "Weiterleitung" die URL per front_content.php?idart=... auf den Webartikel, der das Modul "floating_information" beinhaltet, einzutragen. So führt ein Suchtreffer letztlich doch zum Ziel, auch wenn die passende Infobox dann noch nicht aufgeklappt ist.
Dieses Modul "floating_information" kann mit einem auf die Infoboxen beschränkten Suchmodul - was im folgenden Posting zu finden ist - ergänzt werden.
SOURCEN
Moduleingabe
Code: Alles auswählen
/***********************************************
* floating_information_sd input
*
* Author : seamless-design Markus Hübner
* Copyright : seamless-design Markus Hübner
* Created : 2016-08-02
************************************************/
echo '<table>';
echo '<tr><td>'.mi18n("input - Gewünschte Reihenfolge der idcats").'<td><td><input type="text" name="CMS_VAR[100]" value="CMS_VALUE[100]"/></td></tr>';
echo '<tr><td>'.mi18n("input - Sortierung der Infoblöcke nach").'</td>';
$infoboxes_order="CMS_VALUE[3000]";
echo '<td>
<select name="CMS_VAR[3000]">';
echo '<option value=""';
if($infoboxes_order=="") echo ' selected="selected"';
echo '>--- ? ---</option>';
echo '<option value="sortsequence"';
if($infoboxes_order=="sortsequence") echo ' selected="selected"';
echo '>'.mi18n("input - sortsequence").'</option>';
echo '<option value="title"';
if($infoboxes_order=="title") echo ' selected="selected"';
echo '>'.mi18n("input - title").'</option>';
echo '</select>
</td></tr>';
echo '<tr><td>'.mi18n("input - Sortierung auf-/absteigend").'</td>';
$infoboxes_order_direction="CMS_VALUE[3100]";
echo '<td>
<select name="CMS_VAR[3100]">';
echo '<option value=""';
if($infoboxes_order_direction=="") echo ' selected="selected"';
echo '>--- ? ---</option>';
echo '<option value="ASC"';
if($infoboxes_order_direction=="ASC") echo ' selected="selected"';
echo '>'.mi18n("input - aufsteigend").'</option>';
echo '<option value="DESC"';
if($infoboxes_order_direction=="DESC") echo ' selected="selected"';
echo '>'.mi18n("input - absteigend").'</option>';
echo '</select>
</td></tr>';
echo '</table>';
echo '<input type="image" src="images/submit.gif">';
Code: Alles auswählen
<?php
/***********************************************
* floating_information_sd output
*
* Author : seamless-design Markus Hübner
* Copyright : seamless-design Markus Hübner
* Created : 2016-08-02
************************************************/
$current_url=""; // without submitting current url to js-function, there will be a page-reload within firefox and chrome to www.domain.de/cms/#my_anchor. only after this reload jumping to anchors works
$isHttps = (!empty($_SERVER['HTTPS']));
if($isHttps) $current_url="https://";
else $current_url="http://";
$current_url.=$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$string_idcats="CMS_VALUE[100]";
$array_idcats=explode("#",$string_idcats);
$array_idcats_length=count($array_idcats);
$infoboxes_order="CMS_VALUE[3000]";
if($infoboxes_order=="") $infoboxes_order="title";
$infoboxes_order_direction="CMS_VALUE[3100]";
if($infoboxes_order_direction=="") $infoboxes_order_direction="asc";
echo '<div id="fi_boxes_theme_container" class="fi_boxes_theme_container">';
foreach($array_idcats AS $element)
{
/* get picture of start article begin */
$dirname="";
$filename="";
$list_of_articles = new cArticleCollector(array('idcat' => $element, "startonly" => 1));
$array_articles_to_show=array();
$array_articles_to_show=array();
foreach ($list_of_articles as $thisarticle)
{
$array_articles_to_show[]=$thisarticle->get('idart');
}
if(count($array_articles_to_show)>0)
{
foreach($array_articles_to_show AS $source_idart)
{
$article = new cApiArticleLanguage();
$article->loadByArticleAndLanguageId($source_idart, $lang);
$image = new cApiUpload();
$idupl = $article->getContent('CMS_IMGEDITOR', 1);
$image->loadByMany( array("idupl"=>$idupl) );
$dirname =$image->getField("dirname");
$filename = $image->getField("filename");
}
}
/* get picture of start article end */
/* show theme begin */
$cApiCatLang = new cApiCategoryLanguage();
$cApiCatLang->loadByCategoryIdAndLanguageId($element, $lang);
$theme=$cApiCatLang->get('name');
echo '<div class="fi_boxes_theme_item" id="fi_boxes_theme_item_'.$element.'" onclick="javascript:fi_boxes_theme_show_hide(\''.$element.'\',\''.$string_idcats.'\',\''.$current_url.'\');">';
echo '<div class="fi_boxes_theme_item_content">';
echo '<img style="width: 100%; height: auto;" src="upload/'.$dirname.$filename.'" alt="'.$theme.'" title="'.$theme.'"/><br/>';
echo $theme;
echo '</div>';
echo '</div>';
/* show theme end */
}
echo '</div>';
echo '<div style="clear: both;"></div>';
$string_search_ids=""; // preparation for module "floating_information_search"
foreach($array_idcats AS $element)
{
/* building array of articles within category begin */
//https://docs.contenido.org/display/CONDEVE/cArticleCollector
//http://api.contenido.org/latest/source-class-cArticleCollector.html
$list_of_articles = new cArticleCollector(array('idcat' => $element, "start" => 1, "order" => $infoboxes_order, "direction" => $infoboxes_order_direction));
$array_articles_to_show=array();
foreach ($list_of_articles as $thisarticle)
{
$array_articles_to_show[]=$thisarticle->get('idart');
}
/* building array of articles within category end */
/* show content of articles begin */
if(count($array_articles_to_show)>0)
{
$i=0;
echo '<div id="fi_boxes_theme_idcat_'.$element.'" style="display: none;">';
echo '<div class="fi_boxes container">';
foreach($array_articles_to_show AS $source_idart)
{
$article = new cApiArticleLanguage();
$article->loadByArticleAndLanguageId($source_idart, $lang);
if($i==0)
{
echo '<div id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'" class="fi_box_theme_intro">';
echo '<div class="fi_box_theme_intro" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_content">'; // definition of id as ..._content is necessary for searching ids
echo '<div class="fi_box_theme_intro_headline" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_question">'; // definition of id as ..._question is necessary for searching ids
echo $article->getContent('CMS_HTMLHEAD', 1);
echo '</div>';
echo '<div class="fi_box_theme_intro_content" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_answer">'; // definition of id as ..._answer is necessary for searching ids
echo $article->getContent('CMS_HTML', 1);
echo '</div>';
echo '</div>';
echo '</div>';
}
else
{
echo '<div class="fi_box item" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'">';
echo '<div class="fi_box_content" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_content">';
echo '<div title="'.mi18n("Informationen anzeigen/verbergen").'" class="fi_box_question" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_question" onclick="javascript:fi_box_answer_show_hide(\'fi_boxes_theme_idcat_'.$element.'_box_'.$i.'\',\'\')">'; // second data is necessary. have a look at floating_information.js and called function!
echo $article->getContent('CMS_HTMLHEAD', 1);
echo '</div>';
echo '<div class="fi_box_answer" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_answer" style="display: none;">';
echo $article->getContent('CMS_HTML', 1);
echo '</div>';
echo '</div>';
echo '<div title="'.mi18n("Informationen anzeigen/verbergen").'" class="fi_box_show_answer" id="fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_show_answer" onclick="javascript:fi_box_answer_show_hide(\'fi_boxes_theme_idcat_'.$element.'_box_'.$i.'\',\'\')">'; // second data is necessary. have a look at floating_information.js and called function!
echo ' ';
echo '</div>';
echo '</div>';
}
$string_search_ids.='#fi_boxes_theme_idcat_'.$element.'_box_'.$i.'_content'; // preparation for module "floating_information_search"
$i++;
}
echo '</div>';
echo '<div class="button_back_to_themes" onclick="javascript:window.location=\''.$current_url.'#fi_boxes_theme_container\';"></div>';
echo '</div>';
}
/* show content of articles end */
}
?>
Code: Alles auswählen
div.fi_boxes {
background-color: #f2f2f2;
padding-top: 0em;
padding-bottom: 2em;
padding-left: 0.5em;
padding-right: 0.5em;
margin-bottom: 2em;
width: 100%;
box-shadow:
inset 0px 11px 8px -10px #e1e1e1,
inset 0px -11px 8px -10px #e1e1e1;
}
div.fi_boxes_theme_container {
margin-top: 2em;
margin-bottom: 1em;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
div.fi_boxes_theme_item {
background-color: #ffffff;
width: 22%;
cursor: pointer;
display: flex;
flex-wrap: wrap;
align-content: space-between;
justify-content: center;
}
div.fi_boxes_theme_item_content {
padding: 1%;
text-align: center;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
div.fi_box {
width: 24%;
text-align: center;
}
div.fi_box_theme_intro {
margin-top: 1em;
width: 100%;
text-align: center;
}
div.fi_box_theme_intro_headline {
font-weight: 900;
}
div.fi_box_theme_intro_content {
}
.item {
align-self: stretch;
margin-top: 1em;
}
div.fi_box_content {
background-color: #ffffff;
height: 95%;
margin: 1em;
font-size: 0.9em;
}
div.fi_box_question {
cursor: pointer;
padding: 1em;
color: #555555;
}
div.fi_box_answer {
padding: 0.5em;
padding-bottom: 2.5em;
}
div.fi_box_show_answer {
width: 1em;
height: 1em;
background-image: url('../upload/bullets/fi_item_question_open.gif');
background-repeat: no-repeat;
background-size: 1em 1em;
background-position: center right;
margin-top: -2.5em;
margin-right: 1.5em;
float: right;
cursor: pointer;
}
div.button_back_to_themes {
width: 2em;
height: 2em;
margin-left: auto;
margin-right: auto;
background-image: url('../upload/bullets/button-arrow-up.png');
background-repeat: no-repeat;
background-size: 1em 1em;
cursor:pointer;
}
@media only screen and (max-width: 59em) {
div.fi_boxes {
}
div.fi_box {
width: 33%;
}
div.fi_boxes_theme_item {
width: 33%;
}
}
@media only screen and (max-width: 49em) {
div.fi_boxes {
}
div.fi_box {
width: 49%;
}
}
@media only screen and (max-width: 39em) {
div.fi_box {
width: 98%;
}
div.fi_boxes_theme_item {
width: 48%;
}
}
Code: Alles auswählen
function fi_box_answer_show_hide(var_id,var_origin) {
/*
this function shows or hides the answer to a question an manipulates the appearance of the question in color or whatever you want
examples for var_id:
fi_boxes_theme_idcat_2_box_0 (only possible, if this function is called from searchresult. if id is ending at _0, it contains the opening text of faq-area which has not a button to show/hide it like those boxes representing questions and answers
fi_boxes_theme_idcat_2_box_1 ("normal" id which is transferred by clicking on "show answer" within question-boxes of faq-area
var_origin: necessary -> have a look at module "search" and search.js -> function open_location. if this function is called via searchresult, it contains "search". otherwise it's clear.
*/
var var_box=var_id.split("_box_"); //some operations must not be processed for introtext, e.g. displaying a button to open or close the answer - if first element of this array is 0, it's the introtext
var var_box_number=var_box[1];
var var_pause=0; // in milli-seconds, needed if you want to add some effects an not just let the answer appear.
var var_animation_time=0; // in seconds, needed if you want to add some effects an not just let the answer appear.
var var_status=document.getElementById(var_id+'_answer').style.display; //checking if answer is already displayed or not
if(var_status=="none" || var_status=="" || var_origin=="search")
/*
var_status none:
is set, if that answer was displayed once before but hidden again via user
var_status empty:
nothing done with it, style-information was not manipulated
var_origin search:
this function firstly checks for status. if it is shown, the answer will be hidden. if it is hidden, it will be shown. if this function is called via searchresult, the answer might already be shown via user - in that case it must not be set to hidden. So in that case display will always be set to "block"
*/
{
document.getElementById(var_id+'_question').style.color="#00499a";
document.getElementById(var_id+'_question').style.fontWeight="900";
if(var_box_number!="0") // exclude intro of faq-area
{
document.getElementById(var_id).style.width="98%";
document.getElementById(var_id).style.transition=var_animation_time+"s";
document.getElementById(var_id).style.height="auto";
document.getElementById(var_id).style.marginBottom="-1em";
document.getElementById(var_id+'_show_answer').style.backgroundImage="url('../cms/upload/bullets/fi_item_question_close.gif')";
}
setTimeout(function()
{
document.getElementById(var_id+'_answer').style.display="block";
}
,var_pause);
}
else // when var_status is "block" or var_origin is empty
{
document.getElementById(var_id+'_answer').style.display="none";
document.getElementById(var_id).style.width="";
document.getElementById(var_id).style.transition=var_animation_time+"s";
document.getElementById(var_id+'_question').style.color="#555555";
document.getElementById(var_id+'_question').style.fontWeight="normal";
document.getElementById(var_id).style.height="";
document.getElementById(var_id).style.marginLeft="";
document.getElementById(var_id).style.marginBottom="";
document.getElementById(var_id+'_show_answer').style.backgroundImage="url('../cms/upload/bullets/fi_item_question_open.gif')";
}
}
function fi_boxes_theme_show_hide(var_id_theme,string_idcats,var_current_url) {
/*
this function is called via the parts of the heading menu of areas and shows or hides the different areas/themes of module. it also alters the appearance of heading menu-parts
var_id_theme: contains the idcat of category in which the information of area/theme is located
string_idcats: all idcats which are considered within module
*/
var array_idcats=new Array();
array_idcats = string_idcats.split("#"); //array contains the idcats of categories, in which the articles are located. these articles are filled with information to be shown
var var_status=document.getElementById('fi_boxes_theme_idcat_'+var_id_theme).style.display; // checking if area/theme is shown or not. depending on result it will be toggled.
if(var_status=="none") // all area divs are delivered with display: none at first rendering of site - yes, not that good regarding barriers. but letting them first appear all and afterwards setting them to display none would cause a gnarly flashpopuglysomething - especially on mobile devices... ;O)
{//if faq-area is hidden, it will be shown
document.getElementById('fi_boxes_theme_idcat_'+var_id_theme).style.display="block";
document.getElementById('fi_boxes_theme_item_'+var_id_theme).style.color="#0049a5";
document.getElementById('fi_boxes_theme_item_'+var_id_theme).style.fontWeight="900";
for (var i = 0, len = array_idcats.length; i < len; i++) // all ids of faq-areas are rolled through, to hide them - disregarding the user chosen one
{
if(var_id_theme!=array_idcats[i])
{
document.getElementById('fi_boxes_theme_idcat_'+array_idcats[i]).style.display="none";
document.getElementById('fi_boxes_theme_item_'+array_idcats[i]).style.color="#000000";
document.getElementById('fi_boxes_theme_item_'+array_idcats[i]).style.fontWeight="normal";
}
}
window.location=var_current_url+'#fi_boxes_theme_idcat_'+var_id_theme; // after hiding not necessary areas, jump to shown one
}
else // if faq-area is shown, it now will be hidden and heading menu part is set to passive state
{
document.getElementById('fi_boxes_theme_idcat_'+var_id_theme).style.display="none";
document.getElementById('fi_boxes_theme_item_'+var_id_theme).style.color="#000000";
document.getElementById('fi_boxes_theme_item_'+var_id_theme).style.fontWeight="normal";
}
}
Code: Alles auswählen
Informationen anzeigen/verbergen=Informationen anzeigen/verbergen
input - Gewünschte Reihenfolge der idcats=Gewünschte Reihenfolge der idcats
input - Sortierung auf-/absteigend=Sortierung auf-/absteigend
input - Sortierung der Infoblöcke nach=Sortierung der Infoblöcke nach
input - absteigend=absteigend
input - aufsteigend=aufsteigend
input - sortsequence=Sortierschlüssel
input - title=Backend-Title