forked from ScoDoc/ScoDoc
296 lines
11 KiB
Django/Jinja
296 lines
11 KiB
Django/Jinja
{% extends "sco_page.j2" %}
|
|
{% import 'wtf.j2' as wtf %}
|
|
|
|
{% block styles %}
|
|
{{super()}}
|
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/tui.calendar/toastui-calendar.min.css"/>
|
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.css"/>
|
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/edt.css">
|
|
{% endblock %}
|
|
|
|
|
|
{% block app_content %}
|
|
|
|
<div class="tab-content">
|
|
<h2>Expérimental: emploi du temps</h2>
|
|
|
|
{{ form_groups_choice|safe }}
|
|
|
|
<div class="dropdown">
|
|
<button class="dropbtn">Semaine</button>
|
|
<div class="dropdown-content">
|
|
<ul>
|
|
{% for v in views_names %}
|
|
<li><a href="#" data-view="{{v}}">{{views_names[v]}}</a></li>
|
|
{% endfor %}
|
|
<li>
|
|
<label>
|
|
<input type="checkbox" id="showModulesTitles"
|
|
{{ "checked" if show_modules_titles else "" }}
|
|
>
|
|
noms des modules
|
|
</label>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<form id="calendar_control_form" method="GET">
|
|
<input type="hidden" name="current_date" value="{{current_date}}">
|
|
<input type="hidden" name="show_modules_titles" value="{{ 1 if show_modules_titles else 0 }}">
|
|
<input type="submit" value="Apply Changes" hidden>
|
|
</div>
|
|
|
|
<div>
|
|
<span id="menu-navi">
|
|
<button type="button" class="btn btn-default btn-sm move-today"
|
|
data-action="move-today">Aujourd'hui</button>
|
|
<button type="button" class="btn btn-default btn-sm move-day" data-action="move-prev">
|
|
<i class="calendar-icon ic-arrow-line-left" data-action="move-prev"><</i>
|
|
</button>
|
|
<button type="button" class="btn btn-default btn-sm move-day" data-action="move-next">
|
|
<i class="calendar-icon ic-arrow-line-right" data-action="move-next">></i>
|
|
</button>
|
|
</span>
|
|
<span id="renderRange" class="render-range"></span>
|
|
<span id="cal_warning">Attention: dates en dehors de ce semestre !</span>
|
|
</div>
|
|
<div id="formsemestre-calendar" style="height: calc(100vh - 180px);"></div>
|
|
|
|
<div class="help">
|
|
<ul>
|
|
<li>Les heures sont toujours affichées dans le fuseau horaire du serveur,
|
|
qui est en principe celui des étudiants.
|
|
</li>
|
|
<li>Si vous filtrez par groupe, les évènements dont le groupe n'est pas reconnu seront affichés.
|
|
</li>
|
|
{% if formsemestre.can_be_edited_by(current_user) %}
|
|
<li><a class="stdlink" href="{{
|
|
url_for('notes.formsemestre_edt_help_config',
|
|
scodoc_dept=g.scodoc_dept, formsemestre_id= formsemestre.id)
|
|
}}">Aide à la configuration de l'emploi du temps</a>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock app_content %}
|
|
|
|
{% block scripts %}
|
|
{{ super() }}
|
|
<script src="{{scu.STATIC_DIR}}/libjs/bootstrap-multiselect-1.1.2/bootstrap-multiselect.min.js"></script>
|
|
<script src="{{scu.STATIC_DIR}}/libjs/purl.js"></script>
|
|
<script src="{{scu.STATIC_DIR}}/libjs/tui.calendar/toastui-calendar.min.js"></script>
|
|
<script src="{{scu.STATIC_DIR}}/js/groups_view.js"></script>
|
|
<script>
|
|
let hm_formatter = new Intl.DateTimeFormat('default', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false
|
|
});
|
|
|
|
function getDataAction(target) {
|
|
return target.dataset ? target.dataset.action : target.getAttribute('data-action');
|
|
}
|
|
|
|
function getNextDayISODate(isoDate) {
|
|
// Parse the ISO date string into a Date object
|
|
const date = new Date(isoDate);
|
|
|
|
// Add one day
|
|
date.setDate(date.getDate() + 1);
|
|
|
|
// Convert back to ISO date string (YYYY-MM-DD)
|
|
return date.toISOString().split('T')[0];
|
|
}
|
|
|
|
var calendar;
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.getElementById('menu-navi').addEventListener('click', onClickNavi);
|
|
const Calendar = tui.Calendar;
|
|
const container = document.getElementById('formsemestre-calendar');
|
|
const options = {
|
|
defaultView: '{{view}}',
|
|
calendars: [
|
|
{
|
|
id: 'cal1',
|
|
name: 'Personal',
|
|
backgroundColor: '#03bd9e',
|
|
borderColor: 'white',
|
|
},
|
|
],
|
|
isReadOnly: true,
|
|
// timezone: { zones: [ { timezoneName: 'Europe/Paris' } ] },
|
|
template: {
|
|
// ce template nous permet d'avoir du HTML dans le title de l'event
|
|
time: function(event) {
|
|
const date_start = new Date(event.start);
|
|
const start = hm_formatter.format(date_start);
|
|
return `<strong>${start}</strong> <span>${event.title}</span> <div class="raw-event">${event.raw}</div>`;
|
|
},
|
|
},
|
|
timezone: {
|
|
zones: [
|
|
{
|
|
timezoneName: 'CET', // TODO récupérer timezone serveur
|
|
},
|
|
],
|
|
},
|
|
usageStatistics: false,
|
|
week: {
|
|
dayNames: [ "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
|
|
eventView: ['time'],
|
|
hourStart: {{ hour_start }},
|
|
hourEnd: {{ hour_end }},
|
|
showNowIndicator: true,
|
|
startDayOfWeek: 1,
|
|
taskView: false,
|
|
useDetailPopup:false, // on va pouvoir placer les liens scodoc
|
|
workweek: true, // TODO voir samedi travaillé
|
|
},
|
|
};
|
|
|
|
calendar = new Calendar(container, options);
|
|
|
|
fetch(`${SCO_URL}../api/formsemestre/{{formsemestre.id}}/edt?{{groups_query_args|safe}}&show_modules_titles={{show_modules_titles}}`)
|
|
.then(r=>{return r.json()})
|
|
.then(events=>{
|
|
if (typeof events == 'string') {
|
|
// error !
|
|
alert("error: " + events)
|
|
} else {
|
|
calendar.createEvents(events);
|
|
}
|
|
});
|
|
|
|
{% if current_date %}
|
|
// we need to add one day because our weeks are starting on Monday
|
|
calendar.setDate( getNextDayISODate("{{current_date}}") );
|
|
{% endif %}
|
|
changeCalendarDate();
|
|
|
|
function formatDate(date) {
|
|
let year = date.getFullYear();
|
|
let month = (date.getMonth() + 1).toString().padStart(2, '0'); // Months are zero-indexed in JavaScript
|
|
let day = date.getDate().toString().padStart(2, '0');
|
|
return `${day}/${month}/${year}`;
|
|
}
|
|
|
|
function setRenderRangeText() {
|
|
var renderRange = document.getElementById('renderRange');
|
|
var options = calendar.getOptions();
|
|
var viewName = calendar.getViewName();
|
|
var html = [];
|
|
if (viewName === 'day') {
|
|
html.push(calendar.getDate().toDate().toLocaleString('fr-Fr', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'}));
|
|
} else if (viewName === 'month' &&
|
|
(!options.month.visibleWeeksCount || options.month.visibleWeeksCount > 4)) {
|
|
html.push(
|
|
calendar.getDate().toDate().toLocaleString('fr-Fr', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
}));
|
|
} else {
|
|
html.push(formatDate(calendar.getDateRangeStart()));
|
|
html.push(' - ');
|
|
html.push(formatDate(calendar.getDateRangeEnd()));
|
|
}
|
|
renderRange.innerHTML = html.join('');
|
|
}
|
|
function onClickNavi(e) {
|
|
var action = getDataAction(e.target);
|
|
|
|
switch (action) {
|
|
case 'move-prev':
|
|
calendar.prev();
|
|
break;
|
|
case 'move-next':
|
|
calendar.next();
|
|
break;
|
|
case 'move-today':
|
|
calendar.today();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// setSchedules();
|
|
changeCalendarDate();
|
|
}
|
|
// Update current URL when date change (newDate=ISO string)
|
|
function updateParametersInUrl(newParams) {
|
|
// Parse the current URL
|
|
const currentUrl = new URL(window.location.href);
|
|
|
|
// Access and modify the search parameters
|
|
const searchParams = currentUrl.searchParams;
|
|
Object.entries(newParams).forEach(([key, value]) => {
|
|
searchParams.set(key, value);
|
|
});
|
|
|
|
// Create the new URL
|
|
const newUrl = `${currentUrl.origin}${currentUrl.pathname}?${searchParams.toString()}`;
|
|
|
|
// Update the URL without reloading the page
|
|
window.history.pushState({ path: newUrl }, '', newUrl);
|
|
}
|
|
// Update "current" date (URL and title)
|
|
function changeCalendarDate() {
|
|
setRenderRangeText();
|
|
// current calendar date, ISO, without time
|
|
const iso_date_start = calendar.getDateRangeStart().toDate().toISOString().split('T')[0];
|
|
const iso_date_end = calendar.getDateRangeEnd().toDate().toISOString().split('T')[0];
|
|
const cal_warning = document.querySelector('#cal_warning');
|
|
updateParametersInUrl( { current_date: iso_date_start } );
|
|
calendar_control_form.current_date.value = iso_date_start;
|
|
if ((iso_date_start > "{{ formsemestre.date_fin.isoformat() }}")
|
|
|| (iso_date_end < "{{ formsemestre.date_debut.isoformat() }}")) {
|
|
cal_warning.style.display = 'inline-block';
|
|
} else {
|
|
cal_warning.style.display = 'none';
|
|
}
|
|
}
|
|
// View menu
|
|
const dropdown = document.querySelector('.dropdown');
|
|
const dropbtn = document.querySelector('.dropbtn');
|
|
const dropdownContent = document.querySelector('.dropdown-content');
|
|
dropbtn.textContent = "{{views_names[view]}}";
|
|
|
|
dropbtn.addEventListener('click', function(event) {
|
|
dropdownContent.style.display = dropdownContent.style.display === 'block' ? 'none' : 'block';
|
|
event.stopPropagation();
|
|
});
|
|
|
|
document.querySelectorAll('.dropdown-content a').forEach(item => {
|
|
item.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const selectedText = this.textContent;
|
|
const selectedView = this.getAttribute('data-view');
|
|
calendar.changeView(selectedView); // Change the calendar view
|
|
updateParametersInUrl( { view : selectedView } );
|
|
setRenderRangeText();
|
|
dropbtn.textContent = selectedText; // Update the button text
|
|
dropdownContent.style.display = 'none';
|
|
});
|
|
});
|
|
|
|
const showModulesTitlesCheckbox = document.getElementById('showModulesTitles');
|
|
showModulesTitlesCheckbox.addEventListener('change', function() {
|
|
calendar_control_form.show_modules_titles.value = (calendar_control_form.show_modules_titles.value=="1") ? "0" : "1";
|
|
calendar_control_form.submit();
|
|
});
|
|
|
|
// Close dropdown when clicking outside
|
|
window.addEventListener('click', function() {
|
|
if (dropdownContent.style.display === 'block') {
|
|
dropdownContent.style.display = 'none';
|
|
}
|
|
});
|
|
});
|
|
|
|
</script>
|
|
{% endblock scripts %}
|