import { MelEnumerable } from '../../../mel_metapage/js/lib/classes/enum.js';
import { FramesManager } from '../../../mel_metapage/js/lib/classes/frame_manager.js';
import { EMPTY_STRING } from '../../../mel_metapage/js/lib/constants/constants.js';
import { BnumConnector } from '../../../mel_metapage/js/lib/helpers/bnum_connections/bnum_connections.js';
import { isNullOrUndefined } from '../../../mel_metapage/js/lib/mel.js';
import { MelObject } from '../../../mel_metapage/js/lib/mel_object.js';
import { Mel_Promise } from '../../../mel_metapage/js/lib/mel_promise.js';
import { connectors } from './connectors.js';
export { IndexWorkspace };
/**
* Contient les classes, énumérations et constantes utile pour l'affichage et le fonctionnement de la page d'index des espaces de travail.
* @module Workspace/Index
* @local EVisuMode
* @local EMode
* @local IndexWorkspace
*/
//#region enums
/**
* Liste des modes de visualisations
* @enum {string}
* @package
*/
const EVisuMode = {
/**
* Les espaces seront représenter sous forme de cards
* @type {string}
* @constant
* @default 'cards'
*/
cards: 'cards',
/**
* Les espaces seront représenter sous forme de liste
* @type {string}
* @constant
* @default 'list'
*/
list: 'list',
};
/**
* Liste des différents type de d'onglets
* @enum {string}
* @package
*/
const EMode = {
/**
* Onglet qui contient les espaces de l'utilisateur
* @type {string}
* @constant
* @default 'subscribed'
*/
subscribed: 'subscribed',
/**
* Onglet qui contient les espaces archivés de l'utilisateur
* @type {string}
* @constant
* @default 'archived'
*/
archived: 'archived',
/**
* Onglet qui contient les espaces publics
* @type {string}
* @constant
* @default 'publics'
*/
publics: 'publics',
};
//#endregion
//#region constants
/**
* Texte de l'onglet "Mes espaces"
* @type {string}
* @constant
* @package
*/
const subscribed = MelObject.Empty().gettext(EMode.subscribed, 'mel_workspace');
/**
* Texte de l'onglet "Publics"
* @type {string}
* @constant
* @package
*/
const archived = MelObject.Empty().gettext(EMode.archived, 'mel_workspace');
/**
* Texte de l'onglet "Archivés"
* @type {string}
* @constant
* @package
*/
const publics = MelObject.Empty().gettext(EMode.publics, 'mel_workspace');
/**
* Si le système d'overflow est actif ou non pour les paneaux
* @default true
* @type {boolean}
* @constant
* @package
*/
const OVERFLOW_ENABLED = true;
/**
* Valeur du display de la div qui contient le panel
* @default 'var(--workspace-panel-overflow-system-display, block)'
* @type {string}
* @constant
* @package
*/
const OVERFLOW_CSS_DISPLAY =
'var(--workspace-panel-overflow-system-display, block)';
/**
* Valeur de la prop' overflow de la div qui contient le panel
* @default 'var(--workspace-panel-overflow-system, auto)'
* @type {string}
* @constant
* @package
*/
const OVERFLOW_CSS_PROP = 'var(--workspace-panel-overflow-system, auto)';
//#endregion
/**
* @class
* @classdesc Actions de l'index de la tâche "workspace"
* @extends MelObject
*/
class IndexWorkspace extends MelObject {
/**
* Constructeur de la classe.
* Doit être appeler par le php.
*/
constructor() {
super();
this.#_main();
}
//#region init and setup
/**
* Button de passage en mode "cards"
* @private
* @returns {external:jQuery}
*/
get #$btnBlock() {
return $('#mode-block');
}
/**
* Bouton de passage en mode "liste"
* @private
* @returns {external:jQuery}
*/
get #$btnList() {
return $('#mode-list');
}
/**
* Input de recherche
* @private
* @returns {external:jQuery}
*/
get #$inputSearch() {
return $('#wsp-search-input');
}
/**
* Bouton qui réinitialise la recherche
* @private
* @returns {external:jQuery}
*/
get #$btnResetSearch() {
return $('.reset-search');
}
/**
* Bouton de création d'un espace
* @private
* @returns {external:jQuery}
*/
get #$btnCreate() {
return $('.create-wsp-button');
}
/**
* Fonction qui contient les instructions principales
* @private
*/
#_main() {
if (!FramesManager.Instance.has_frame('stockage')) {
console.info(
'(!)[Workspace/Index] Chargement des documents en arrière plan...',
);
FramesManager.Instance.switch_frame('stockage', { changepage: false });
}
this._init_buttons_data();
this._set_listeners();
this._set_blocks_listeners();
//Gestion de l'overflow
if (OVERFLOW_ENABLED) {
$('.workspace-list')
.parent()
// .css('display', OVERFLOW_CSS_DISPLAY)
.css('overflow', OVERFLOW_CSS_PROP);
$(window).resize(this._on_resize.bind(this));
this._on_resize();
}
}
/**
* Assigne les listeners
* @package
*/
_set_listeners() {
this.#$btnBlock.on(
'api:pressed',
this._event_button_pressed.bind(this, EVisuMode.cards),
);
this.#$btnList.on(
'api:pressed',
this._event_button_pressed.bind(this, EVisuMode.list),
);
this.#$inputSearch.on('change', this._search.bind(this));
this.#$btnResetSearch.click(this._event_search_reset.bind(this));
this.#$btnCreate.click(() => {
top.m_mp_Create();
top.m_mp_createworkspace();
});
}
/**
* Initialise les boutons
* @returns {Promise<void>}
* @package
* @async
*/
async _init_buttons_data() {
await Mel_Promise.wait(
() => this.#$btnBlock.parent().find('[aria-pressed="true"]').length > 0,
);
this.#$btnBlock.parent().find('[aria-pressed="true"]').attr('tabindex', -1);
if (this.get_env('visu-mode') === EVisuMode.list) {
this.#$btnList.click();
}
}
/**
* Assigne le listener lié au changement de favoris aux bnum-workspace-block-item
* @package
*/
_set_blocks_listeners() {
$('bnum-workspace-block-item').on('api:favorite', () => {
this._reorder();
this._set_blocks_listeners();
if (FramesManager.Instance.has_frame('bureau')) {
FramesManager.Instance.get_frame('bureau', {
jquery: false,
}).contentWindow.location.reload();
}
});
}
/**
* Met la bonne taille aux div qui contiennent les espaces.
* @package
*/
_container_resize() {
const bar_pixel_correction = 30;
const header_panel = 15;
const constant = bar_pixel_correction;
let tab = null;
for (tab of $('bnum-tabs')) {
tab = $(tab);
const tabs = tab.find('[role="tablist"]').height(); //$('bnum-tabs [role="tablist"]').height();
const baseHeaderPannel = tab.find('.header-pannel').height(); //$('bnum-tabs .header-pannel').height();
const headerPannel = isNaN(baseHeaderPannel)
? 0
: baseHeaderPannel - header_panel;
// const headerHeight = $('.wsp-header').height();
const total = tab.height();
const result = total - tabs - headerPannel - constant;
if (this._container === true)
tab.find('.workspace-list').css('height', `${result}px`);
else
tab
.find('.workspace-list')
.css('height', EMPTY_STRING)
.parent()
.css('height', `${result}px`);
}
tab = null;
}
//#endregion
//#region base private functions
/**
* Réordonne les cards.<br/>
*
* /!\Uniquement pour les espaces de l'utilisateur.
* @package
*/
_reorder() {
const data = MelEnumerable.from(
$(
`[data-pannel-namespace="${EMode.subscribed}"] bnum-workspace-block-item`,
),
).select((x) => {
return {
html: x
.getInitHtml()
.replace(
'data-favorite',
`data-favorite="${x.isFavorite()}" data-old-favorite`,
),
isFavorite: x.isFavorite(),
date: x.edited(),
title: x.title(),
};
});
let $dest = $(
`[data-pannel-namespace="${EMode.subscribed}"] .workspace-list`,
);
const html = MelEnumerable.from(data)
.orderByDescending((x) => (x.isFavorite ? Infinity : x.date.valueOf()))
.then((x) => x.title)
.select((x) => x.html)
.join(EMPTY_STRING);
$dest.html(html);
$dest = null;
}
//#endregion
//#region search functions
/**
* Recherche dans les espaces de l'utilisateur
* @param {TabsElement} mainTabs Element principal
* @param {string} searchValue Valeur de la recherche
* @package
*/
_mine_search(mainTabs, searchValue) {
//Récuparéation des blocks
let arr = MelEnumerable.from(
mainTabs.currentPannel().find('bnum-workspace-block-item'),
)
.aggregate(
mainTabs.currentPannel('archived').find('bnum-workspace-block-item'),
)
.where((x) =>
x.title().toUpperCase().includes(searchValue.toUpperCase()),
);
/**
* Div de destination qui contient les clones des espaces
* @package
* @type {external:jQuery}
*/
let $dest = $('#search-pannel')[0].currentPannel();
for (const element of arr) {
element.getClone().appendTo($dest);
}
//Suppression des indésirables
$dest.find('bnum-icon').each((i, e) => {
e = $(e);
if (e.text().includes('keep')) e.remove();
});
//Libération de la mémoire
arr = null;
$dest = null;
}
/**
* Désactive la recherche et le bouton de réinitialisement de la recherche
* @package
*/
_search_busy() {
this._p_$disable(this.#$inputSearch);
this._p_$disable(this.#$btnResetSearch);
}
/**
* Active la recherche et le bouton de réinitialisement de la recherche
* @package
*/
_search_not_busy() {
this._p_$enable(this.#$inputSearch);
this._p_$enable(this.#$btnResetSearch);
}
/**
* Recherche dans les espaces publiques
* @param {string} searchValue Valeur de la recherche
* @async
* @return {Promise<void>}
* @package
*/
async _public_search(searchValue) {
/**
* Gestion du redimentionnement
* @type {boolean}
* @package
*/
this._container = true;
/**
* Div de destination des résultats
* @package
* @type {external:jQuery}
*/
let $dest = $('#search-pannel')[0].currentPannel();
//Ajout d'un loading
$dest.html(this.generate_loader('generatedsearchwsp', true).generate());
//On récupère les données ainsi que le nombre de page max
const promiseArr = await Promise.allSettled([
this._public_search_data(searchValue),
this._get_count_max(searchValue),
]);
const [result, count] = promiseArr.map((x) => x.value);
//Ajout des résultats
$dest.html(result);
//Gestion du scroll
let scroll = $('#search-pannel bnum-infinite-scroll-container')[0];
scroll.onscrolledtoend.push(async (e) => {
this._search_busy();
const data = await this._public_search_data(
searchValue,
e.post_data._page,
);
$(e.caller).append($(data));
this._search_not_busy();
});
scroll.setPageCountMax(count);
//Libération de la mémoire
$dest = null;
scroll = null;
}
/**
* Récupère le nombre de page max pour le scroll container
* @param {string} searchValue Valeur de la recherche
* @returns {Promise<number>}
* @async
* @package
*/
async _get_count_max(searchValue) {
const connector = connectors.publics_search_count;
let params = connector.needed;
params._search = searchValue;
return (
await BnumConnector.force_connect(connector, {
params,
default_return: 0,
})
).datas;
}
/**
* Récupère les données, par page, d'un résultat de recherche.
* @param {string} searchValue Valeur de la recherche
* @param {number} [page=1] Page que l'on souhaite charger
* @returns {Promise<string>} html
* @throws {Error} Si l'appèle au serveur crash
* @package
*/
async _public_search_data(searchValue, page = 1) {
const connector = connectors.publics_search;
let params = connector.needed;
params._search = searchValue;
params._page = page;
const data = await BnumConnector.connect(connector, {
params,
});
if (!data.has_error) {
return data.datas;
} else throw new Error(data.error);
}
//#endregion
//#region protected functions
/**
* Désactive un élément et le retourne
* @param {external:jQuery} $item Elément à désactiver
* @returns {external:jQuery}
* @protected
*/
_p_$disable($item) {
return $item.addClass('disabled').attr('disabled', 'disabled');
}
/**
* Active un élément et le retourne
* @param {external:jQuery} $item Elément à désactiver
* @returns {external:jQuery}
* @protected
*/
_p_$enable($item) {
return $item.removeClass('disabled').removeAttr('disabled');
}
//#endregion
//#region events functions
/**
* Appeller par le bouton de réinitialisation de la recherche.
* Vide la recherche puis focus celle-ci.
* @package
*/
_event_search_reset() {
this.#$inputSearch.val(EMPTY_STRING).change().focus();
}
/**
* Appeller par les boutons de changement de mode de visualisation.
* @param {EVisuMode} mode Nouveau mode de visualisation
* @param {Event} e Evènement
* @package
*/
_event_button_pressed(mode, e) {
var control = $('bnum-tabs');
const CLASS_MODE_LIST = 'mode-list';
BnumConnector.connect(connectors.set_visu_mode, {
params: { _mode: mode },
});
$(e.currentTarget).attr('tabindex', -1);
document
.querySelector(`#mode-${mode === EVisuMode.cards ? 'list' : 'block'}`)
.unpress()
.setAttribute('tabindex', 0);
if (mode === EVisuMode.cards) control.removeClass(CLASS_MODE_LIST);
else control.addClass(CLASS_MODE_LIST);
control = control.find('button.mel-tabheader.active').attr('aria-controls');
$(`#${control}`).focus();
control = null;
}
/**
* Appeller lorsque la fenêtre est redimensionnée
* @package
*/
_on_resize() {
$('.body').css(
'height',
`${$('#layout-content').height() - ($('.wsp-header').height() + 50)}px`,
);
this._container_resize();
}
/**
* Est appeller par la recherche
* @async
* @returns {Promise<void>}
* @package
*/
async _search() {
this._search_busy();
this._container = false;
const searchValue = $('#wsp-search-input').val();
if ($('#search-pannel').length > 0) $('#search-pannel').remove();
if (isNullOrUndefined(searchValue) || searchValue === EMPTY_STRING) {
$('#main-pannel').css('display', EMPTY_STRING);
$('.reset-search')
.attr('title', 'Entrez un texte dans la recherche')
.attr('disabled', 'disabled')
.addClass('disabled')
.children()
.first()
.text('search');
} else {
$('.reset-search')
.attr('title', 'Quitter la recherche')
.removeAttr('disabled')
.removeClass('disabled')
.children()
.first()
.text('close');
let mainTabs = $('bnum-tabs')[0];
if (mainTabs.currentTabText() === archived)
mainTabs.selectTab(EMode.subscribed);
$('#main-pannel').css('display', 'none');
if (!$('#search-pannel').length) {
let tab = document.createElement('bnum-tabs');
tab.setAttribute('data-navs', mainTabs.getCurrentTabId());
tab.setAttribute('data-ex-label', 'mel_workspace');
tab.setAttribute(
'data-description',
'Contient le résultat de la recherche',
);
tab.setAttribute('data-shadow', false);
tab.setAttribute('id', 'search-pannel');
let div = document.createElement(
mainTabs.currentTabText() === publics
? 'bnum-infinite-scroll-container'
: 'div',
);
div.classList.add('workspace-list', 'mel-focus');
div.setAttribute('data-linked-to', mainTabs.getCurrentTabId());
if (mainTabs.currentTabText() === publics)
div.setAttribute('data-pagecount', 0);
tab.appendChild(div);
$(mainTabs).parent().append(tab);
div = null;
tab = null;
}
$('#search-pannel .mel-tab-content').focus();
switch (mainTabs.currentTabText()) {
case subscribed:
case archived:
this._mine_search(mainTabs, searchValue);
break;
default:
this._public_search(searchValue);
break;
}
$('#search-pannel')
.find('.workspace-list')
.parent()
.css('overflow', 'auto');
}
this._container_resize();
this._search_not_busy();
}
//#endregion
}