import { MelEnumerable } from '../../../../mel_metapage/js/lib/classes/enum.js';
import {
EWebComponentMode,
HtmlCustomDataTag,
} from '../../../../mel_metapage/js/lib/html/JsHtml/CustomAttributes/js_html_base_web_elements.js';
import { isNullOrUndefined } from '../../../../mel_metapage/js/lib/mel.js';
import { BnumEvent } from '../../../../mel_metapage/js/lib/mel_events.js';
import { RenderEvent, ViewRender } from './events.js';
/**
* @typedef ResourceConfigObject
* @property {string} id
* @property {string} title
*/
const LICENSE_KEY = 'GPL-My-Project-Is-Open-Source';
export class FullCalendarElement extends HtmlCustomDataTag {
constructor() {
super({ mode: EWebComponentMode.div });
this.onsourcerequested = new BnumEvent();
this.oneventrender = new BnumEvent();
this.onresourcerender = new BnumEvent();
this.ondatechanged = new BnumEvent();
this.ondayrender = new BnumEvent();
this.onallloaded = new BnumEvent();
this.onviewchanged = new BnumEvent();
this._loaded = [];
this._config = {};
this.oneventrender.push((...args) => {
const [obj, node] = args;
this.dispatchEvent(new RenderEvent('event', this, obj, node));
});
this.onresourcerender.push((...args) => {
const [obj, node] = args;
this.dispatchEvent(new RenderEvent('resource', this, obj, node));
});
this.onviewchanged.push((view, node) => {
this.dispatchEvent(new ViewRender(view, node, this));
});
this.ondayrender.push((date, cell) => {
this.dispatchEvent(
new CustomEvent('api:fc.day.render', { detail: { date, cell } }),
);
});
this.licenseKey = LICENSE_KEY;
this.calendar = null;
}
get eventsSource() {
return this._p_get_data('sources')
?.split?.(',')
?.map?.((x) => x.trim());
}
/**
* @type {?ResourceConfigObject[]}
*/
get resourceSources() {
let data = null;
//Vérifie que l'on veut des ressources
if ([true, 'true'].includes(this._p_get_data('have-resources'))) {
data = this._p_get_data('resources');
//Si les ressources n'ont pas déjà été mises en mémoires
if (!data) {
let srcs = [];
//On cherche les ressources puis on les récupères
let querry = this.querySelectorAll('fullcalendar-resource');
let element;
for (element of querry) {
srcs.push({ id: element.srcId, title: element.srcTitle });
element.remove();
element = null;
}
//On sauvegarde
this._p_save_into_data('resources', srcs);
data = srcs;
}
}
return data;
}
get defaultView() {
return this._p_get_data('default-view');
}
get size() {
return new StSize(
this._p_get_data('size-width'),
this._p_get_data('size-height'),
);
}
get firstHour() {
const tmp = +this._p_get_data('first-hour');
return isNaN(tmp) ? null : tmp;
}
get scrollTime() {
return (
this._p_get_data('scroll-time') ||
(!isNullOrUndefined(this.firstHour)
? `${this.firstHour < 10 ? `0${this.firstHour}` : this.firstHour}:00`
: null)
);
}
get slotDuration() {
let type = null;
switch (this._p_get_data('duration-type')?.toLocaleLowerCase?.()) {
case 'minutes':
case 'minute':
case 'min':
case 'm':
type = SlotDuration.EType.minutes;
break;
default:
break;
}
return type
? new SlotDuration(type, this._p_get_data('duration-time') || 60)
: null;
}
get locale() {
return this._p_get_data('locale');
}
get axisFormat() {
return this._p_get_data('axis-format');
}
get slotLabelFormat() {
return this._p_get_data('slot-label-format');
}
get startRendering() {
return ['true', true, '1', 1].includes(this._p_get_data('start'));
}
get date() {
return moment(this.calendar.getDate());
}
set date(val) {
this.calendar.gotoDate(val.toDate ? val.toDate() : val);
this.ondatechanged.call(moment(val), this);
}
get slotSize() {
const size = this._p_get_data('slot-size');
return isNullOrUndefined(size) ? null : +size;
}
_p_main() {
super._p_main();
let config = {
schedulerLicenseKey: this.licenseKey,
resourceRender: this.onresourcerender.call.bind(this.onresourcerender),
eventRender: this.oneventrender.call.bind(this.oneventrender),
dayRender: this.ondayrender.call.bind(this.ondayrender),
slotWidth: 30,
};
if (!isNullOrUndefined(this.slotSize)) config.slotSize = this.slotSize;
if (this.resourceSources) config.resources = this.resourceSources;
if (this.defaultView) config.defaultView = this.defaultView;
if (this.size?.heigth) config.height = this.size.heigth;
if (this.size?.width) config.width = this.size.width;
if (this.firstHour) config.firstHour = this.firstHour;
if (this.scrollTime) config.scrollTime = this.scrollTime;
if (this.slotDuration) config.slotLabelInterval = this.slotDuration.get();
if (this.locale) config.locale = this.locale;
if (this.axisFormat) config.axisFormat = this.axisFormat;
if (this.slotLabelFormat) config.slotLabelFormat = this.slotLabelFormat;
if (this.eventsSource && this.eventsSource.length > 0) {
config.eventSources = [];
for (const source of this.eventsSource) {
config.eventSources.push({
events: async function (
id,
getCallback,
start,
end,
timezone,
callback,
) {
try {
let events = [];
const array = await getCallback({
caller: this,
id,
start,
end,
timezone,
});
if (array) {
let flat = MelEnumerable.from([array]).flat();
if (flat.any()) events.push(...flat);
}
// console.log(id, events);
callback(events);
// this._loaded.push(true);
// if (this._loaded.length >= this.eventsSource.length) {
// this.onallloaded.call({
// caller: this,
// });
// this._loaded.length = 0;
//}
} catch (error) {
debugger;
console.error(error);
}
}.bind(
this,
source,
this.onsourcerequested.call.bind(this.onsourcerequested),
),
id: source,
});
}
}
if (Object.keys(this._config).length > 0) {
for (const key of Object.keys(this._config)) {
config[key] = this._config[key];
}
}
this._config = config;
let calendar = new FullCalendar.Calendar($(this), config);
this.onviewchanged.add('start', () => {
this.onviewchanged.remove('start');
setTimeout(() => {
const date = `${this.date.format('YYYY-MM-DD')}T${this.scrollTime ? (this.scrollTime.split(':').length === 2 ? `${this.scrollTime}:00` : this.scrollTime) : '09:00:00'}`;
this.$.find('.fc-scroller').animate(
{
scrollLeft: $(`[data-date="${date}"]`).position().left, // Scroll to 01:00 pm
},
1000,
);
}, 10);
});
calendar.on('eventAfterAllRender', (...args) => {
this.onallloaded.call(this, ...args);
});
calendar.on('viewRender', (...args) => {
if (this.calendar.getView().slotWidth === 1) this.forceRerender();
else this.onviewchanged.call(...args);
});
if (this.startRendering) calendar.render();
this.calendar = calendar;
}
addConfig(name, value) {
this._config[name] = value;
return this;
}
prev() {
this.calendar.prev();
this.ondatechanged.call(this.date, this);
}
next() {
this.calendar.next();
this.ondatechanged.call(this.date, this);
}
today() {
this.calendar.today();
this.ondatechanged.call(this.date, this);
}
render() {
this.calendar.render();
}
forceRerender() {
this.calendar.destroy();
let calendar = new FullCalendar.Calendar($(this), this._config);
calendar.on('eventAfterAllRender', (...args) => {
this.onallloaded.call(this, ...args);
});
calendar.on('viewRender', (...args) => {
this.onviewchanged.call(...args);
});
calendar.render();
this.calendar = calendar;
}
fetch() {
this.calendar.refetchEvents();
}
/**
*
* @param {string | string[]} sources
* @param {Object} [param1={}]
* @returns {FullCalendarElement}
* @static
*/
static CreateNode(
sources,
{
resources = null,
defaultView = null,
height = null,
width = null,
firstHour = null,
scrollTime = null,
slotDurationType = null,
slotDurationTime = null,
locale = 'fr',
axisFormat = null,
slotLabelFormat = null,
sourcesCallback = null,
render = false,
slotSize = null,
} = {},
) {
/**
* @type {FullCalendarElement}
*/
let node = document.createElement('full-calendar');
if (typeof sources !== 'string' && Array.isArray(sources))
sources = sources.join(',');
node.setAttribute('data-sources', sources);
if (!isNullOrUndefined(slotSize))
node.setAttribute('data-slot-size', slotSize);
if (defaultView) node.setAttribute('data-default-view', defaultView);
if (height) node.setAttribute('data-size-height', height);
if (width) node.setAttribute('data-size-width', width);
if (firstHour) node.setAttribute('data-first-hour', firstHour);
if (scrollTime) node.setAttribute('data-scroll-time', scrollTime);
if (slotDurationType)
node.setAttribute('data-duration-type', slotDurationType);
if (slotDurationTime)
node.setAttribute('data-duration-time', slotDurationTime);
if (axisFormat) node.setAttribute('data-axis-format', axisFormat);
if (slotLabelFormat)
node.setAttribute('data-slot-label-format', slotLabelFormat);
if (locale) node.setAttribute('data-locale', locale);
if (render) node.setAttribute('data-start', true);
if (sourcesCallback) node.onsourcerequested.push(sourcesCallback);
if (resources) {
node.setAttribute('data-have-resources', true);
let rcs = null;
for (const element of resources) {
rcs = FullCalendarResourceElement.CreateNode(element.id, element.title);
node.appendChild(rcs);
rcs = null;
}
}
return node;
}
}
class StSize {
#width;
#height;
constructor(w, h) {
this.#width = w;
this.#height = h;
}
get width() {
return +this.#width || null;
}
get heigth() {
return +this.#height || null;
}
}
class SlotDuration {
#type;
#time;
constructor(type, time) {
this.#type = type;
this.#time = time;
}
get() {
let type = null;
switch (this.#type) {
case SlotDuration.EType.minutes:
type = 'minutes';
break;
default:
throw new Error('Type non défini');
}
let config = {};
config[type] = +this.#time;
return config;
}
}
SlotDuration.EType = {
minutes: Symbol(),
};
{
const TAG = 'full-calendar';
if (!customElements.get(TAG)) customElements.define(TAG, FullCalendarElement);
}
export class FullCalendarResourceElement extends HtmlCustomDataTag {
constructor() {
super();
}
get srcId() {
return this._p_get_data('src-id');
}
get srcTitle() {
return this._p_get_data('src-title');
}
/**
*
* @param {*} id
* @param {*} title
* @returns {FullCalendarResourceElement}
*/
static CreateNode(id, title) {
let node = document.createElement('fullcalendar-resource');
node.setAttribute('data-src-id', id);
node.setAttribute('data-src-title', title);
return node;
}
}
{
const TAG = 'fullcalendar-resource';
if (!customElements.get(TAG))
customElements.define(TAG, FullCalendarResourceElement);
}