/* eslint-disable no-shadow */
/**
* Met en pause une fonction asynchrone.
* @param {number} ms
*/
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
/**
* Vérifie si une fonction est asynchrone
* @param {Function} myFunction
* @returns {boolean}
*/
const isAsync = (myFunction) => myFunction.constructor.name === 'AsyncFunction';
/**
* Attend que la fonction soit vrai
* @param {Function} func
* @param {number} waitTime ms
*/
const wait = async function (func, waitTime = 500) {
while (isAsync(func) ? await func() : func()) {
await delay(waitTime);
}
};
const ping = async function (url, useSSL = true) {
// //let ip = url;
// var _that = this;
// let img = new Image();
// img.onload = function() {_that.ok = true;};
// img.onerror = function(e) {_that.ok = false; console.error(e);};
// //let start = new Date().getTime();
let ssl = useSSL ? 'https' : 'http';
// img.src = !url.includes("https") && !url.includes("http") ? (ssl + "://" + url) : url;
// console.log(img.src);
// let timer = setTimeout(function() { _that.ok = false;}, waitTime*1000);
// await wait(() => _that.ok === undefined);
// clearTimeout(timer)
// return _that.ok;
let ok;
try {
await $.ajax({
type: 'GET',
url:
!url.includes('https') && !url.includes('http')
? ssl + '://' + url
: url,
success: function (result) {
ok = true;
},
error: function (result) {
ok = false;
},
});
} catch (error) {
console.error(error);
ok = false;
}
return ok;
};
const mceToRcId = function (txt = '') {
return txt
.replaceAll('.', '_-P-_')
.replaceAll('@', "'_-A-_'")
.replaceAll('%', '_-C-_');
};
(() => {
function ureplacer(pmatch) {
var ret = '';
pmatch = pmatch.replace(/\,/g, '/');
var ix = pmatch.substr(1, pmatch.length - 2);
if (ix.length % 4 != 0)
ix = ix.padEnd(ix.length + 4 - (ix.length % 4), '=');
try {
var dx = atob(ix);
for (var j = 0; j < dx.length; j = j + 2) {
ret =
ret +
String.fromCharCode((dx.charCodeAt(j) << 8) + dx.charCodeAt(j + 1));
}
} catch (err) {
console.log(
'Error in decoding foldername IMAP UTF7, sending empty string back',
);
console.log(err);
ret = '';
}
return ret;
}
function breplacer(umatch) {
var bst = '';
for (var i = 0; i < umatch.length; i++) {
var f = umatch.charCodeAt(i);
bst = bst + String.fromCharCode(f >> 8) + String.fromCharCode(f & 255);
}
try {
bst = '&' + btoa(bst).replace(/\//g, ',').replace(/=+/, '') + '-';
} catch (err) {
console.log(
'Error in encoding foldername IMAP UTF7, sending empty string back',
);
console.log(err);
bst = '';
}
return bst;
}
function decode_imap_utf7(mstring) {
var stm = new RegExp(/(\&[A-Za-z0-9\+\,]+\-)/, 'g');
return mstring.replace(stm, ureplacer).replace('&-', '&');
}
function encode_imap_utf7(ustring) {
ustring = ustring.replace(/\/|\~|\\/g, '');
var vgm = new RegExp(/([^\x20-\x7e]+)/, 'g');
return ustring.replace('&', '&-').replace(vgm, breplacer);
}
function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
let expires = 'expires=' + d.toUTCString();
document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
}
window.decode_imap_utf7 = decode_imap_utf7;
window.melSetCookie = setCookie;
window.getCookie = (name) => {
return rcmail.get_cookie(name);
};
window.removeCookie = (name) => {
setCookie(name, '', -5);
};
})();
/**
* Lien du chargement des évènements d'un calendrier.
*/
const ev_calendar_url = '?_task=calendar&_action=load_events';
/**
* Liste des différents données constantes utile pour le plugin "mel_metapage".
*/
const mel_metapage = {
/**
* Liste des différents évènements.
*/
EventListeners: {
/**
* Lorsque le calendrier est mis à jours.
*/
calendar_updated: new EventListenerDatas('mel_metapage.calendar_updated'),
/**
* Lorsque les tâches sont mises à jours.
*/
tasks_updated: new EventListenerDatas('mel_metapage.tasks_updated'),
/**
* Lorsque les mails sont mis à jours.
*/
mails_updated: new EventListenerDatas('mel_metapage.mails_updated'),
/**
* Lorsque le stockage est mis à jours.
*/
wsp_stockage_updated: new EventListenerDatas(
'mel_metapage.wsp_stockage_updated',
),
workspaces_updated: new EventListenerDatas('workspace.updated'),
},
/**
* Différents clés de stockage local.
*/
Storage: {
unexist: Symbol('unexist'),
exists(val) {
return (val ?? this.unexist) !== this.unexist;
},
/**
*
* @returns {MelDataStore}
*/
_getDataStore() {
let self = (top ?? window).mel_metapage.Storage;
if (!self._getDataStore.datastoreobject) {
const current_user_key = `bnum.${rcmail.env.username}`;
self._getDataStore.datastoreobject = new MelDataStore(
current_user_key,
{},
);
if (rcmail.env.keep_login) {
const keys = Object.keys(localStorage);
for (let index = 0, len = keys.length; index < len; ++index) {
const key = keys[index];
if (key !== current_user_key && key.includes('bnum')) {
localStorage.removeItem(key);
}
}
}
}
return self._getDataStore.datastoreobject;
},
/**
* Récupère une donnée depuis le stockage local.
* @param {string} key Clé de la donnée à récupérer.
*/
get(key, _default = null) {
let self = mel_metapage.Storage;
try {
return self._getDataStore().get(key) ?? _default;
} catch (error) {
console.error(error);
return self.unexist;
}
},
/**
* Ajoute ou modifie une donnée dans le stockage local.
* @param {string} key Clé de la donnée pour la retrouver.
* @param {*} item Donnée à sauvegarder.
*/
set(key, item, stringify = true) {
this._getDataStore().set(key, item);
this.setStoreChange(key, item);
},
/**
* Supprime une donnée dans le stockage local.
* @param {string} key Clé de la donnée à supprimer.
*/
remove(key) {
this._getDataStore().remove(key);
this.setStoreChange(key, undefined);
},
setStoreChange(key, item) {
if ((top ?? window).rcmail !== undefined)
(top ?? window).rcmail.triggerEvent('storage.change', { key, item });
(top ?? window).$('iframe.mm-frame').each((i, e) => {
try {
e.contentWindow.rcmail.triggerEvent('storage.change', { key, item });
} catch (error) {}
});
},
getAppStorageSize() {
return this._getDataStore().getSize();
},
check(storage = null) {
if (storage === null) {
let items = [];
for (const key in mel_metapage.Storage) {
const element = mel_metapage.Storage[key];
if (element !== undefined) {
items.push(mel_metapage.Storage.check_day(key));
}
}
return {
items: items,
wait: async function () {
for (let index = 0; index < this.items.length; ++index) {
const element = this.items[index];
if (element.wait !== undefined) await element.wait();
}
},
};
} else {
const update_element = (update_key, day_key) => {
let item = {
wait: async () => {
return mel_metapage.Storage.get(update_key);
},
};
let update = false;
if (
!update &&
moment(mel_metapage.Storage.get(day_key)).format('DD/MM/YYYY') !==
moment().format('DD/MM/YYYY')
)
update = true;
if (!update && mel_metapage.Storage.get(update_key) === null)
update = true;
if (update) {
mel_metapage.Storage.remove(update_key);
workspaces.sync.PostToParent({
exec: 'rcmail.mel_metapage_fn.tasks_updated()',
child: false,
});
item.wait = async () => {
await wait(() => mel_metapage.Storage.get(update_key) === null);
return mel_metapage.Storage.get(update_key);
};
}
return item;
};
switch (storage) {
case mel_metapage.Storage.other_tasks:
case mel_metapage.Storage.tasks:
return update_element(
storage,
mel_metapage.Storage.last_task_update,
);
case mel_metapage.Storage.calendar_all_events:
case mel_metapage.Storage.calendar:
return update_element(
storage,
mel_metapage.Storage.last_calendar_update,
);
default:
return item;
}
}
},
/**
* Clé des données du calendrier.
*/
calendar_all_events: CONST_STORAGE_KEY_ALL_EVENTS,
calendar: 'mel_metapage.calendar',
calendar_by_days: 'mel_metapage.calendars.by_days',
calendars_number_wainting: 'mel_metapage.calendars.by_days.waiting',
/**
* Clé des données des tâches.
*/
tasks: 'mel_metapage.tasks',
other_tasks: 'mel_metapage.tasks.others',
other_tasks_count: 'mel_metapage.tasks.others.count',
/**
* Clé du nombre de mail non lus.
*/
mail: 'mel_metapage.mail.count',
wsp_mail: 'mel_metapage.wsp.mails',
last_calendar_update: 'mel_metapage.calendar.last_update_2',
last_task_update: 'mel_metapage.tasks.last_update',
ariane: 'ariane_datas',
wait_frame_loading: 'mel_metapage.wait_frame_loading',
wait_frame_waiting: 'waiting...',
wait_frame_loaded: 'loaded',
wait_call_loading: 'mel_metapage.call.loading',
color_mode: 'colorMode',
title_workspaces: 'workspaces.title',
},
/**
* Liste des symboles.
*/
Symbols: {
/**
* Symboles du plugin "My_Day".
*/
my_day: {
/**
* Symbole "Calendrier", est utilisé pour savoir si il faut mettre à jours uniquement les évènements ou non.
*/
calendar: Symbol('calendar'),
/**
* Symbole "Tâches", est utilisé pour savoir si il faut mettre à jours uniquement les tâches ou non.
*/
tasks: Symbol('tasks'),
},
nextcloud: {
folder: Symbol('folder'),
file: Symbol('file'),
},
navigator: {
firefox: Symbol('firefox'),
},
null: Symbol('null'),
},
/**
* Les différents Identifiants
*/
Ids: {
/**
* Ids pour le menu.
*/
menu: {
/**
* Id des différents badges du menu.
*/
badge: {
calendar: 'menu-badge-calendar',
tasks: 'menu-badge-tasks',
mail: 'menu-badge-mail',
ariane: 'menu-badge-ariane',
},
},
create: {
doc_input: 'generated-document-input-mel-metapage',
doc_input_ext: 'generated-document-input-mel-metapage-ext',
doc_input_hidden: 'generated-document-input-mel-metapage-hidden',
doc_input_path: 'generated-document-select-mel-metapage-path',
},
},
PopUp: {
/**
* Ouvre la popup de chat
* @returns
*/
open_ariane() {
if (rcmail.busy) return;
if (mel_metapage.PopUp.ariane === null) {
mel_metapage.PopUp.ariane = new ArianePopUp(ArianeButton.default());
rcmail.addEventListener('toggle-options-user', (show) => {
let $iframe =
mel_metapage.PopUp.ariane.ariane.card.body.card.find('iframe');
if (show.show === true) $iframe.css('z-index', '1');
else $iframe.css('z-index', '');
});
}
if (mel_metapage.PopUp.ariane.is_show === true)
mel_metapage.PopUp.ariane.hide();
else mel_metapage.PopUp.ariane.show();
},
ariane: null,
},
Other: {
webconf: {
private: '/group',
},
},
RCMAIL_Start: {
async ping_nextcloud() {
if (
rcmail.env.nextcloud_url !== undefined &&
rcmail.env.nextcloud_url !== null &&
rcmail.env.nextcloud_url !== ''
) {
rcmail.env.nextcloud_pinged = await ping(rcmail.env.nextcloud_url);
if (rcmail.env.nextcloud_pinged === false)
rcmail.env.nextcloud_pinged = await ping(
rcmail.env.nextcloud_url,
true,
);
}
},
},
Frames: {
max: 10,
lastFrames: [],
add(frame) {
if (parent !== window) return parent.mel_metapage.Frames.add(frame);
if (frame?.task === 'webconf') return this;
if (this.lastFrames.length + 1 > 5) this.lastFrames.pop();
this.lastFrames.push(frame);
return this;
},
reset() {
if (parent !== window) return parent.mel_metapage.Frames.reset();
this.lastFrames = [];
return this;
},
pop() {
if (parent !== window) return parent.mel_metapage.Frames.pop();
if (this.lastFrames.length === 0) return null;
return this.lastFrames.pop();
},
last(it = 0) {
if (parent !== window) return parent.mel_metapage.Frames.last(it);
if (this.lastFrames.length === 0) return null;
return this.lastFrames[this.lastFrames.length - 1 - it];
},
back(_default = 'home') {
if (parent !== window) return parent.mel_metapage.Frames.back(_default);
const unexist = mel_metapage.Storage.unexist;
let last = this.pop()?.task || _default;
if (last === unexist) last = _default;
return mel_metapage.Functions.change_frame(last, true, true).then(() => {
if ($('.menu-last-frame').hasClass('disabled')) {
m_mp_ChangeLasteFrameInfo();
}
});
},
create_frame(name, task, icon) {
return {
name,
task,
icon,
};
},
},
Functions: {
/**
* Copie un texte dans le press-papier
* @param {string} text Texte à copier
*/
copy(text) {
function copyOnClick(val) {
var tempInput = document.createElement('input');
tempInput.value = val;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
}
copyOnClick(text);
rcmail.display_message(
`${text} copier dans le presse-papier.`,
'confirmation',
);
return this;
},
/**
* Récupère les données du calendrier entre deux dates.
* @param {moment} start (moment) Début des évènements à récupérer
* @param {moment} end (moment) Fin des évènements à récupérer
*/
update_calendar(start, end) {
start = start.format('YYYY-MM-DDTHH:mm:ss');
end = end.format('YYYY-MM-DDTHH:mm:ss');
if (rcmail.env.ev_calendar_url === undefined)
rcmail.env.ev_calendar_url = ev_calendar_url;
return $.ajax({
// fonction permettant de faire de l'ajax
type: 'GET', // methode de transmission des données au fichier php
url:
rcmail.env.ev_calendar_url +
`&source=${mceToRcId(rcmail.env.username)}` +
'&start=' +
start +
'&end=' +
end, // url du fichier php
success: function (data) {
try {
let events = [];
data = JSON.parse(data);
data = Enumerable.from(data)
.where(
(x) =>
mel_metapage.Functions.check_if_date_is_okay(
x.start,
x.end,
start,
) ||
mel_metapage.Functions.check_if_date_is_okay(
x.start,
x.end,
end,
),
)
.toArray();
return data;
} catch (ex) {
console.error(ex);
rcmail.display_message(
'Une erreur est survenue lors de la synchronisation.',
'error',
);
}
},
error: function (xhr, ajaxOptions, thrownError) {
// Add these parameters to display the required response
console.error(xhr, ajaxOptions, thrownError);
rcmail.display_message(
'Une erreur est survenue lors de la synchronisation.',
'error',
);
},
});
},
/**
* Vérifie si un élement est valide ou si c'est un doublon ou une instance originale
* @param {JSON} element
* @param {Array<JSON>} events
* @param {boolean} test
* @returns {boolean|JSON} True si pas de problème | Evènement problématique
*/
check_if_calendar_valid(element, events, test = true) {
if (mceToRcId(rcmail.env.username) !== element.calendar) return false;
else {
if (element._instance !== undefined && test) {
for (let it = 0; it < events.length; it++) {
const event = events[it];
if (event.uid === element.uid && event._instance === undefined)
return event;
}
}
}
return true;
},
/**
* Vérifie si une date se trouve entre 2 dates
* @param {string|moment} sd
* @param {string|moment} ed
* @param {string|moment} date
* @returns {boolean}
*/
check_if_date_is_okay(sd, ed, date) {
if (typeof sd === 'string') sd = moment(sd).startOf('day');
if (typeof ed === 'string') ed = moment(ed).endOf('day');
if (typeof date === 'string') date = moment(date);
startDate = moment(date).startOf('day');
endDate = moment(date).endOf('day');
if (startDate <= sd && sd <= endDate) return true;
else if (startDate <= ed && ed <= endDate) return true;
else if (
sd <= startDate &&
startDate <= ed &&
sd <= endDate &&
endDate <= ed
)
return true;
else return false;
},
get_from_url(url) {
const URL_VARIABLE = '/?';
const URL_SEPARATOR = '&';
url = url.split(URL_VARIABLE)[1].split(URL_SEPARATOR);
let datas = {};
for (let index = 0, len = url.length; index < len; ++index) {
const element = url[index].split('=');
datas[element[0]] = element[1];
}
return datas;
},
/**
* Récupère une URL conforme.
* @param {string} task Tâche
* @param {string} action Action
* @param {JSON} args divers arguments ex {_eventType:1}
* @returns {string}
*/
url(task, action = '', args = null) {
let url = task;
if (action !== null && action !== undefined && action !== '')
url += '&_action=' + action;
if (
window.location.href.includes(
`${rcmail.env.mel_metapage_const.key}=${rcmail.env.mel_metapage_const.value}`,
) ||
window !== parent
) {
if (args === null || args === undefined) {
args = {};
args[rcmail.env.mel_metapage_const.key] =
rcmail.env.mel_metapage_const.value;
} else if (args[rcmail.env.mel_metapage_const.key] === undefined)
args[rcmail.env.mel_metapage_const.key] =
rcmail.env.mel_metapage_const.value;
}
if (args !== null) {
for (const key in args) {
if (Object.hasOwnProperty.call(args, key)) {
const element = args[key];
url += '&' + key + '=' + element;
}
}
}
return rcmail.get_task_url(
url,
window.location.origin + window.location.pathname,
);
},
public_url(path, args = null) {
let url =
window.location.origin +
window.location.pathname +
(window.location.pathname[window.location.pathname.length - 1] === '/'
? ''
: '/') +
'public/' +
path;
if (args !== null) {
for (const key in args) {
if (Object.hasOwnProperty.call(args, key)) {
const element = args[key];
url += (url.includes('?') ? '&' : '?') + key + '=' + element;
}
}
}
return url;
},
/**
* Change de frame, même si l'on est pas depuis "TOP"
* @param {string} frame Frame à ouvrir
* @param {boolean} changepage Si vrai, on change de page, sinon la page ouverte sera caché.
* @param {boolean} waiting Si l'on veux attendre que la frame sois ouverte ou non.
* @param {JSON} args Arguments à ajouter dans l'url de la frame.
*/
async change_frame(
frame,
changepage = true,
waiting = false,
args = null,
actions = [],
) {
await PageManager.SwitchFrame(frame, { changepage, args, actions });
// var busy;
// if (changepage) busy = (top ?? window).rcmail.set_busy(true, 'loading');
// // if (frame === "webconf")
// // {
// // var initial_change_page = changepage;
// // changepage = false;
// // }
// // if (waiting)
// // mel_metapage.Storage.set(
// // mel_metapage.Storage.wait_frame_loading,
// // mel_metapage.Storage.wait_frame_waiting,
// // );
// (top ?? window).rcmail.env.can_change_while_busy = true;
// let promise = (top ?? window).mm_st_OpenOrCreateFrame(
// frame,
// changepage,
// args,
// actions,
// );
// if (waiting) await promise;
// // if (waiting) {
// // await wait(
// // () =>
// // mel_metapage.Storage.get(
// // mel_metapage.Storage.wait_frame_loading,
// // ) !== mel_metapage.Storage.wait_frame_loaded,
// // );
// // mel_metapage.Storage.remove(mel_metapage.Storage.wait_frame_loading);
// // }
// // if (frame === "webconf")
// // {
// // if (initial_change_page)
// // {
// // (top ?? window).mm_st_OpenOrCreateFrame(frame, initial_change_page, args, actions);
// // }
// // //this.update_refresh_thing();
// // }
// if (changepage && busy) {
// (top ?? window).rcmail.set_busy(false, 'loading', busy);
// busy = null;
// }
return this;
},
/**
* Change de page en utilisant le combo tâche + action.
* @param {string} task
* @param {string} action
* @param {JSON} params
* @returns
*/
async change_page(
task,
action = null,
params = {},
update = true,
force = false,
) {
let contracted_task;
let $querry;
if (window !== parent)
return await parent.mel_metapage.Functions.change_page(
task,
action,
params,
update,
force,
);
contracted_task = mm_st_ClassContract(task);
if (action !== null) params['_action'] = action;
$querry = $(`iframe.${task}-frame`);
if (update) {
if ($querry.length > 0) {
params[rcmail.env.mel_metapage_const.key] =
rcmail.env.mel_metapage_const.value;
action = mel_metapage.Functions.url(task, null, params);
try {
if ($querry[0].contentWindow.location.href !== action)
$querry[0].src = action;
else if (force) {
$querry[0].contentWindow.location.reload();
}
} catch (error) {}
} else if ($(`.${task}-frame`).length > 0) {
action = mel_metapage.Functions.url(task, null, params);
if (window.location.href !== action) $(`.${task}-frame`).remove();
}
}
return await this.change_frame(contracted_task, true, true, params);
},
/**
* Ouvre la page de chat, avec un can/group/tem associé ou non.
* @param {string} channel_or_group group/ ou channel/
* @returns {Promise}
*/
open_chat(channel_or_group = null) {
return mel_metapage.Functions.change_frame('rocket', true, true).then(
() => {
if (channel_or_group !== null && channel_or_group !== undefined) {
if (channel_or_group[0] !== '/')
channel_or_group = `/${channel_or_group}`;
parent.$('.discussion-frame')[0].contentWindow.postMessage(
{
externalCommand: 'go',
path: channel_or_group,
},
'*',
);
}
},
);
},
/**
* F5 une frame
* @param {string} frame Classe de la frame à refresh
* @returns Chaînage
*/
update_frame(frame) {
this.call('reload_frame', false, {
_integrated: true,
always: true,
args: [`${frame}-frame`],
});
return this;
},
/**
* Reviens à la frame d'avant.
* @param {boolean} wait Si l'on doit attendre le changement de frame ou non.
* @param {string} default_frame Frame par défaut si il n'y a pas de frame d'avant. Si null, ne fait rien dans ce cas.
*/
async frame_back(wait = true, default_frame = null) {
let last = await this.ask('rcmail.env.last_frame_class');
if (
last === null ||
last === undefined ||
last === mel_metapage.Storage.unexist
) {
if (default_frame !== null) last = default_frame;
else return;
}
const tmp = await this.change_frame(last, true, wait);
top.rcmail.clear_messages();
for (const iterator of $('iframe.mm-frame')) {
iterator.contentWindow.rcmail.clear_messages();
}
return tmp;
},
get_current_title(current_task = null, _default = document.title) {
if (parent !== window)
return parent.mel_metapage.Function.get_current_title(
current_task,
_default,
);
if (current_task === null)
current_task = (top ?? window).rcmail.env.current_task;
if (current_task === 'chat' || current_task === 'discussion') {
return 'Discussion';
} else if (current_task === 'webconf') {
return 'Visioconférence';
} else {
const frame = $(`iframe.${current_task}-frame`);
if (frame.length > 0) return frame[0].contentDocument.title || _default;
else if ($(`.${current_task}-frame`).length > 0) return document.title;
else return _default;
}
},
/**
* Execute un string depuis "TOP"
* @param {string} exec String à éxécuter
* @param {string} child Exécuter aussi dans les fenetres filles ?
* @param {JSON} args Autres arguments (eval etc....)
*/
call(exec, child = false, args = {}) {
if (typeof exec !== 'string') {
const tmp_exec = JSON.stringify(exec);
if (tmp_exec === undefined) {
if (typeof exec === 'function') exec = `(${exec.toString()})()`;
else exec = exec.toString();
} else exec = tmp_exec;
}
let config = {
exec: exec,
child: child,
};
if (args != null && args !== undefined) {
for (const key in args) {
if (Object.hasOwnProperty.call(args, key)) {
const element = args[key];
config[key] = element;
}
}
}
if (
window.workspaces !== undefined &&
window.workspaces.sync !== undefined
)
workspaces.sync.PostToParent(config);
else {
parent.postMessage(config);
}
return this;
},
/**
* Execute du script à un contexte au dessus.
* @param {string} exec String à éxécuter
* @param {boolean} child Exécuter aussi dans les fenetres filles ?
* @param {JSON} args Autres arguments (eval etc....)
*/
async callAsync(exec, child = false, args = {}) {
mel_metapage.Storage.set(
mel_metapage.Storage.wait_call_loading,
mel_metapage.Storage.wait_frame_waiting,
);
this.call(exec, child, args);
await wait(() => {
return (
mel_metapage.Storage.get(mel_metapage.Storage.wait_call_loading) ===
mel_metapage.Storage.wait_frame_waiting
);
});
return this;
},
/**
* Modifie l'url du navigateur
* @param {string} url URL à afficher
*/
title(url) {
mel_metapage.Functions.call(
`window.history.replaceState({}, document.title, '${url}')`,
);
return this;
},
/**
* Met (ou pas) la frame en cours et parente en loading.
* @param {boolean} busy
*/
busy(busy = true) {
const framed = window !== parent;
mel_metapage.Storage.set('mel.busy', busy);
if (busy) {
this.call("rcmail.set_busy(true, 'loading')");
if (framed) rcmail.set_busy(true, 'loading');
} else {
this.call('rcmail.set_busy(false);rcmail.clear_messages();');
if (framed) {
rcmail.set_busy(false);
rcmail.clear_messages();
}
}
return this;
},
/**
* Vérifie si l'application est occupée.
* @returns {boolean}
*/
is_busy() {
const framed = window !== parent && rcmail.busy != undefined;
if (framed)
return mel_metapage.Storage.get('mel.busy') === true || rcmail.busy;
else {
if (rcmail.busy === undefined)
return mel_metapage.Storage.get('mel.busy') === true;
else
return rcmail.busy || mel_metapage.Storage.get('mel.busy') === true;
}
},
/**
* @async
* Récupère une variable globale parente.
* @param {string} props Variable à récupérer
* @returns {Promise<any>} Valeur de la variable
*/
async ask(props) {
this.call(`mel_metapage.Storage.set("mel.ask", ${props})`);
await wait(() => mel_metapage.Storage.get('mel.ask') === null);
props = mel_metapage.Storage.get('mel.ask');
mel_metapage.Storage.remove('mel.ask');
return props;
},
updateRichText(html) {
return html.replace(/</g, '<');
},
remove_accents(string) {
return string.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
},
replace_dets(string = '', rep = '') {
const dets = [
' le ',
' la ',
' les ',
' un ',
' une ',
' de ',
' des ',
' mon ',
' ma ',
' tes ',
' ton ',
' ta ',
' son ',
' sa ',
' ses ',
' notre ',
' nos ',
' vos ',
' votre ',
' leur ',
' leurs ',
' se ',
' ce ',
' cette ',
' cet ',
' ces ',
' a ',
"l'",
];
for (const iterator of dets) {
string = string.replaceAll(iterator, rep);
}
while (string[0] === rep) {
string = string.slice(1, string.length);
}
return string;
},
replace_special_char(string, rep = '') {
const regexp = /[^a-zA-Z0-9_ -]/g;
string = string.replace(regexp, rep);
while (string[0] === rep) {
string = string.slice(1, string.length);
}
return string;
},
/**
*
* @param {string} url
* @returns
*/
webconf_url(url) {
if (url[url.length - 1] === '&') url = url.slice(0, url.length - 1);
let val = url.toUpperCase();
if (val.includes(rcmail.env['webconf.base_url'].toUpperCase())) {
val = val.split('/');
val = val[val.length - 1];
val = val.toUpperCase();
} else if (val.includes('PUBLIC/WEBCONF'))
val = val.split('_KEY=')[1].split('&')[0];
else {
let link = WebconfLink.create({ location: url, categories: [] });
val = link.key;
try {
if (val === '') {
link = WebconfLink.create({
location: `#visio:${url}`,
categories: [],
});
val = link.key;
}
} catch (error) {
val = null;
}
}
return val || null;
},
_shuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
},
generateWebconfRoomName() {
var charArray = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
];
var digitArray = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
var roomName =
this._shuffle(digitArray).join('').substring(0, 3) +
this._shuffle(charArray).join('').substring(0, 7);
return this._shuffle(roomName.split('')).join('');
},
/**
* Faire facilement une requête ajax
* @param {string} url
* @param {JSON} datas
* @param {function} success
* @param {function} failed
* @param {string} type
* @returns {Promise<any>} Appel ajax
*/
ajax(
url,
datas = mel_metapage.Symbols.null,
success = (datas) => {},
failed = (xhr, ajaxOptions, thrownError) => {
console.error(xhr, ajaxOptions, thrownError);
},
type = 'POST',
) {
let config = {
// fonction permettant de faire de l'ajax
type: type, // methode de transmission des données au fichier php
url: url, //rcmail.env.ev_calendar_url+'&start='+dateNow(new Date())+'&end='+dateNow(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()+1)), // url du fichier php
success: success,
error: failed,
};
if (datas !== mel_metapage.Symbols.null) config['data'] = datas;
return $.ajax(config);
},
/**
* Execute un appel ajax get
* @param {string} url
* @param {JSON} datas
* @param {function} success
* @param {function} failed
* @returns {Promise<any>}
*/
get(
url,
datas = {},
success = (datas) => {},
failed = (xhr, ajaxOptions, thrownError) => {
console.error(xhr, ajaxOptions, thrownError);
},
) {
for (const key in datas) {
if (Object.hasOwnProperty.call(datas, key)) {
const element = datas[key];
url += `${url.includes('?') ? '&' : '?'}${key}=${encodeURIComponent(element)}`;
}
}
return this.ajax(url, mel_metapage.Symbols.null, success, failed, 'GET');
},
/**
* Execute un appel ajax post
* @param {string} url
* @param {Symbol|JSON} datas <c>mel_metapage.Symbols.null</c> si aucune données.
* @param {function} success
* @param {function} failed
*/
post(
url,
datas = mel_metapage.Symbols.null,
success = (datas) => {},
failed = (xhr, ajaxOptions, thrownError) => {
console.error(xhr, ajaxOptions, thrownError);
},
) {
return this.ajax(url, datas, success, failed);
},
/**
* Contient différents fonctions pour mettre à jours certaines données.
*/
update: {
/**
* Met à jours le calendrier.
*/
calendar() {
mel_metapage.Functions.call(
'rcmail.mel_metapage_fn.calendar_updated();',
);
return this;
},
},
/**
* Vérifie si un handler existe sur un élément.
* @param {DOMElement} element Element à tester.
* @param {function} handler Fonction à vérifier
* @param {string} type Type d'évènement
* @returns {boolean}
*/
handlerExist(element, handler, type = 'click') {
if (element.val !== undefined) element = element[0];
return Enumerable.from(jQuery._data(element, 'events')[type])
.where((x) => x.handler + '' === handler + '')
.any();
},
/**
* Fonctions lié au stockage nextcloud.
*/
stockage: {
/**
* Ouvre la frame nextcloud et affiche un document en particulier (si il existe).
* @param {JSON|Nextcloud_File} datas Données du document à afficher.
* {
file:nom du fichier,
folder:chemin du fichier
}
* @param {boolean} isfiledatas Si vrai, datas est un objet <c>Nextcloud_File</c>
* @param {function} thenFunc Action à faire une fois que l'on à changer de page.
*/
go(datas, goFunc = null, thenFunc = null) {
let init = 'new Nextcloud("rcmail.env.nextcloud_username")';
let go = `.go(${JSON.stringify(datas)}, ${goFunc})`;
let then = '';
if (thenFunc !== null) {
then = `.then((a) => { (${thenFunc + ''})(a) })`;
}
return mel_metapage.Functions.call(init + go + then);
},
have_0_quota() {
return rcmail.env.have_0_quota ?? false;
},
is_stockage_active() {
const DEFAULT = false;
return rcmail?.env?.why_is_not_active?.value
? rcmail.env.why_is_not_active.value ===
rcmail.env.why_is_not_active.consts.ST_ACTIVE
: DEFAULT;
},
canDriveActions() {
return !this.have_0_quota() && this.is_stockage_active();
},
},
/**
* Recherche dans les mails
* @param {string} itemToSearch Objet à chercher
* @param {Array<string>} fields Champs
* @param {boolean} openFrame Ouvrir ou non la frame
*/
async searchOnMail(itemToSearch, fields, openFrame = false) {
if (parent === window) {
if (openFrame)
await mel_metapage.Functions.change_frame('mail', true, true);
if ($('iframe.mail-frame').length > 0)
$('iframe.mail-frame')[0].contentWindow.postMessage({
exec: 'search',
_integrated: true,
child: false,
args: [itemToSearch, fields],
});
else search_action(itemToSearch, fields);
} else
mel_metapage.Functions.call(
`mel_metapage.Functions.searchOnMail('${itemToSearch}', ${JSON.stringify(fields)}, ${openFrame})`,
);
return this;
},
doActionFrame(frame, doAction, ...functionArgs) {
//console.log("[doActionFrame]",frame, doAction, parent !== window);
if (parent !== window) {
mel_metapage.Functions.call('mel_metapage.doActionFrame', false, {
_integrated: true,
always: true,
args: [frame, doAction + '', ...functionArgs],
});
} else {
if (typeof doAction === 'string') {
doAction = new Function(`return (${doAction})(...arguments)`);
}
//Personne ouvert
if ($(`.${frame}-frame`).length === 0) doAction(0, ...functionArgs);
else if ($(`iframe.${frame}-frame`).length > 0)
//Frame ouverte
doAction(1, ...functionArgs);
//Page ouverte
else doAction(2, ...functionArgs);
}
return this;
},
update_refresh_thing() {
let current = (top ?? window).$('.refresh-current-thing');
let action =
window.webconf_helper.already() ||
(top ?? window).rcmail.env.current_frame_name === 'webconf';
if (action === true)
current.addClass('disabled').attr('disabled', 'disabled');
else current.removeClass('disabled').removeAttr('disabled');
return this;
},
isNavigator(symbol) {
switch (symbol) {
case mel_metapage.Symbols.navigator.firefox:
return typeof InstallTrigger !== 'undefined';
default:
throw 'Unknown navigator';
}
},
/**
*
* @param {string|JSON} _params - String sous forme '?dir=PATH&fileid=ID' ou JSON sous forme {path:'', id:''}
*/
async change_frame_nextcloud(_params = null) {
const appfiles = '/apps/files/';
const urlToAdd =
_params.id === undefined && _params.includes(appfiles) ? appfiles : '';
let param = urlToAdd + (_params ?? '');
let configArgs = null;
//si _params n'est pas un string
if (_params !== null) {
if (_params.id !== undefined)
param = `${urlToAdd}?dir=${_params.path}&fileid=${_params.id}`;
configArgs = {
_params: urlencode(param),
};
}
const url = `${rcmail.env.nextcloud_url}${param ?? ''}`;
if (parent.$('iframe.stockage-frame').length > 0)
parent
.$('iframe.stockage-frame')[0]
.contentWindow.$('#mel_nextcloud_frame')[0].src = url;
await this.change_frame('stockage', true, true, configArgs);
parent.$(
'iframe.stockage-frame',
)[0].contentWindow.rcmail.env.nextcloud_gotourl = url;
return this;
},
async comment_mail(uid, comment, folder = 'INBOX') {
let data = uid;
await this.post(
mel_metapage.Functions.url('mel_metapage', 'comment_mail'),
{
_uid: uid,
_comment: comment,
_folder: folder,
},
(datas) => {
if (datas == 'false') {
rcmail.display_message('Une erreur est survenue!', 'error');
data = false;
} else data = datas;
},
);
return data;
},
calculateObjectSizeInMo(obj) {
const jsonString = JSON.stringify(obj);
const blob = new Blob([jsonString]);
const sizeInBytes = blob.size;
const sizeInMb = sizeInBytes / (1024 * 1024);
return sizeInMb;
},
colors: {
kMel_Luminance(rgb) {
let R = rgb[0] / 255;
let G = rgb[1] / 255;
let B = rgb[2] / 255;
if (R <= 0.04045) {
R = R / 12.92;
} else {
R = ((R + 0.055) / 1.055) ** 2.4;
}
if (G <= 0.04045) {
G = G / 12.92;
} else {
G = ((G + 0.055) / 1.055) ** 2.4;
}
if (B <= 0.04045) {
B = B / 12.92;
} else {
B = ((B + 0.055) / 1.055) ** 2.4;
}
const L = 0.2126 * R + 0.7152 * G + 0.0722 * B;
return L;
},
kMel_CompareLuminance(rgb1, rgb2) {
const l1 = this.kMel_Luminance(rgb1);
const l2 = this.kMel_Luminance(rgb2);
let ratio;
if (l1 > l2) {
ratio = (l1 + 0.05) / (l2 + 0.05);
} else {
ratio = (l2 + 0.05) / (l1 + 0.05);
}
return ratio;
},
kMel_LuminanceRatioAAA(rgb1, rgb2) {
const isAAA = this.kMel_CompareLuminance(rgb1, rgb2) > 4.5;
return isAAA;
},
kMel_extractRGB(color) {
let regexp = /#[a-fA-F\d]{6}/g;
let rgbArray = color.match(regexp);
if (rgbArray) {
rgbArray[0] = parseInt(color.slice(1, 3), 16);
rgbArray[1] = parseInt(color.slice(3, 5), 16);
rgbArray[2] = parseInt(color.slice(5, 7), 16);
return rgbArray;
}
regexp = /#[a-fA-F\d]{3}/g;
rgbArray = color.match(regexp);
if (rgbArray) {
rgbArray[0] = parseInt(color.slice(1, 2), 16);
rgbArray[1] = parseInt(color.slice(2, 3), 16);
rgbArray[2] = parseInt(color.slice(3, 4), 16);
return rgbArray;
}
regexp = /\d+/g;
rgbArray = color.match(regexp);
if (rgbArray.length === 3 || rgbArray.length === 4) {
return rgbArray;
}
},
},
},
};
window.mel_metapage = mel_metapage;