tabs feature, adding macro and documentation

This commit is contained in:
Tchama 2019-12-13 18:08:57 +01:00
parent 03c75b811e
commit 054adcbc43
6 changed files with 243 additions and 93 deletions

View File

@ -23,9 +23,9 @@ class DefaultController extends Controller
public function testAction()
{
return $this->render('ChillMainBundle:Test:index.html.twig', [
return $this->render('ChillMainBundle:Tabs:index.html.twig', [
'tabs' => [
"test1" => [
'test1' => [
[
'name' => "Link 1",
'content' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.",
@ -47,7 +47,7 @@ class DefaultController extends Controller
'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.",
]
],
"test2" => [
'test2' => [
[
'name' => "Link 1",
'link' => "http://localhost",
@ -73,8 +73,9 @@ class DefaultController extends Controller
//'link' => "http://localhost",
'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.",
]
],
]
]
]);
}
}
}

View File

@ -78,38 +78,41 @@ let isLinkRef = function(link) {
window.addEventListener('load', function()
{
tabParams.forEach(function(unit) {
let tabPanel = document.querySelector('#'+ unit.id );
if (tabPanel) {
let
tabPanel = document.querySelector('#'+ unit.id ),
nav = tabPanel.querySelector('nav'),
tabs = nav.querySelectorAll('ul.nav-tabs li.nav-item'),
links = nav.querySelectorAll('ul.nav-tabs li.nav-item a.nav-link'),
contents = tabPanel.querySelectorAll('div.tab-content div.tab-pane')
;
let
nav = tabPanel.querySelector('nav'),
tabs = nav.querySelectorAll('ul.nav-tabs li.nav-item'),
links = nav.querySelectorAll('ul.nav-tabs li.nav-item a.nav-link'),
contents = tabPanel.querySelectorAll('div.tab-content div.tab-pane')
;
if (unit.type == 'pill') {
tabPanel.classList.add('pills');
}
if (! unit.startPanel) {
unit.startPanel = 1;
}
setPaneHeight(contents);
// initial position
setNewActive(links, contents, unit.startPanel);
// listen
links.forEach(function(link) {
if (isLinkRef(link) == false) {
link.addEventListener('click', function()
{
resetActive(links, contents);
setNewActive(links, contents, countNewActive(links, link));
});
if (unit.type == 'pill') {
tabPanel.classList.add('pills');
}
});
if (! unit.initPane) {
unit.initPane = 1;
}
setPaneHeight(contents);
// initial position
setNewActive(links, contents, unit.initPane);
// listen
links.forEach(function(link) {
if (isLinkRef(link) == false) {
link.addEventListener('click', function()
{
resetActive(links, contents);
setNewActive(links, contents, countNewActive(links, link));
});
}
});
}
});
});

View File

@ -0,0 +1,126 @@
# Fonctionnalité Tabs sur Chill-Main
Version 0.2
(to be translated)
## Description générale
**Tabs** est pensé comme une fonctionnalité paramétrique, qui permet de déployer facilement un ou plusieurs groupes d'onglets, avec des options qui permettent de varier son affichage et son comportement.
Le comportement naturel, ce sont des panneaux qui sont affichés ou cachés en javascript, lorqu'on clique sur l'onglet relatif.
## Controller
```
// in myController.php
public function myPageAction()
{
return $this->render('mytemplate.html.twig', [
'tabs' => [
'myFirstPanel' => [
[ 'name' => "Link 1",
'content' => "content text"
],
[ 'name' => "Link 2",
'content' => "content text for link 2"
]
],
'mySecondPanel' => [
[ 'name' => "Link 1",
'content' => "content text"
],
[ 'name' => "Link 2",
'link' => "http://my.url"
]
]
],
// ...
]);
}
```
#### Description
* On peut définir plusieurs panneaux d'onglets qui s'afficheront dans une même page ;
* Voici la description du tableau passé au template depuis le controller :
* Au départ on rassemble tous les panneaux d'onglets dans une seule clé, nommée ici `tabs` (la variable est utilisée dans le template, mais son nom peut changer);
* Au niveau suivant, chaque clé correspond à l'identifiant(id) d'un panneau d'onglet ;
* Au niveau suivant, chaque onglet est défini par un tableau, qui comprends les clés suivantes :
* la clé `name`, le titre de l'onglet ;
* la clé `content`, le contenu du panneau relatif à l'onglet. A ce stade, si `content` contient un tableau, il vous faudra adapter la boucle twig de la macro (voir ci-dessous) ;
* une clé `link` (facultative)
* Lorsque la clé `link` est définie pour un onglet, le comportement est différent : le lien est suivi et on quitte la page. Un panneau d'onglets peut être mixte, avec certains onglets qui sont en réalité des liens.
## Template
```
{# in mytemplate.html.twig #}
{% block css%}
<link rel="stylesheet" href="{{ asset('build/tabs.css') }}"/>
{% endblock %}
{% block js%}
<script type="text/javascript">
let tabParams = [{
id : 'myFirstPanel',
type: 'tab',
initPane: 2,
disposition: 'horizontal',
fade: true
},
{
id : 'mySecondPanel',
type: 'pill',
initPane: 5,
disposition: 'vertical',
fade: false
}
];
</script>
<script type="text/javascript" src="{{ asset('build/tabs.js') }}"></script>
{% endblock %}
{% import '@ChillMain/Tabs/macro.html.twig' as tabsPanel %}
{% block content %}
{# Display one tabsPanel #}
{{ tabsPanel.displayOne(tabs, 'myFirstPanel') }}
{# Display all tabPanels #}
{{ tabsPanel.display(tabs) }}
{% endblock %}
```
* Il faut commencer par charger la feuille de style `tabs.css` et le script `tabs.js` à l'intérieur des blocs css et js ;
* Avant d'appeler `tabs.js`, on définit un tableau d'options pour le script :
* **id**: string, la clé identifiant du panneau d'onglet (obligatoire)
* **type**: [tab|pill] affecte l'affichage (default: tab)
* **initPane**: entier, numéro de l'onglet à afficher au chargement de la page (default: 1)
* [prévu] **disposition**: [horizontal|vertical] affecte l'affichage (default: horizontal)
* [prévu] **fade**: boolean, transition (default: false)
* Ensuite on peut importer la macro `@ChillMain/Tabs/macro.html.twig` qui permet d'afficher les panneaux d'onglets, soit un par un, soit tous les panneaux ;
* Ou on peut s'inspirer des boucles twig de la macro pour en écrire de nouvelles personnalisées ;
## Limitations
* On ne peut pas afficher plusieurs fois le même panneau dans la même page
## Aller plus loin
* fixer les options disposition et fade
* js, calculer puis fixer la hauteur du panneau suivant le plus long
* controller, avec link, on clique il charge une nouvelle page, avec le même panneau d'onglet ?!
* insérer le initPane dans les urls en paramètres GET &initPane=xx
* quand tab.content n'est pas un string : un bloc de code html, un tableau..

View File

@ -0,0 +1,43 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}Page de test{% endblock %}
{% block css%}
<link rel="stylesheet" href="{{ asset('build/tabs.css') }}"/>
{% endblock %}
{% block js%}
<script type="text/javascript">
let tabParams = [{
id : 'test1',
type: 'tab',
initPane: 2,
disposition: 'horizontal',
fade: true
},
{
id : 'test2',
type: 'pill',
initPane: 5,
disposition: 'vertical',
fade: false
}
];
</script>
<script type="text/javascript" src="{{ asset('build/tabs.js') }}"></script>
{% endblock %}
{% import '@ChillMain/Tabs/macro.html.twig' as tabsPanel %}
{% block content %}
{# Display one tabsPanel
{{ tabsPanel.displayOne(tabs, 'test1') }}
#}
{# Display all tabPanels #}
{{ tabsPanel.display(tabs) }}
{% endblock %}

View File

@ -0,0 +1,36 @@
{#
Display only one panel
#}
{% macro displayOne(tabs, panel) %}
<div class="tabs" id="{{ panel }}">
<nav>
<ul class="nav-tabs" role="tablist">
{% for tab in tabs[panel] %}
<li class="nav-item">
{% set ref = (tab.link is defined )? tab.link : '#' %}
<a class="nav-link" href="{{ ref }}">{{ tab.name }}</a>
</li>
{% endfor %}
</ul>
</nav>
<div class="tab-content">
{% for tab in tabs[panel] %}
<div class="tab-pane fade" role="tabpanel">
{% if tab.content is defined %}
<p>{{ tab.content }}</p>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endmacro %}
{#
Display all panels
#}
{% macro display(tabs) %}
{% import _self as tabsPanel %}
{% for panel,array in tabs %}
{{ tabsPanel.displayOne(tabs, panel) }}
{% endfor %}
{% endmacro %}

View File

@ -1,59 +0,0 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}Page de test{% endblock %}
{% block css%}
<link rel="stylesheet" href="{{ asset('build/tabs.css') }}"/>
{% endblock %}
{% block js%}
<script type="text/javascript">
let tabParams = [{
id : 'test1',
type: 'tab',
startPanel: 2,
disposition: 'horizontal',
fade: true
},
{
id : 'test2',
type: 'pill',
startPanel: 5,
disposition: 'vertical',
fade: false
}
];
</script>
<script type="text/javascript" src="{{ asset('build/tabs.js') }}"></script>
{% endblock %}
{% block content %}
{% for key,tabsPanel in tabs %}
<div class="tabs" id="{{ key }}">
<nav>
<ul class="nav-tabs" role="tablist">
{% for tab in tabsPanel %}
<li class="nav-item">
{% set ref = (tab.link is defined )? tab.link : '#' %}
<a class="nav-link" href="{{ ref }}">{{ tab.name }}</a>
</li>
{% endfor %}
</ul>
</nav>
<div class="tab-content">
{% for tab in tabsPanel %}
<div class="tab-pane fade" role="tabpanel">
{% if tab.content is defined %}
<p>{{ tab.content }}</p>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}