Skip to content

Commit

Permalink
Extract monthNavigator custom element
Browse files Browse the repository at this point in the history
  • Loading branch information
florimondmanca committed Dec 19, 2023
1 parent ef5a35a commit 3fbaa00
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ export class FairCalendarController {
@Query() dto: FairCalendarControllerDTO,
@LoggedUser() user: User
) {
const date =
dto.month !== undefined && dto.year !== undefined
? new Date(dto.year, dto.month, 15)
: new Date();
let date = new Date();

if (dto.year !== undefined && dto.month !== undefined) {
date = new Date(dto.year, dto.month - 1, 15);
}

const userId = dto.userId ? dto.userId : user['id'];

Expand Down Expand Up @@ -101,7 +102,7 @@ export class FairCalendarController {
overviewTable,
fullCalendarEvents,
date,
currentMonth: date.getMonth(),
currentMonth: date.getMonth() + 1,
currentYear: date.getFullYear(),
userId
};
Expand Down
77 changes: 0 additions & 77 deletions src/assets/customElements/fairCalendarFiltersForm.js

This file was deleted.

4 changes: 2 additions & 2 deletions src/assets/customElements/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
import autoForm from './autoForm';
import clipboardButton from './clipboardButton';
import eventForm from './eventForm';
import fairCalendarFiltersForm from './fairCalendarFiltersForm';
import monthNavigator from './monthNavigator';
import navMenuButton from './navMenuButton';
import themeToggler from './themeToggler';

customElements.define('pc-auto-form', autoForm);
customElements.define('pc-clipboard-button', clipboardButton);
customElements.define('pc-event-form', eventForm);
customElements.define('pc-faircalendar-filters-form', fairCalendarFiltersForm);
customElements.define('pc-month-navigator', monthNavigator);
customElements.define('pc-nav-menu-button', navMenuButton);
customElements.define('pc-theme-toggler', themeToggler);
85 changes: 85 additions & 0 deletions src/assets/customElements/monthNavigator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// @ts-check
import { onParsed, waitForElement } from '../lib/customElements';

export default class extends HTMLElement {
/** @type {HTMLInputElement} */
#month;

/** @type {HTMLInputElement} */
#year;

connectedCallback() {
onParsed(() => {
const parent = /** @type {HTMLElement} */ (this.parentElement);

const findFields = /** @type {Promise<[HTMLInputElement, HTMLInputElement]>} */ (Promise.all(
[
waitForElement(this.dataset.monthTarget || '', parent, {
timeout: 3000
}),
waitForElement(this.dataset.yearTarget || '', parent, {
timeout: 3000
})
]
));

findFields.then(([month, year]) => {
// Assume month is 1 (January) to 12 (December)
this.#month = month;
this.#year = year;

const template = /** @type {HTMLTemplateElement} */ (this.querySelector(
'template'
));

this.appendChild(document.importNode(template.content, true));

const previousBtn = /** @type {HTMLButtonElement} */ (this.querySelector(
'button[data-previous]'
));

const todayBtn = /** @type {HTMLButtonElement} */ (this.querySelector(
'button[data-today]'
));

const nextBtn = /** @type {HTMLButtonElement} */ (this.querySelector(
'button[data-next]'
));

previousBtn.addEventListener('click', () => {
this._updateMonth(+month.value - 1);
});

todayBtn.addEventListener('click', () => {
const today = new Date();
month.value = (today.getMonth() + 1).toString();
year.value = today.getFullYear().toString();
// Trigger change on either field, but only once
year.dispatchEvent(new Event('change'));
});

nextBtn.addEventListener('click', () => {
this._updateMonth(+month.value + 1);
});
});
});
}

/**
* @param {number} month
*/
_updateMonth(month) {
if (month < 1) {
month += 12;
this.#year.value = (+this.#year.value - 1).toString();
}

if (month > 12) {
month -= 12;
this.#year.value = (+this.#year.value + 1).toString();
}

this.#month.value = month.toString();
this.#month.dispatchEvent(new Event('change'));
}
}
36 changes: 36 additions & 0 deletions src/assets/lib/customElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,39 @@
export function onParsed(cb) {
requestAnimationFrame(cb);
}

/**
* Wait until an element appears in the DOM.
* Credit: https://stackoverflow.com/a/61511955
* @param {string} selector
* @param {Element} root
* @param {{timeout?: number}} options
* @returns {Promise<Element>}
*/
export function waitForElement(selector, root, { timeout } = {}) {
return new Promise(resolve => {
let timeoutHandle;

if (timeout) {
timeoutHandle = setTimeout(
() => reject(`failed to find ${selector} after ${timeout} ms`),
timeout
);
}

if (document.querySelector(selector)) {
clearTimeout(timeoutHandle);
return resolve(document.querySelector(selector));
}

const observer = new MutationObserver(_mutations => {
if (document.querySelector(selector)) {
observer.disconnect();
clearTimeout(timeoutHandle);
resolve(document.querySelector(selector));
}
});

observer.observe(root, { childList: true, subtree: true });
});
}
20 changes: 20 additions & 0 deletions src/templates/macros/month_navigator.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% import 'macros/icons.njk' as icons %}

{% macro month_navigator(monthTarget, yearTarget) %}
<pc-month-navigator data-month-target="{{ monthTarget }}" data-year-target="{{ yearTarget }}">
<template>
<div class="pc-cluster" style="--cluster-align: stretch">
{# TODO: translations #}
<button type="button" data-previous class="pc-btn pc-btn--muted" title="Mois précédent">
{{ '<' }}
</button>
<button type="button" data-today class="pc-btn pc-btn--muted" title="Aujourd'hui">
{{ icons.calendar() }}
</button>
<button type="button" data-next class="pc-btn pc-btn--muted" title="Mois suivant">
{{ '>' }}
</button>
</div>
</template>
</pc-month-navigator>
{% endmacro %}
78 changes: 37 additions & 41 deletions src/templates/pages/faircalendar/_filters_form.njk
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
{% from 'macros/month_navigator.njk' import month_navigator %}

{% macro filters_form() %}
<pc-faircalendar-filters-form>
<form
method="GET"
action="{{ path('faircalendar_index') }}"
class="pc-cluster pc-gap"
style="--cluster-align: flex-end"
>
<template id="faircalendar-filters-form-navigation">
<div class="pc-cluster" style="--cluster-align: stretch">
<button id="previousBtn" type="button" class="pc-btn pc-btn--muted" title="Mois précédent">{{ '<' }}</button>
<button id="todayBtn" type="button" class="pc-btn pc-btn--muted" title="Aujourd'hui">
{{ icons.calendar() }}
</button>
<button id="nextBtn" type="button" class="pc-btn pc-btn--muted" title="Mois suivant">{{ '>' }}</button>
</div>
</template>
<div class="pc-cluster pc-gap" style="--cluster-align: flex-end">
{{ month_navigator(monthTarget='#month', yearTarget='#year') }}

<div class="pc-select-group pc-m" style="--m: 0">
<label class="pc-label" for="month">{{ 'faircalendar-filters-month-title'|trans }}</label>
<select name="month" id="month">
{% for month in range(12) %}
<option value="{{ month }}" {% if month == currentMonth %}selected{% endif %}>{{ month|longMonth|capitalize }}</option>
{% endfor %}
</select>
</div>
<div class="pc-input-group pc-m" style="--m: 0">
<label class="pc-label" for="year">{{ 'faircalendar-filters-year-title'|trans }}</label>
<input name="year" id="year" type="number" value="{{ currentYear }}">
</div>
<div class="pc-select-group pc-m" style="--m: 0">
<label class="pc-label" for="userId">{{ 'faircalendar-filters-userId-title'|trans }}</label>
<select name="userId" id="userId">
{% for user in users %}
<option value="{{ user.id }}" {% if user.id == userId %}selected{% endif %}>{{ user|fullName }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="pc-btn pc-btn--secondary">
{{ 'common-form-update'|trans }}
</button>
</form>
</pc-faircalendar-filters-form>
<pc-auto-form>
<form
method="GET"
action="{{ path('faircalendar_index') }}"
class="pc-cluster pc-gap"
style="--cluster-align: flex-end"
>
<div class="pc-select-group pc-m" style="--m: 0">
<label class="pc-label" for="month">{{ 'faircalendar-filters-month-title'|trans }}</label>
<select name="month" id="month">
{% for month in range(1, 13) %}
<option value="{{ month }}" {% if month == currentMonth %}selected{% endif %}>{{ (month - 1)|longMonth|capitalize }}</option>
{% endfor %}
</select>
</div>
<div class="pc-input-group pc-m" style="--m: 0">
<label class="pc-label" for="year">{{ 'faircalendar-filters-year-title'|trans }}</label>
<input name="year" id="year" type="number" value="{{ currentYear }}">
</div>
<div class="pc-select-group pc-m" style="--m: 0">
<label class="pc-label" for="userId">{{ 'faircalendar-filters-userId-title'|trans }}</label>
<select name="userId" id="userId">
{% for user in users %}
<option value="{{ user.id }}" {% if user.id == userId %}selected{% endif %}>{{ user|fullName }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="pc-btn pc-btn--secondary">
{{ 'common-form-update'|trans }}
</button>
</form>
</pc-auto-form>
</div>
{% endmacro %}
Loading

0 comments on commit 3fbaa00

Please sign in to comment.