forked from entrouvert/publik-base-theme
publik-famille: adapt widget to display many weeks (#69146)
This commit is contained in:
parent
daab975165
commit
857c00a08c
|
@ -2,240 +2,315 @@
|
|||
|
||||
{% block widget-control %}
|
||||
{% with options=widget.get_options|list %}
|
||||
|
||||
{% with first_monday=options.0.options.date|date|adjust_to_week_monday last_option=options|last %}
|
||||
{% with last_day=last_option.options.date|date|adjust_to_week_monday|add_days:6 %}
|
||||
{% now 'Y-m-d' as now %}
|
||||
|
||||
<button class="previous-week">←</button>
|
||||
<ul>
|
||||
{% for day in first_monday|iterate_days_until:last_day %}
|
||||
{% if day.weekday == 0 %}
|
||||
{% if not forloop.first %}</ul></li>{% endif %}
|
||||
<li class="week{% if forloop.first %} shown{% endif %}"><span class="week-title">Semaine<br class="weekbreak"> du {{day|date:"d/m"}} au {{day|add_days:6|date:"d/m"}}</span><ul>
|
||||
{% endif %}
|
||||
<li class="day-title {% if form.var.current_day == day|date:"Y-m-d" or not form.var.current_day and now == day|date:"Y-m-d" %}current{% endif %}" data-weekday="{{day.weekday}}"><strong>{{day|date:"l d/m"}}</strong></li>
|
||||
{% with day_str=day|date:"Y-m-d" %}
|
||||
{% for option in options %}
|
||||
{% if option.options.date == day_str %}
|
||||
|
||||
<li {% if option.disabled %}class="disabled"{% endif %}
|
||||
data-date="{{ option.options.date }}"
|
||||
{% if option.options.status %}data-status="{{ option.options.status }}"{% endif %}
|
||||
{% if widget.readonly and not option.disabled %}
|
||||
{% if option.selected and not option.options.booked_for_external_user %}data-has-change
|
||||
{% elif not option.selected and option.options.booked_for_external_user %}data-has-change
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
><label><input
|
||||
{% if not widget.value and option.options.booked_for_external_user %}checked="checked"
|
||||
{% elif widget.value and option.options.booked_for_external_user and option.disabled %}checked="checked"
|
||||
{% elif option.selected %}checked="checked"{% endif %}
|
||||
{% if widget.readonly or option.disabled %}disabled{% endif %}
|
||||
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}
|
||||
type="checkbox"
|
||||
data-event-id="{{ option.options.id }}"
|
||||
data-overlaps="{{ option.options.overlaps|join:" " }}"
|
||||
{% if widget.readonly %}value="yes" disabled
|
||||
{% else %}name="{{ option.name }}" value="yes"
|
||||
{% endif %}><span>{{ option.options.label }}</span></label>
|
||||
{% if widget.readonly and option.selected %}<input type="hidden" name="{{ option.name }}" value="yes">{% endif %}
|
||||
</li>
|
||||
|
||||
{% with first_monday=options.0.options.date|adjust_to_week_monday last_option=options|last %}
|
||||
{% with last_day=last_option.options.date|adjust_to_week_monday|add_days:6 %}
|
||||
{% now 'W' as current_week %}
|
||||
{% spaceless %}
|
||||
<button class="template-famille-reservations-par-semaine--previous-week">←</button>
|
||||
<div class="template-famille-reservations-par-semaine--week-list">
|
||||
<div class="template-famille-reservations-par-semaine--slider">
|
||||
{% for day in first_monday|iterate_days_until:last_day %}
|
||||
{% if day.weekday == 0 %}
|
||||
{% with sunday=day|add_days:6 %}
|
||||
<div class="template-famille-reservations-par-semaine--week-title {% if form.var.current_day == day|date:"Y-m-d" or not form.var.current_day and current_week == day|date:"W" %}current{% endif %}">
|
||||
Du {{ day|date:"d/m" }} au {{ sunday|date:"d/m" }}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
<div class="template-famille-reservations-par-semaine--day-item" data-weekday="{{ day.weekday }}" data-date="{{ day|date:"Y-m-d" }}">
|
||||
<div class="template-famille-reservations-par-semaine--day-title">
|
||||
{{ day|date:"l d/m" }}
|
||||
</div>
|
||||
{% with day_str=day|date:"Y-m-d" %}
|
||||
{% for option in options %}
|
||||
{% if option.options.date == day_str %}
|
||||
<div class="template-famille-reservations-par-semaine--activity-item {% if option.disabled %}disabled{% endif %} {% if widget.readonly %}readonly{% endif %}"
|
||||
{% if widget.readonly and not option.disabled %}
|
||||
{% if option.selected and not option.options.booked_for_external_user %}data-has-change
|
||||
{% elif not option.selected and option.options.booked_for_external_user %}data-has-change
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
>
|
||||
<div class="template-famille-reservations-par-semaine--activity-status {{ option.options.status }}"></div>
|
||||
<div class="template-famille-reservations-par-semaine--activity-label"/>
|
||||
<label>
|
||||
<input
|
||||
{% if not widget.value and option.options.booked_for_external_user %}checked="checked"{% endif %}
|
||||
{% if option.selected %}checked="checked"
|
||||
{% elif widget.readonly or option.disabled %}disabled{% endif %}
|
||||
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}
|
||||
type="checkbox"
|
||||
data-event-id="{{ option.options.id }}"
|
||||
data-overlaps="{{ option.options.overlaps|join:" " }}"
|
||||
{% if widget.readonly %}value="yes" disabled
|
||||
{% else %}name="{{ option.name }}" value="yes"
|
||||
{% endif %} />
|
||||
<span>{{ option.options.label }}</span>
|
||||
</label>
|
||||
{% if widget.readonly and option.selected %}<input type="hidden" name="{{ option.name }}" value="yes">{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% if forloop.last %}</ul></li>{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<button class="next-week">→</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="template-famille-reservations-par-semaine--next-week">→</button>
|
||||
{% endspaceless %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
<style>
|
||||
.template-famille-reservations-par-semaine .content {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, auto);
|
||||
grid-template-rows: repeat(2, auto);
|
||||
justify-items: left;
|
||||
--min-column-width: 250;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine .content ul li label {
|
||||
line-height: 150%;
|
||||
.template-famille-reservations-par-semaine--previous-week,
|
||||
.template-famille-reservations-par-semaine--next-week {
|
||||
height: 3em;
|
||||
width: 3em;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine.widget-readonly .content {
|
||||
margin-right: 1em;
|
||||
.template-famille-reservations-par-semaine--next-week {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine .content > ul {
|
||||
.template-famille-reservations-par-semaine--week-list {
|
||||
overflow: hidden;
|
||||
margin-bottom: 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine .content > ul > li {
|
||||
display: none;
|
||||
.template-famille-reservations-par-semaine--slider {
|
||||
column-gap: 0px;
|
||||
display: grid;
|
||||
grid-auto-columns: 0px;
|
||||
grid-auto-rows: 0px;
|
||||
grid-auto-flow: column;
|
||||
position: relative;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content > ul > li.shown {
|
||||
display: block;
|
||||
}
|
||||
.template-famille-reservations-par-semaine button.previous-week,
|
||||
.template-famille-reservations-par-semaine button.next-week {
|
||||
height: 3em;
|
||||
z-index: 10;
|
||||
}
|
||||
.template-famille-reservations-par-semaine button.previous-week {
|
||||
margin-left: 0;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.template-famille-reservations-par-semaine button.next-week {
|
||||
margin-left: 1em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .week-title {
|
||||
|
||||
.template-famille-reservations-par-semaine--week-title {
|
||||
display: block;
|
||||
height: 3em;
|
||||
line-height: 3em;
|
||||
}
|
||||
.template-famille-reservations-par-semaine li.day-title {
|
||||
margin: 1em 0 0.5em 0;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content label {
|
||||
position: relative;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input[disabled] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input[disabled] + span {
|
||||
padding-left: 1.66rem;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input[disabled] + span::before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
height: calc(0.66rem + 2px);
|
||||
width: calc(0.66rem + 2px);
|
||||
background: transparent;
|
||||
top: 0.33rem;
|
||||
left: 0;
|
||||
border: 1px solid black;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input[disabled] + span::before {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input[disabled] + span::after {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
height: calc(0.66rem);
|
||||
width: calc(0.66rem);
|
||||
background: transparent;
|
||||
transition: background 0.1s linear;
|
||||
top: calc(0.33rem + 1px);
|
||||
left: 1px;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content input:checked + span::after {
|
||||
background: #3c3;
|
||||
|
||||
.template-famille-reservations-par-semaine--week-title {
|
||||
border-bottom: 1px solid #888;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 3.2rem;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine .content [data-status=booked] input[disabled] + span::after {
|
||||
background: #3c3;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content [data-status=absence] input[disabled] + span::after {
|
||||
background: red;
|
||||
}
|
||||
.template-famille-reservations-par-semaine .content [data-status=cancelled] input[disabled] + span::after {
|
||||
background: yellow;
|
||||
.template-famille-reservations-par-semaine--day-item {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
div.CheckboxesWidget.template-famille-reservations-par-semaine div.content ul li.disabled {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine.widget-readonly .content [data-has-change] input[disabled]:checked + span::after {
|
||||
background: #3f3;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine.widget-readonly .content [data-status=booked][data-has-change] input[disabled]:not(:checked) + span::after {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine .content [data-has-change] label {
|
||||
.template-famille-reservations-par-semaine--day-title {
|
||||
border-bottom: 1px solid #888;
|
||||
margin: 1rem 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
br.weekbreak { display: none; }
|
||||
.template-famille-reservations-par-semaine--activity-item {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin: 0.3rem 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.template-famille-reservations-par-semaine--activity-item.disabled {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
br.weekbreak { display: block; }
|
||||
.template-famille-reservations-par-semaine--activity-status {
|
||||
min-height: calc(0.66rem + 2px);
|
||||
min-width: calc(0.66rem + 2px);
|
||||
background: transparent;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 2px;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
div.template-famille-reservations-par-semaine div.content > ul {
|
||||
margin: 0 -4em;
|
||||
}
|
||||
div.template-famille-reservations-par-semaine div.content > ul .week-title {
|
||||
margin: 0 4em;
|
||||
line-height: 150%;
|
||||
text-align: center;
|
||||
}
|
||||
.template-famille-reservations-par-semaine--activity-status.booked {
|
||||
background: #3c3;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-status.cancelled {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-status.absence {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item[data-has-change] .template-famille-reservations-par-semaine--activity-status:not(.booked) {
|
||||
background: #3f3;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item[data-has-change] .template-famille-reservations-par-semaine--activity-status.booked {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item[data-has-change] label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item:not(.readonly):not(.disabled) .template-famille-reservations-par-semaine--activity-status {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item input {
|
||||
flex-shrink: 0;
|
||||
margin-right: 1rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-item input[disabled] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.template-famille-reservations-par-semaine--activity-label label {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function initAgendaWidget($widget, prefix) {
|
||||
const $weekList = $(prefix + '--week-list', $widget);
|
||||
const $slider = $(prefix + '--slider', $widget);
|
||||
let $currentWeek = $(prefix + '--week-title.current', $widget);
|
||||
if (!$currentWeek.length) {
|
||||
$currentWeek = $(prefix + '--week-title:first', $widget);
|
||||
}
|
||||
const $nextWeekButton = $(prefix + '--next-week', $widget);
|
||||
const $previousWeekButton = $(prefix + '--previous-week', $widget);
|
||||
const $editAgendaBtn = $(prefix + '--edit-btn', $widget);
|
||||
|
||||
function refresh_week_classes() {
|
||||
$('p.activite').hide();
|
||||
$('.week.shown [data-date]').each(function(idx, elem) {
|
||||
$('.activite-' + $(elem).data('date')).show();
|
||||
let $selectedWeek = $currentWeek;
|
||||
|
||||
function refresh_week_classes() {
|
||||
$('p.activite').hide();
|
||||
$($selectedWeek).nextUntil(prefix + '--week-title').each(function(idx, elem) {
|
||||
$('.activite-' + $(elem).data('date')).show();
|
||||
});
|
||||
}
|
||||
|
||||
function getPreviousWeek() { return $selectedWeek.prevAll(prefix + '--week-title:first'); }
|
||||
function getNextWeek() { return $selectedWeek.nextAll(prefix + '--week-title:first'); }
|
||||
|
||||
function setCurrentWeek($week, enableTransition) {
|
||||
if(!$week.length) {
|
||||
return;
|
||||
}
|
||||
const currentOffset = $week[0].offsetLeft;
|
||||
$slider.css({
|
||||
'transform': `translate(-${currentOffset}px)`,
|
||||
'transition': (enableTransition ? 'transform 0.5s' : '')
|
||||
});
|
||||
|
||||
$selectedWeek = $week;
|
||||
$nextWeekButton.prop('disabled', getNextWeek().length == 0);
|
||||
$previousWeekButton.prop('disabled', getPreviousWeek().length == 0);
|
||||
|
||||
const selectedWeekIsInPast = $selectedWeek.nextAll(prefix + '--week-title.current').length;
|
||||
$weekToEdit = selectedWeekIsInPast ? $currentWeek : $selectedWeek;
|
||||
$editAgendaBtn.prop('href', $weekToEdit.attr('data-edit-url'));
|
||||
}
|
||||
|
||||
function setPreviousWeek() {
|
||||
setCurrentWeek(getPreviousWeek(), true);
|
||||
refresh_week_classes();
|
||||
return false;
|
||||
}
|
||||
function setNextWeek() {
|
||||
setCurrentWeek(getNextWeek(), true);
|
||||
refresh_week_classes();
|
||||
return false;
|
||||
}
|
||||
|
||||
$previousWeekButton.on('click', setPreviousWeek);
|
||||
$nextWeekButton.on('click', setNextWeek);
|
||||
|
||||
let touchStartX = 0;
|
||||
$widget.on('touchstart', (e) => {
|
||||
touchStartX = e.changedTouches[0].screenX;
|
||||
});
|
||||
|
||||
$widget.on('touchend', (e) => {
|
||||
const touchEndX = e.changedTouches[0].screenX
|
||||
if (touchEndX - touchStartX < -30) {
|
||||
setNextWeek();
|
||||
} else if (touchEndX - touchStartX > 30) {
|
||||
setPreviousWeek();
|
||||
}
|
||||
});
|
||||
|
||||
function updateColumnsWidth() {
|
||||
const minWidth = $slider.css('--min-column-width');
|
||||
const availableWidth = $weekList[0].offsetWidth;
|
||||
let columnsWidth = availableWidth < minWidth ? availableWidth : availableWidth / Math.floor(availableWidth / minWidth);
|
||||
$slider.css('grid-template-columns', `repeat(53, ${columnsWidth}px)`);
|
||||
|
||||
if($selectedWeek) {
|
||||
// Update slider offset to bring it at the new position of the selectedWeek
|
||||
setCurrentWeek($selectedWeek, false);
|
||||
}
|
||||
}
|
||||
|
||||
function hideEmptyDays() {
|
||||
let nbRows = 8;
|
||||
for(let i = 0; i < 7; ++i) {
|
||||
const $days = $(prefix + `--day-item[data-weekday=${i}]`, $widget);
|
||||
const $activities = $(prefix + '--activity-item', $days);
|
||||
if(!$activities.length) {
|
||||
$days.css('display', 'none');
|
||||
nbRows -= 1;
|
||||
}
|
||||
|
||||
$slider.css('grid-template-rows', `repeat(${nbRows}, auto`);
|
||||
}
|
||||
}
|
||||
|
||||
hideEmptyDays();
|
||||
new ResizeObserver(updateColumnsWidth).observe($weekList[0]);
|
||||
addEventListener('resize', updateColumnsWidth);
|
||||
|
||||
refresh_week_classes();
|
||||
var observer = new MutationObserver(refresh_week_classes);
|
||||
$('.comment-field').each(function(idx, elem) {
|
||||
observer.observe(elem, {attributes: true, childList: true})
|
||||
});
|
||||
}
|
||||
|
||||
$('.template-famille-reservations-par-semaine .previous-week').on('click', function() {
|
||||
var $prev = $('li.shown').prev();
|
||||
if ($prev.length) { $('li.shown').removeClass('shown'); $prev.addClass('shown'); }
|
||||
refresh_week_classes();
|
||||
return false;
|
||||
});
|
||||
$('.template-famille-reservations-par-semaine .next-week').on('click', function() {
|
||||
var $next = $('li.shown').next();
|
||||
if ($next.length) { $('li.shown').removeClass('shown'); $next.addClass('shown'); }
|
||||
refresh_week_classes();
|
||||
return false;
|
||||
});
|
||||
$('.template-famille-reservations-par-semaine li.day-title').each(function(idx, elem) {
|
||||
/* hide empty days */
|
||||
var $next = $(elem).next();
|
||||
if ($next.length == 0 || $next.is('.day-title')) {
|
||||
$(elem).hide();
|
||||
}
|
||||
});
|
||||
|
||||
initAgendaWidget($('.template-famille-reservations-par-semaine'), '.template-famille-reservations-par-semaine');
|
||||
|
||||
|
||||
/* check overlaps */
|
||||
$('.template-famille-reservations-par-semaine input').on('change', function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$(this).parents('ul').find("input[data-overlaps~='"+$(this).data('event-id')+"']").prop('checked', false);
|
||||
$(this).parents(".template-famille-reservations-par-semaine--day-item").find("input[data-overlaps~='"+$(this).data('event-id')+"']").prop('checked', false);
|
||||
}
|
||||
});
|
||||
$('.template-famille-reservations-par-semaine input:disabled').each(function(index) {
|
||||
if ($(this).attr('checked')) {
|
||||
$(this).parents('ul').find("input[data-overlaps~='"+$(this).data('event-id')+"']").prop('disabled', true);
|
||||
$(this).parents(".template-famille-reservations-par-semaine--day-item").find("input[data-overlaps~='"+$(this).data('event-id')+"']").prop('disabled', true);
|
||||
}
|
||||
});
|
||||
/* init first week shown */
|
||||
var $cell = $('.template-famille-reservations-par-semaine');
|
||||
$cell.find('li').removeClass('shown');
|
||||
if ($('li.day-title.current', $cell).length) {
|
||||
$('li.day-title.current', $cell).parents('li.week').addClass('shown');
|
||||
} else {
|
||||
$('li', $cell).first().addClass('shown');
|
||||
}
|
||||
|
||||
refresh_week_classes();
|
||||
|
||||
var observer = new MutationObserver(refresh_week_classes);
|
||||
$('.comment-field').each(function(idx, elem) {
|
||||
observer.observe(elem, {attributes: true, childList: true})
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue