This commit is contained in:
2020-04-22 11:57:47 +02:00
74 changed files with 3058 additions and 107 deletions

View File

@@ -58,12 +58,6 @@ chill_main_admin_central:
chill_main_admin_permissions:
path: /{_locale}/admin/permissions
defaults: {_controller: ChillMainBundle:Admin:indexPermissions }
options:
menus:
admin_section:
order: 200
label: Users and permissions
icons: [key]
chill_main_search:
path: /{_locale}/search.{_format}
@@ -88,3 +82,7 @@ login_check:
logout:
path: /logout
chill_main_test:
path: /{_locale}/main/test
defaults: { _controller: ChillMainBundle:Default:test }

View File

@@ -2,19 +2,6 @@ parameters:
# cl_chill_main.example.class: Chill\MainBundle\Example
services:
twig_intl:
class: Twig_Extensions_Extension_Intl
tags:
- { name: twig.extension }
twig_date:
class: Twig_Extensions_Extension_Date
arguments:
- "@translator"
tags:
- { name: twig.extension }
chill.main.helper.translatable_string:
class: Chill\MainBundle\Templating\TranslatableStringHelper
arguments:

View File

@@ -0,0 +1,16 @@
services:
# Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader:
#
# tags:
# - routing.loader
Chill\MainBundle\CRUD\Resolver\Resolver:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
$crudConfig: '%chill_main_crud_route_loader_config%'
Chill\MainBundle\CRUD\Templating\TwigCRUDResolver:
arguments:
$resolver: '@Chill\MainBundle\CRUD\Resolver\Resolver'
tags:
- { name: twig.extension }

View File

@@ -10,3 +10,9 @@ services:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
tags:
- { name: 'chill.menu_builder' }
Chill\MainBundle\Routing\MenuBuilder\AdminSectionMenuBuilder:
arguments:
$authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'
tags:
- { name: 'chill.menu_builder' }

View File

@@ -1,4 +1,21 @@
services:
twig_intl:
class: Twig_Extensions_Extension_Intl
tags:
- { name: twig.extension }
twig_date:
class: Twig_Extensions_Extension_Date
arguments:
- "@translator"
tags:
- { name: twig.extension }
twig_text:
class: Twig_Extensions_Extension_Text
tags:
- { name: twig.extension }
Chill\MainBundle\Templating\ChillTwigHelper:
tags:
- { name: twig.extension }
@@ -7,5 +24,9 @@ services:
arguments:
$requestStack: '@Symfony\Component\HttpFoundation\RequestStack'
$originalExtension: '@twig.extension.routing'
tags:
- { name: twig.extension }
Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension:
tags:
- { name: twig.extension }

View File

@@ -13,6 +13,10 @@ div.chill-collection {
li.chill-collection__list__entry:nth-last-child(1n+2) {
margin-bottom: 1rem;
}
button.chill-collection__list__remove-entry {
margin-left: 0.5rem;
}
}
button.chill-collection__button--add {

View File

@@ -76,7 +76,7 @@ var initializeRemove = function(collection, entry) {
return;
}
button.classList.add('sc-button', 'bt-delete');
button.classList.add('sc-button', 'bt-delete', 'chill-collection__list__remove-entry');
button.textContent = content;
button.addEventListener('click', function(e) {

36
Resources/public/main.js Normal file
View File

@@ -0,0 +1,36 @@
// import jQuery
const $ = require('jquery');
// create global $ and jQuery variables
global.$ = global.jQuery = $;
const moment = require('moment');
global.moment = moment;
const pikaday = require('pikaday-jquery');
const select2 = require('select2');
global.select2 = select2;
// import js
import {chill} from './js/chill.js';
global.chill = chill;
// css
require('./sass/scratch.scss');
require('./css/chillmain.css');
require('./css/pikaday.css');
require('./js/collection/collections.js');
require('./modules/breadcrumb/index.js');
require('./modules/download-report/index.js');
//require('./css/scratch.css');
//require('./css/select2/select2.css');
require('select2/dist/css/select2.css');
require('./modules/select_interactive_loading/index.js');
require('./modules/export-list/export-list.scss');
// img
require('./img/favicon.ico');
require('./img/logo-chill-sans-slogan_white.png');
require('./img/logo-chill-outil-accompagnement_white.png');

View File

@@ -17,6 +17,10 @@ body {
position: relative;
height: 90%;
padding-top: 10%;
footer.footer {
position: absolute;
bottom: 0;
}
}
#content:before {
@@ -63,10 +67,10 @@ button {
p.forgot-password-link {
text-align: center;
a {
font-weight: 300;
color: #fff;
text-decoration: none;
}
}
}

View File

@@ -0,0 +1 @@
require("./show_hide.js");

View File

@@ -0,0 +1,126 @@
/**
* Create a control to show or hide values
*
* Possible options are:
*
* - froms: an Element, an Array of Element, or a NodeList. A
* listener will be attached to **all** input of those elements
* and will trigger the check on changes
* - test: a function which will test the element and will return true
* if the content must be shown, false if it must be hidden.
* The function will receive the `froms` as first argument, and the
* event as second argument.
* - container: an Element, an Array of Element, or a Node List. The
* child nodes will be hidden / shown inside this container
* - event_name: the name of the event to listen to. `'change'` by default.
*
* @param object options
*/
var ShowHide = function(options) {
var
froms = typeof options.froms[Symbol.iterator] === "function" ? options.froms : [ options.froms ], //options.froms;
test = options.test,
container = typeof options.container[Symbol.iterator] === "function" ? options.container : [ options.container ],
is_shown = true,
event_name = 'event_name' in options ? options.event_name : 'change',
container_content = [],
debug = 'debug' in options ? options.debug : false,
load_event = 'load_event' in options ? options.load_event : 'load',
id = 'uid' in options ? options.id : Math.random();
var bootstrap = function(event) {
if (debug) {
console.log('debug is activated on this show-hide', this);
}
// keep the content in memory
for (let c of container.values()) {
let contents = [];
for (let el of c.childNodes.values()) {
contents.push(el);
}
container_content.push(contents);
}
// attach the listener on each input
for (let f of froms.values()) {
let inputs = f.querySelectorAll('input');
for (let input of inputs.values()) {
if (debug) {
console.log('attaching event to input', input);
}
input.addEventListener(event_name, function(e) {
onChange(e);
});
}
}
// first launch of the show/hide
onChange(event);
};
var onChange = function (event) {
var result = test(froms, event), me;
if (result === true) {
if (is_shown === false) {
forceShow();
me = new CustomEvent('show-hide-show', { detail: { id: id, container: container, froms: froms } });
window.dispatchEvent(me);
}
} else if (result === false) {
if (is_shown) {
forceHide();
me = new CustomEvent('show-hide-hide', { detail: { id: id, container: container, froms: froms } });
window.dispatchEvent(me);
}
} else {
throw "the result of test is not a boolean";
}
};
var forceHide = function() {
if (debug) {
console.log('force hide');
}
for (let contents of container_content.values()) {
for (let el of contents.values()) {
el.remove();
}
}
is_shown = false;
};
var forceShow = function() {
if (debug) {
console.log('show');
}
for (let i of container_content.keys()) {
var contents = container_content[i];
for (let el of contents.values()) {
container[i].appendChild(el);
}
}
is_shown = true;
};
var forceCompute = function(event) {
onChange(event);
};
if (load_event !== null) {
window.addEventListener('load', bootstrap);
} else {
bootstrap(null);
}
return {
forceHide: forceHide,
forceShow: forceShow,
forceCompute: forceCompute,
};
};
export {ShowHide};

View File

@@ -0,0 +1,2 @@
require("./tabs.js");
require("./tabs.scss");

View File

@@ -0,0 +1,118 @@
/*
* Remove active class on both elements: link and content
*/
let resetActive = function(links, contents)
{
for (items of [links, contents]) {
items.forEach(function(item) {
if (item.classList.contains('active')) {
item.classList.remove('active');
}
});
}
}
/*
* Count links array and return rank of given link
*/
let countNewActive = function(links, link)
{
let rank = 0;
for (let i = 0; i < links.length; ++i) {
rank++;
if(links[i] == link) {
return rank;
}
}
}
/*
* Set class active on both new elements: link and content
*/
let setNewActive = function(links, contents, rank)
{
if (! links[rank-1]) { rank = 1; }
link = links[rank-1];
link.classList.add('active');
count = 0;
contents.forEach(function(pane) {
count++;
if (rank == count) {
pane.classList.add('active');
}
});
}
/*
* Set height of content pane
*/
let setPaneHeight = function(contents)
{
contents.forEach(function(pane) {
// let computedStyle = getComputedStyle(pane);
// console.log(computedStyle.height);
// comment prendre la hauteur d'une div masquée avec display:none
});
}
/*
* Check if links are defined in controller
* If true, disable javascript listener
*/
let isLinkRef = function(link) {
if (link.getAttribute('href') == "#") {
return false;
}
return true;
}
/*
* Main function
*/
window.addEventListener('load', function()
{
tabParams.forEach(function(unit) {
let tabPanel = document.querySelector('#'+ unit.id );
if (tabPanel) {
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.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,98 @@
$navigation-color: #334d5c;
$body-font-color: #ffffff;
$tab-font-color: #495057;
$border-color: #dee2e6;
$pills-color: #ed9345;
$radius : .25rem;
div.tabs {
margin: 3em;
nav {
ul.nav-tabs {
display: flex;
display: -ms-flexbox;
flex-wrap: wrap;
-ms-flex-wrap: wrap;
list-style: none;
padding-left: 0;
margin-bottom: 0;
li.nav-item {
margin-bottom: -1px;
a.nav-link {
display: block;
padding: .5rem 1rem;
}
}
}
}
div.tab-content {
div.tab-pane {
display: none;
&.fade {
transition: opacity .15s linear;
}
&.active {
display: block;
}
}
}
&:not(.pills) {
nav {
ul.nav-tabs {
border-bottom: 1px solid $border-color;
li.nav-item {
a.nav-link {
border: 1px solid transparent;
border-top-left-radius: $radius;
border-top-right-radius: $radius;
color: $navigation-color;
}
&.show a.nav-link,
& a.nav-link.active {
color: $tab-font-color;
background-color: $body-font-color;
border-color: $border-color $border-color $body-font-color;
}
}
}
}
}
&.pills {
nav {
ul.nav-tabs {
border-bottom: 0;
li.nav-item {
& a.nav-link {
border: 0;
border-radius: $radius;
}
&.show > a.nav-link,
& a.nav-link.active {
color: $body-font-color;
background-color: $pills-color;
}
}
}
}
}
}

View File

@@ -4,7 +4,6 @@
@import 'custom/fonts';
@import 'custom/timeline';
@import 'custom/mixins/entity';
@import 'custom/activity';
@import 'custom/report';
@import 'custom/person';
@import 'custom/pagination';

View File

@@ -3,12 +3,12 @@
@font-face {
font-family: 'FontAwesome';
src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
src: url('./../../../fonts/fontawesome-webfont.eot?v=#{$fa-version}');
src: url('./../../../fonts/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
url('./../../../fonts/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
url('./../../../fonts/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
url('./../../../fonts/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
url('./../../../fonts/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;

View File

@@ -1,7 +0,0 @@
span.entity.entity-activity.activity-reason {
@include entity($chill-pink, white);
}
.activity {
color: $chill-green;
}

View File

@@ -10,6 +10,7 @@ ul.record_actions, ul.record_actions_column {
display: flex;
justify-content: flex-end;
padding: 0.5em 0;
flex-wrap: wrap-reverse;
li {
display: inline-block;

View File

@@ -1,6 +1,6 @@
@mixin entity($background-color, $color: white) {
font-variant: small-caps;
display: inline;
display: inline-block;
padding: .2em .6em .3em;
font-size: 88%;
font-weight: bold;
@@ -11,5 +11,6 @@
border-radius: .25em;
color: $color;
background-color: $background-color;
margin: 0.5em;
}

View File

@@ -1,7 +1,7 @@
.sc-button {
margin-bottom: 0.5rem;
&.bt-submit, &.bt-save, &.bt-create, &.bt-new {
&.bt-submit, &.bt-save, &.bt-create, &.bt-new, &.bt-duplicate {
@include button($green, $white);
}
@@ -19,6 +19,7 @@
&:not(.change-icon) {
// icons using font-awesome "old way"
&.bt-create::before,
&.bt-save::before,
&.bt-new::before,
@@ -31,6 +32,14 @@
font: normal normal normal 14px/1 FontAwesome;
margin-right: 0.5em;
}
// icons using font-awesome "new svg way"
&.bt-duplicate::before {
display: inline-block;
width: 1em;
margin-right: 0.5em;
vertical-align: middle;
}
&.bt-save::before {
// add a floppy
@@ -60,6 +69,10 @@
&.bt-show::before, &.bt-view::before {
content: "";
}
&.bt-duplicate::before {
content: url("./copy-solid.svg");
}
}
> i.fa {

View File

@@ -0,0 +1,4 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="copy" class="svg-inline--fa fa-copy fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<!-- adapted from original work obtained from font-awesome CC-BY 4.0 International - https://fontawesome.com/license Last updated on July 12, 2018 -->
<path fill="white" d="M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z"></path>
</svg>

After

Width:  |  Height:  |  Size: 733 B

View File

@@ -25,10 +25,17 @@ label {
abbr {
display: none;
}
// mark the label for empty placeholder
&[for$="_placeholder"] {
font-style: italic;
}
}
.inline-choice {
white-space:nowrap;
display: inline-block;
label {
white-space:normal;
display: inline;
@@ -38,6 +45,11 @@ label {
}
}
div.choice-widget-expanded {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
textarea,
//input,
#{$all-text-inputs},

View File

@@ -34,6 +34,7 @@ Save: Enregistrer
This form contains errors: Ce formulaire contient des erreurs
Choose an user: Choisir un utilisateur
'You are going to leave a page with unsubmitted data. Are you sure you want to leave ?': "Vous allez quitter la page alors que des données n'ont pas été enregistrées. Êtes vous sûr de vouloir partir ?"
No value: Aucune information
Edit: Modifier
Update: Mettre à jour
@@ -228,4 +229,27 @@ Log in with your new password: Connectez-vous avec votre nouveau mot de passe
# impersonate
Exit impersonation: Retour Administrateur
Impersonate: Mode fantôme
Impersonate mode: Mode fantôme
Impersonate mode: Mode fantôme
crud:
# general items
new:
button_action_form: Créer
link_edit: Modifier
save_and_close: Créer & fermer
save_and_show: Créer & voir
save_and_new: Créer & nouveau
success: Les données ont été créées
edit:
button_action_form: Enregistrer
back_to_view: Voir
save_and_close: Enregistrer & fermer
save_and_show: Enregistrer & voir
success: Les données ont été modifiées
delete:
success: Les données ont été supprimées
link_to_form: Supprimer
default:
success: Les données ont été enregistrées
view:
link_duplicate: Dupliquer

View File

@@ -17,3 +17,4 @@ This username or email does not exists: Cet utilisateur ou email n'est pas prés
#phonenumber
This is not a landline phonenumber: Ce numéro n'est pas une ligne fixe valide
This is not a mobile phonenumber: Ce numéro n'est pas un numéro de portable valide
This is not a valid phonenumber: Ce numéro de téléphone n'est pas valide

View File

@@ -0,0 +1,37 @@
<div class="{% block crud_content_main_div_class %}grid-10 centered{% endblock %}">
{% block crud_content_header %}
<h1>{{ ('crud.'~crud_name~'.title_delete')|trans({ '%as_string%': entity|chill_entity_render_string }) }}</h1>
{% endblock crud_content_header %}
<p class="message-confirm">{{ ('crud.'~crud_name~'.confirm_message_delete')|trans({ '%as_string%': entity|chill_entity_render_string }) }}</p>
{{ form_start(form) }}
<ul class="record_actions">
{% block content_form_actions_back %}
<li class="cancel">
<a class="sc-button bt-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_before %}{% endblock %}
{% block content_form_actions_view %}
{% if is_granted(chill_crud_config('role', crud_name, 'view'), entity) %}
<li class="">
<a class="sc-button bt-show" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_view', { 'id': entity.id }) }}">
{{ 'crud.edit.back_to_view'|trans }}
</a>
</li>
{% endif %}
{% endblock %}
{% block content_form_actions_confirm_delete %}
<li>
<button type="submit" class="sc-button bt-delete" value="delete-and-close">{{ ('crud.'~crud_name~'.button_delete')|trans }}</button>
</li>
{% endblock content_form_actions_confirm_delete %}
{% block content_form_actions_after %}{% endblock %}
</ul>
{{ form_end(form) }}
</div>

View File

@@ -0,0 +1,63 @@
<div class="{% block crud_content_main_div_class %}grid-10 centered{% endblock %}">
{% block crud_content_header %}
<h1>{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form %}
{{ form_start(form) }}
{% block crud_content_form_rows %}
{% for f in form %}
{{ form_row(f) }}
{% endfor %}
{% endblock crud_content_form_rows %}
{% block crud_content_form_actions %}
<ul class="record_actions sticky-form-buttons">
{% block content_form_actions_back %}
<li class="cancel">
<a class="sc-button bt-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_before %}{% endblock %}
{% block content_form_actions_delete %}
{% if chill_crud_action_exists(crud_name, 'delete') %}
{% if is_granted(chill_crud_config('role', crud_name, 'delete'), entity) %}
<li class="">
<a class="sc-button bt-small bt-delete" href="{{ chill_path_add_return_path('chill_crud_'~crud_name~'_delete', { 'id': entity.id }) }}"></a>
</li>
{% endif %}
{% endif %}
{% endblock content_form_actions_delete %}
{% block content_form_actions_view %}
{% if chill_crud_action_exists(crud_name, 'view') %}
{% if is_granted(chill_crud_config('role', crud_name, 'view'), entity) %}
<li class="">
<a class="sc-button bt-small bt-show" href="{{ chill_path_forward_return_path('chill_crud_'~crud_name~'_view', { 'id': entity.id }) }}"></a>
</li>
{% endif %}
{% endif %}
{% endblock content_form_actions_view %}
{% block content_form_actions_save_and_close %}
<li class="">
<button type="submit" name="submit" value="save-and-close" class="sc-button bt-update">
{{ 'crud.edit.save_and_close'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_save_and_show %}
<li class="">
<button type="submit" name="submit" value="save-and-show" class="sc-button bt-update">
{{ 'crud.edit.save_and_show'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_after %}{% endblock %}
</ul>
{% endblock %}
{{ form_end(form) }}
{% endblock %}
</div>

View File

@@ -0,0 +1 @@
{{ ('crud.'~crud_name~'.title_edit')|trans }}

View File

@@ -0,0 +1 @@
{{ data }}

View File

@@ -0,0 +1,48 @@
<div class="grid-10 centered">
{% block index_header %}
<h1>{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}</h1>
{% endblock index_header %}
{% if entities|length == 0 %}
{% block no_existing_entities %}
<p>{{ no_existing_entities_sentences|default('No entities')|trans }}</p>
{% endblock %}
{% else %}
{% block table_entities %}
<table>
<thead>
<tr>
{% block table_entities_thead_tr %}
<th>id</th>
{% endblock %}
</tr>
</thead>
<tbody>
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
</tr>
{% endfor %}
{% endblock %}
</tbody>
</table>
{% endblock %}
{% endif %}
<div class="crud_index__pagination">
{{ chill_pagination(paginator) }}
</div>
{% block list_actions %}
<ul class="record_actions sticky-form-buttons">
{% block add_new %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_' ~ crud_name ~ '_new') }}" class="sc-button bt-new">{{ ('crud.'~crud_name~'.index.add_new')|trans( {'%crud_name%': crud_name} ) }}</a>
</li>
{% endblock %}
</ul>
{% endblock list_actions %}
</div>

View File

@@ -0,0 +1,50 @@
<div class="{% block crud_content_main_div_class %}grid-10 centered{% endblock %}">
{% block crud_content_header %}
<h1>{{ ('crud.' ~ crud_name ~ '.title_new')|trans({'%crud_name%' : crud_name }) }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form %}
{{ form_start(form) }}
{% block crud_content_form_rows %}
{% for f in form if f.vars.name != 'submit' %}
{{ form_row(f) }}
{% endfor %}
{% endblock crud_content_form_rows %}
{% block crud_content_form_actions %}
<ul class="record_actions sticky-form-buttons">
{% block content_form_actions_back %}
<li class="cancel">
<a class="sc-button bt-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_save_and_close %}
<li class="">
<button type="submit" name="submit" value="save-and-close" class="sc-button bt-create">
{{ 'crud.new.save_and_close'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_save_and_show %}
<li class="">
<button type="submit" name="submit" value="save-and-show" class="sc-button bt-create">
{{ 'crud.new.save_and_show'|trans }}
</button>
</li>
{% endblock %}
{% block content_form_actions_save_and_new %}
<li class="">
<button type="submit" name="submit" value="save-and-new" class="sc-button bt-create">
{{ 'crud.new.save_and_new'|trans }}
</button>
</li>
{% endblock %}
</ul>
{% endblock %}
{{ form_end(form) }}
{% endblock %}
</div>

View File

@@ -0,0 +1 @@
{{ ('crud.' ~ crud_name ~ '.title_new')|trans({'%crud_name%' : crud_name }) }}

View File

@@ -0,0 +1,63 @@
<div class="{% block crud_content_main_div_class %}grid-10 centered{% endblock %}">
{% block crud_content_header %}
<h1>{{ 'crud.%crud_name%.title_view'|trans({'%crud_name%' : crud_name }) }}</h1>
{% endblock crud_content_header %}
{% block crud_content_view %}
{% block crud_content_view_details %}
<dl class="chill_view_data">
<dt>id</dt>
<dd>{{ entity.id|default("No id") }}</dd>
</dl>
{% endblock crud_content_view_details %}
{% block crud_content_view_actions %}
<ul class="record_actions sticky-form-buttons">
{% block content_view_actions_back %}
<li class="cancel">
<a class="sc-button bt-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_view_actions_before %}{% endblock %}
{% block content_form_actions_delete %}
{% if chill_crud_action_exists(crud_name, 'delete') %}
{% if is_granted(chill_crud_config('role', crud_name, 'delete'), entity) %}
<li class="">
<a class="sc-button bt-delete" href="{{ chill_path_add_return_path('chill_crud_'~crud_name~'_delete', { 'id': entity.id }) }}">
{{ 'crud.delete.link_to_form'|trans }}
</a>
</li>
{% endif %}
{% endif %}
{% endblock content_form_actions_delete %}
{% block content_view_actions_duplicate_link %}
{% if chill_crud_action_exists(crud_name, 'new') %}
{% if is_granted(chill_crud_config('role', crud_name, 'new'), entity) %}
<li>
<a class="sc-button bt-duplicate" href="{{ chill_path_add_return_path('chill_crud_'~crud_name~'_new', { 'duplicate_id': entity.id, 'duplicate': true }) }}">
{{ 'crud.view.link_duplicate'|trans }}
</a>
</li>
{% endif %}
{% endif %}
{% endblock content_view_actions_duplicate_link %}
{% block content_view_actions_edit_link %}
{% if chill_crud_action_exists(crud_name, 'edit') %}
{% if is_granted(chill_crud_config('role', crud_name, 'edit'), entity) %}
<li>
<a class="sc-button bt-edit" href="{{ chill_path_forward_return_path('chill_crud_'~crud_name~'_edit', { 'id': entity.id }) }}">
{{ 'crud.new.link_edit'|trans }}
</a>
</li>
{% endif %}
{% endif %}
{% endblock content_view_actions_edit_link %}
{% block content_view_actions_after %}{% endblock %}
</ul>
{% endblock crud_content_view_actions %}
{% endblock crud_content_view %}
</div>

View File

@@ -0,0 +1 @@
{{ 'crud.%crud_name%.title_view'|trans({'%crud_name%' : crud_name }) }}

View File

@@ -0,0 +1,8 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}{{ ('crud.' ~ crud_name ~ '.delete.title')|trans({'%crud_name%': crud_name}) }}{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_delete_content.html.twig' %}
{% endembed %}
{% endblock content %}

View File

@@ -0,0 +1,10 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% endembed %}
{% endblock content %}

View File

@@ -0,0 +1,10 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1,10 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_view_title.html.twig') %}
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_view_content.html.twig' %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1 @@
{% if value is not empty %}<blockquote class="chill-user-quote">{{ value|localizeddate(date_format, time_format) }}</blockquote>{% else %}<span class="chill-no-data-statement">{{ message|trans }}</span>{% endif %}

View File

@@ -0,0 +1 @@
{% if value is not empty %}{{ value|localizeddate(date_format, time_format) }}{% else %}<span class="chill-no-data-statement">{{ message|trans }}</span>{% endif %}

View File

@@ -52,7 +52,7 @@
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
<div {{ block('widget_container_attributes') }} class="choice-widget-expanded">
{% for child in form %}
<span class="inline-choice">
{{ form_widget(child) }}

View File

@@ -0,0 +1 @@
<footer class="footer"></footer>

View File

@@ -1,5 +1,5 @@
{#
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
<info@champs-libres.coop> / <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
@@ -15,7 +15,6 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
<!DOCTYPE html>
<html>
<head>
@@ -29,7 +28,7 @@
<body>
<div id="content">
{{ include('@ChillMain/Login/_login-logo.html.twig') }}
{% if error is not null %}
<p>{{ error.message|trans }}</p>
{% endif %}
@@ -42,11 +41,15 @@
<input type="password" name="_password" />
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
<br/>
<button type="submit" name="login">{{ 'Login'|trans }}</button>
<button type="submit" name="login">{{ 'Login'|trans }}</button>
</form>
<p class="forgot-password-link"><a href="{{ path('password_request_recover') }}">{{ 'Forgot your password ?'|trans }}</a></p>
{{ include('@ChillMain/Login/_footer.html.twig') }}
</div>
<script type="text/javascript" src="{{ asset('build/runtime.js') }}"></script>
</body>
</html>

View File

@@ -21,16 +21,18 @@
<a href="{{ path('chill_main_admin_central') }}" class="more">Admin Sections</a>
</div>
<ul class="submenu width-15-em" style="padding-left: 0; padding-right: 0; background-color:transparent;">
{% for route in routes %}
{% for menu in menus %}
<li style="display:block; background-color: #333333; padding-left:1.5em; border-bottom:1px; border-bottom: 1px solid #FFF;padding-top:0; padding-bottom:0;">
<div style="margin-bottom:2px;">
<div style="font-family: 'Open Sans'; font-weight: 300; font-size: 0.75em; text-align:left; height: 46px; display:inline-block; width: calc(100% - 5em - 1px); vertical-align:top;">
<a href="{{ path(route.key, args ) }}">{{ route.label|trans }}</a>
<div style="font-family: 'Open Sans'; font-weight:300; font-size: 0.75em; text-align:left; height: 46px; display:inline-block; width: calc(100% - 5em - 1px); vertical-align:top;">
<a href="{{ menu.uri }}">{{ menu.label|trans }}</a>
</div>
<div style="background-color: #333333; text-align:center;width: 2em; margin-left:-0.15em; font-size:1.5em; color:#FFF; height: 46px; display:inline-block; vertical-align:top;float:right">{% spaceless %}
{% for icon in route.icons %}
{% if menu.extras.icons is defined %}
{% for icon in menu.extras.icons %}
<i class="fa fa-{{ icon }}"></i>
{% endfor %}
{% endif %}
{% endspaceless %}</div>
</div>
</li>

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

@@ -142,6 +142,7 @@
{{ include('@ChillMain/Layout/_footer.html.twig') }}
<script type="text/javascript" src="{{ asset('build/runtime.js') }}"></script>
<script type="text/javascript" src="{{ asset('build/chill.js') }}"></script>
<script type="text/javascript">