- 1 :
function html_helper(option, html, optional_classes = "", attribs = null){
- 2 :
- 3 :
if (!!attribs)
- 4 :
{
- 5 :
const tmp = attribs;
- 6 :
attribs = '';
- 7 :
- 8 :
for (const key in tmp) {
- 9 :
if (Object.hasOwnProperty.call(tmp, key)) {
- 10 :
const element = tmp[key];
- 11 :
attribs += `${key}="${element}" `;
- 12 :
}
- 13 :
}
- 14 :
- 15 :
}
- 16 :
else attribs = '';
- 17 :
- 18 :
switch (option) {
- 19 :
case html_helper.options["block"]:
- 20 :
return `<div class="square_div ${optional_classes}" ${attribs}><div class=contents><div class=square-contents>${html}</div></div></div>`;
- 21 :
case html_helper.options.create_button:
- 22 :
- 23 :
let onclick = "";
- 24 :
let classes = 'mel-button create mel-before-remover btn btn-secondary';
- 25 :
let id = "";
- 26 :
- 27 :
if (typeof optional_classes !== "string" && optional_classes !== null && optional_classes !== undefined)
- 28 :
{
- 29 :
if (optional_classes.onclick !== undefined)
- 30 :
onclick = `onclick="${optional_classes.onclick}"`;
- 31 :
- 32 :
if (optional_classes.new_classes !== undefined)
- 33 :
classes = `${optional_classes.new_classes}`
- 34 :
- 35 :
if (optional_classes.additional_classes !== undefined)
- 36 :
classes += `${optional_classes.additional_classes}`
- 37 :
- 38 :
if (optional_classes.id !== undefined)
- 39 :
id = `id="${optional_classes.id}"`;
- 40 :
}
- 41 :
- 42 :
if (classes !== "")
- 43 :
classes = `class="${classes}"`;
- 44 :
- 45 :
return `<button ${id} ${classes} ${onclick} ${attribs} >${html}</button>`;
- 46 :
default:
- 47 :
return html;
- 48 :
}
- 49 :
}
- 50 :
- 51 :
html_helper.options = {
- 52 :
"block":Symbol("block"),
- 53 :
"create_button":Symbol("create_button")
- 54 :
}
- 55 :
- 56 :
/**
- 57 :
* Renvoie vrai si le string est vide ou vaut null
- 58 :
* @param {string} string String à tester
- 59 :
*/
- 60 :
html_helper.is_null_or_empty = function(string)
- 61 :
{
- 62 :
return string === null || string == "";
- 63 :
}
- 64 :
- 65 :
html_helper.JSON = {
- 66 :
parse:(string) => {
- 67 :
if (string === null || string === undefined)
- 68 :
return string;
- 69 :
return JSON.parse(string.replaceAll('¤¤¤¤¤¤¤¤', '"'));
- 70 :
},
- 71 :
stringify:(item) => {
- 72 :
if (item === null)
- 73 :
item = "null";
- 74 :
else if (item === undefined)
- 75 :
item = "undefined";
- 76 :
return JSON.stringify(item).replaceAll('"', "¤¤¤¤¤¤¤¤");
- 77 :
}
- 78 :
}
- 79 :
- 80 :
/**
- 81 :
* Récupère le html pour la liste des tâches de l'utilisateur. Récupère les données depuis le stockage local.
- 82 :
* @param {*} e Element qui contiendra le html
- 83 :
* @param {*} e_news Element qui contiendra le nombre de tâches (facultatif)
- 84 :
* @param {JSON} tabs Liste des onglets
- 85 :
* @param {String} title Titre du block
- 86 :
*/
- 87 :
html_helper.TasksAsync = async function (tabs, e = null, e_news = null,title = null)
- 88 :
{
- 89 :
let storage = await mel_metapage.Storage.check(mel_metapage.Storage.tasks).wait();
- 90 :
- 91 :
if (html_helper.tasks_updates === undefined)
- 92 :
{
- 93 :
html_helper.tasks_updates = new Mel_Update(mel_metapage.EventListeners.tasks_updated.after, "tasks.update", async () => {
- 94 :
$('.html-tasks').each(async (i,e) => {
- 95 :
e = $(e);
- 96 :
const tabs = html_helper.JSON.parse(e.data('task-tabs'));
- 97 :
const title = e.data('task-title');
- 98 :
e[0].outerHTML = await html_helper.TasksAsync(tabs, null, null, title);
- 99 :
});
- 100 :
});
- 101 :
}
- 102 :
- 103 :
return html_helper.Tasks(storage, tabs, e, e_news, title);
- 104 :
}
- 105 :
- 106 :
/**
- 107 :
* Récupère le html pour la liste des tâches de l'utilisateur.
- 108 :
* @param {*} e Element qui contiendra le html
- 109 :
* @param {Array} datas Liste des tâches
- 110 :
* @param {*} e_news Element qui contiendra le nombre de tâches (facultatif)
- 111 :
* @param {JSON} tabs Liste des noms des onglets
- 112 :
* @param {String} title Titre du block
- 113 :
*/
- 114 :
html_helper.Tasks = function (datas, tabs, e = null, e_news = null,title = null)
- 115 :
{
- 116 :
let html = ''
- 117 :
html += '<div class="html-tasks" data-task-tabs="'+html_helper.JSON.stringify(tabs)+'" data-task-title="'+title+'">';
- 118 :
if (!html_helper.is_null_or_empty(title))
- 119 :
{
- 120 :
html += "<div class=task-title>";
- 121 :
html += "<span>" + title + "</span>";
- 122 :
html += "</div>";
- 123 :
}
- 124 :
// html = '<div id=dwp-tadk-urg class="tab-task-dwp mel-tab mel-tabheader">Tâches urgentes</div>';
- 125 :
//html += '<center><div id=dwp-tadk-all class="tab-task-dwp mel-tab mel-tabheader active last">'+tabs["right"]+'</div></center>';
- 126 :
- 127 :
html += '<div style="margin:10px 0;"><div id="nb-waiting-task" class="nb-task wsp-task-classik tab-task mel-tab-content" style=""><span class="icon-mel-time roundbadge large clear"></span><span><span class="waiting-task"></span><span class="nb-waiting-task nb font-size-large">'+datas.length+'</span> tâches en cours</span></div></div>';
- 128 :
- 129 :
datas = Enumerable.from(datas).orderBy((x) => x.order).thenBy((x) => (x._hasdate === 1 ? x.datetime : Number.MAX_VALUE )).toArray();
- 130 :
let date;
- 131 :
- 132 :
html += `<ul class="ignore-bullet">`;
- 133 :
- 134 :
for (let index = 0; index < datas.length; index++) {
- 135 :
const element = datas[index];
- 136 :
date = moment(parseInt(element.created + "000"));
- 137 :
html += "<li>";
- 138 :
html += "<div class=row style=margin-bottom:15px;margin-right:15px;>";
- 139 :
- 140 :
if (date._isValid)
- 141 :
html += `<div class=col-md-10><a href=# class="element-block mel-not-link mel-focus" onclick="open_task('${element.id}')"><span class="element-title default-text bold element-block">${element.title}</span><span class="element-desc secondary-text element-block">Créée le ${date.format("DD/MM/YYYY")} à ${date.format("hh:mm")}</span></a></div>`;//html += "<div class=col-md-12><span class=element-title>" + element.title + "</span><br/><span class=element-desc>Créée le " + date.format("DD/MM/YYYY") + " à " + date.format("hh:mm") +"</span></div>";
- 142 :
else
- 143 :
html += "<div class=col-md-12></div>";
- 144 :
- 145 :
//html += '<div class=col-md-2><a style=display:none; onclick="add_task_to_completed(`'+element.id+'`)" class="roundbadge large hover tick ' + (element.mel_metapage.order == 0 ? "icon-mel-warning warning" : "icon-mel-time clear") + '"></a></div>'
- 146 :
html += "</div>";
- 147 :
html += "</li>";
- 148 :
}
- 149 :
html += "</ul>";
- 150 :
html += "</div>";
- 151 :
- 152 :
if (e !== null)
- 153 :
e.html(html);
- 154 :
- 155 :
if (e_news !== null)
- 156 :
{
- 157 :
if (datas.length > 0)
- 158 :
{
- 159 :
e_news.html(datas.length);
- 160 :
e_news.removeClass("hidden");
- 161 :
}
- 162 :
else
- 163 :
e_news.addClass("hidden");
- 164 :
}
- 165 :
- 166 :
return html;
- 167 :
}
- 168 :
- 169 :
html_helper.CalendarsAsync = async function(config = {
- 170 :
add_day_navigation:false,
- 171 :
add_create:false,
- 172 :
create_function:null,
- 173 :
add_see_all:false,
- 174 :
next_when_empty_today_function:null,
- 175 :
}, e = null, e_number = null, _date = moment())
- 176 :
{
- 177 :
const Loader = (await loadJsModule('mel_metapage', 'calendar_loader', '/js/lib/calendar/')).CalendarLoader.Instance;
- 178 :
let storage = Loader.get_next_events_day(_date, {});
- 179 :
- 180 :
const KEY = 'HTML_CALENDAR_TOP_FUNCTION';
- 181 :
const Top = (await loadJsModule('mel_metapage', 'top')).Top;
- 182 :
- 183 :
if (!Top.has(KEY)) {
- 184 :
Top.add(KEY, true);
- 185 :
- 186 :
Loader.add_event_listener(mel_metapage.EventListeners.calendar_updated.after, function() {
- 187 :
- 188 :
Loader.select('iframe.mm-frame').each((index, element) => {
- 189 :
if (!$(element).hasClass('discussion-frame')) {
- 190 :
element.contentWindow.$('.html-calendar').each(async (i, calendar) => {
- 191 :
calendar = $(calendar);
- 192 :
- 193 :
let config = html_helper.JSON.parse(calendar.data('config'));
- 194 :
const date = moment(calendar.data('date'));
- 195 :
- 196 :
if (config.add_create) delete config.add_create;
- 197 :
- 198 :
if (!(config.add_day_navigation && moment(calendar.find(".mm-agenda-date").data("current-date")).startOf("day").format() !== date.startOf("day").format())) {
- 199 :
e[0].outerHTML = await html_helper.CalendarsAsync(config, null, null, date);
- 200 :
}
- 201 :
});
- 202 :
}
- 203 :
});
- 204 :
- 205 :
}, { callback_key:KEY});
- 206 :
}
- 207 :
- 208 :
if (moment().startOf('day').format() === moment(_date).startOf('day').format()) storage.where(x => moment(x.end) > moment());
- 209 :
- 210 :
return await html_helper.Calendars({datas:storage.toArray(), config:config, e:e, e_number:e_number, _date:_date});
- 211 :
}
- 212 :
- 213 :
html_helper.Calendars = async function ({datas, config = {
- 214 :
add_day_navigation:false,
- 215 :
add_create:false,
- 216 :
create_function:null,
- 217 :
add_see_all:false,
- 218 :
next_when_empty_today_function:null
- 219 :
}, e = null, e_number = null, _date = moment(), get_only_body = false} = {})
- 220 :
{
- 221 :
const Loader = (await loadJsModule('mel_metapage', 'calendar_loader', '/js/lib/calendar/')).CalendarLoader.Instance;
- 222 :
const html_events = (await loadJsModule('mel_metapage', 'html_events', '/js/lib/html/')).html_events;
- 223 :
const html_li = (await loadJsModule('mel_metapage', 'html', '/js/lib/html/')).html_li;
- 224 :
- 225 :
let html = ''
- 226 :
if (!get_only_body)
- 227 :
html += '<div class="html-calendar" data-config="'+html_helper.JSON.stringify(config)+'" data-date="'+_date.format()+'">';
- 228 :
if (config.add_day_navigation === true)
- 229 :
{
- 230 :
const count = Enumerable.from(datas).where(x => x.free_busy !== "free").count();
- 231 :
let nav_click = "rcube_calendar.change_calendar_date($('.mm-agenda-date'), ¤¤¤)";
- 232 :
html += '<div class="row">';
- 233 :
html += '<div class="col-2"><span class="icon-mel-calendar mm-agenda-icon"><span class="notif roundbadge lightgreen edited" '+(typeof datas === "string" || count === 0 ? "style=display:none;" : "")+'>'+count+'</span></span></div>';
- 234 :
html += '<div class="col-6"><span class="mm-agenda-date">'+rcube_calendar.mel_metapage_misc.GetDate(_date)+'</span></div>';
- 235 :
html += '<div class="col-4"><div class="row">';
- 236 :
html += '<div class="col-6"><button class="btn-mel-invisible btn-arrow btn btn-secondary" onclick="'+nav_click.replace("¤¤¤", "-1")+'"> <span class="icon-mel-arrow-left"><span class="sr-only">'+rcmail.gettext("last_day", "mel_metapage")+'</span></span> </button></div>';
- 237 :
html += '<div class="col-6"><button class="btn-mel-invisible btn-arrow btn btn-secondary" onclick="'+nav_click.replace("¤¤¤", "1")+'"> <span class="icon-mel-arrow-right"><span class="sr-only">'+rcmail.gettext("next_day", "mel_metapage")+'</span></span> </button></div>';
- 238 :
html += "</div></div></div>"
- 239 :
}
- 240 :
if (!get_only_body)
- 241 :
html += '<ul class="block-body ignore-bullet">';
- 242 :
- 243 :
//let icon;
- 244 :
if (typeof datas === "string")
- 245 :
html += "<div>" + datas + "</div>";
- 246 :
else {
- 247 :
- 248 :
if (datas.length > 0)
- 249 :
{
- 250 :
var $jquery_array = $('');
- 251 :
let li;
- 252 :
for (let index = 0; index < datas.length; index++) {
- 253 :
const element = datas[index];
- 254 :
- 255 :
li = new html_li({});
- 256 :
new html_events(element, {'data-ignore-date':true}, _date).appendTo(li);
- 257 :
li = li.generate();
- 258 :
$jquery_array = $.merge($jquery_array, li);
- 259 :
html += html_events.$_toString(li);
- 260 :
}
- 261 :
html_helper.Calendars.$jquery_array = $jquery_array;
- 262 :
li = null;
- 263 :
}
- 264 :
else
- 265 :
{
- 266 :
const now = moment();
- 267 :
const raw_storage = Loader.load_all_events();
- 268 :
const storage = Enumerable.from(config.next_when_empty_today_function !== null && typeof config.next_when_empty_today_function === "function" ? config.next_when_empty_today_function(raw_storage) : raw_storage).where(x => moment(x.start) > now);
- 269 :
const storage_count = storage.count();
- 270 :
if (storage_count > 0)
- 271 :
{
- 272 :
const storage_first = storage.first();
- 273 :
const value = !!storage_first.value && !!storage_first.value[0] ? storage_first.value[0] : storage_first;
- 274 :
const all_day = value.allDay ? "_all_day" : "";
- 275 :
html += `<li><span class="element-title element-no default-text bold element-block">${rcmail.gettext('mel_portal.no_event_today')}</span>
- 276 :
<a href=# class="element-block mel-not-link mel-focus" onclick="${html_helper.Calendars.generate_link(value)}">
- 277 :
<span class="element-title default-text bold element-block">${rcmail.gettext(`mel_portal.next_agenda_event${all_day}`).replace('{date}', moment(value.start).format('DD/MM/YYYY')).replace('{horaire}', moment(value.start).format('HH:mm'))}</span>
- 278 :
<span class="element-desc secondary-text element-block">${value.title}</span>
- 279 :
</a>
- 280 :
</li>`;
- 281 :
}
- 282 :
else html += `<li>Pas d'évènements aujourd'hui ainsi que dans les 7 prochains jours !</li>`;
- 283 :
}
- 284 :
}
- 285 :
- 286 :
if (!get_only_body)
- 287 :
{
- 288 :
html += "</ul>";
- 289 :
html += "</div>";
- 290 :
}
- 291 :
else
- 292 :
html = `<ul class="ignore-bullet">${html}</ul>`;
- 293 :
- 294 :
if (config.add_create === true)
- 295 :
{
- 296 :
const data_text = 'Créer <span class="icon-mel-plus plus"></span>';
- 297 :
if (!html.includes(data_text))
- 298 :
html += html_helper(html_helper.options.create_button, data_text, {
- 299 :
onclick:config.create_function === undefined || config.create_function === null ? "html_helper.Calendars.create()" : config.create_function
- 300 :
});
- 301 :
}
- 302 :
- 303 :
if (e !== null) e.html(html);
- 304 :
if (e_number !== null)
- 305 :
{
- 306 :
if (datas.length > 0)
- 307 :
{
- 308 :
e_number.html(datas.length);
- 309 :
e_number.removeClass("hidden");
- 310 :
}
- 311 :
else
- 312 :
e_number.addClass("hidden");
- 313 :
}
- 314 :
- 315 :
if (!!e && !!$jquery_array) {
- 316 :
e.find('ul').html($jquery_array);
- 317 :
}
- 318 :
- 319 :
return html;
- 320 :
}
- 321 :
- 322 :
html_helper.Calendars.create = function(config = {
- 323 :
date:moment(),
- 324 :
selector:null
- 325 :
})
- 326 :
{
- 327 :
- 328 :
let date;
- 329 :
- 330 :
if (config.selector !== undefined && config.selector !== null)
- 331 :
date = $(config.selector).data("current-date");
- 332 :
else if (config.date !== undefined && config.date !== null)
- 333 :
date = config.date;
- 334 :
else
- 335 :
date = moment();
- 336 :
- 337 :
const e = {
- 338 :
target:null
- 339 :
};
- 340 :
- 341 :
let event = {
- 342 :
start:moment(`${moment(date).format("YYYY-MM-DD")} ${moment().format("HH:mm")}`),
- 343 :
end:null//moment().add(1, "h")
- 344 :
};
- 345 :
- 346 :
event.end = moment(event.start).add(1, "h");
- 347 :
rcmail.local_storage_set_item("tmp_calendar_event", event);
- 348 :
//console.log("[html_helper.Calendars.create]", event, date, config);
- 349 :
- 350 :
return rcmail.commands['add-event-from-shortcut'] ? rcmail.command('add-event-from-shortcut', '', e.target, e) : rcmail.command('addevent', '', e.target, e);
- 351 :
}
- 352 :
- 353 :
html_helper.Calendars.generate_link = function(event)
- 354 :
{
- 355 :
let link = "";
- 356 :
- 357 :
if (SearchResultCalendar && SearchResultCalendar.CreateOrOpen)
- 358 :
link = `SearchResultCalendar.CreateOrOpen('${JSON.stringify(event).replaceAll('"', '£¤£').replaceAll("'", "µ¤¤µ")}')`;
- 359 :
- 360 :
return link;
- 361 :
}
- 362 :
- 363 :
/**
- 364 :
* Classe qui permet de générer du html
- 365 :
*/
- 366 :
class mel_html{
- 367 :
/**
- 368 :
* Constructeur de la classe
- 369 :
* @param {string} tag Balise (exemple : div, li, ul etc...)
- 370 :
* @param {Object} attribs Attributs de la balise
- 371 :
* @param {string} content Contenu de la balise
- 372 :
*/
- 373 :
constructor(tag, attribs = {}, content = '')
- 374 :
{
- 375 :
this.tag = tag.toLowerCase();
- 376 :
this.attribs = attribs;
- 377 :
this.content = content;
- 378 :
this.onclick = new MelEvent();
- 379 :
this.onkeydown = new MelEvent();
- 380 :
this.onmouseover = new MelEvent();
- 381 :
this.onmouseout = new MelEvent();
- 382 :
this.aftergenerate = new MelEvent();
- 383 :
}
- 384 :
- 385 :
/**
- 386 :
* Actions à faire avant de générer l'élément jquery
- 387 :
* @abstract
- 388 :
* @private Cette fonction est privée
- 389 :
*/
- 390 :
_before_generate() {}
- 391 :
- 392 :
/**
- 393 :
* Récupère le jquery de ces données html
- 394 :
* @param {Object} additionnal_attribs Attributs additionnels
- 395 :
* @returns {$}
- 396 :
*/
- 397 :
generate(additionnal_attribs = {})
- 398 :
{
- 399 :
this._before_generate();
- 400 :
- 401 :
let multi_balise = true;
- 402 :
- 403 :
switch (this.tag) {
- 404 :
case CONST_HTML_IMG:
- 405 :
case CONST_HTML_INPUT:
- 406 :
case CONST_HTML_BR:
- 407 :
multi_balise = false;
- 408 :
break;
- 409 :
- 410 :
default:
- 411 :
break;
- 412 :
}
- 413 :
- 414 :
if (multi_balise && !!this.attribs[mel_html.ATTRIB_NO_MULTI_BALISE]) multi_balise = false;
- 415 :
- 416 :
let $html = $(`${CONST_BALISE_START}${this.tag} ${(!multi_balise ? CONST_BALISE_CLOSE_END : CONST_BALISE_END)}${(multi_balise ? `${CONST_BALISE_CLOSE_START}${this.tag}${CONST_BALISE_END}` : EMPTY_STRING)}`);
- 417 :
- 418 :
for (const iterator of Enumerable.from(this.attribs).concat(additionnal_attribs).where(x => 0 === x || !!(x || null))) {
- 419 :
switch (iterator.key) {
- 420 :
case CONST_ATTRIB_CLASS:
- 421 :
$html.addClass(Array.isArray(iterator.value) ? iterator.value.join(' ') : iterator.value);
- 422 :
break;
- 423 :
case mel_html.EVENT_ON:
- 424 :
for (const key in iterator.value) {
- 425 :
if (Object.hasOwnProperty.call(iterator.value, key)) {
- 426 :
const element = iterator.value[key];
- 427 :
$html.on(key, element);
- 428 :
}
- 429 :
}
- 430 :
break;
- 431 :
case 'style':
- 432 :
iterator.value = this._getStyle();
- 433 :
default:
- 434 :
$html.attr(iterator.key, iterator.value);
- 435 :
break;
- 436 :
}
- 437 :
}
- 438 :
- 439 :
let generated = this._generateContent($html, this.content);
- 440 :
generated = this.bind_events(generated);
- 441 :
- 442 :
if (this.aftergenerate.count() > 0) {
- 443 :
this.aftergenerate.call(generated);
- 444 :
}
- 445 :
- 446 :
return generated;
- 447 :
}
- 448 :
- 449 :
/**
- 450 :
* Ajoute les évènements de l'objet à un élement jquery
- 451 :
* @param {$} $element
- 452 :
* @returns {$} Elément avec les actions
- 453 :
*/
- 454 :
bind_events($element) {
- 455 :
if (this.onclick.haveEvents()) $element.on(CONST_EVENT_ACTION_CLICK, (event) => {
- 456 :
this.onclick.call(event);
- 457 :
});
- 458 :
- 459 :
if (this.onkeydown.haveEvents()) $element.on('keydown', (event) => {
- 460 :
this.onkeydown.call(event);
- 461 :
});
- 462 :
- 463 :
if (this.onmouseover.haveEvents()) $element.on('mouseover', (event) => {
- 464 :
this.onmouseover.call(event);
- 465 :
});
- 466 :
- 467 :
if (this.onmouseout.haveEvents()) $element.on('mouseout', (event) => {
- 468 :
this.onmouseout.call(event);
- 469 :
});
- 470 :
- 471 :
return $element;
- 472 :
}
- 473 :
- 474 :
/**
- 475 :
* Ajoute une classe à la liste des classes de cet élément html
- 476 :
* @param {string} classes Classe à ajouter
- 477 :
* @returns Chaînage
- 478 :
*/
- 479 :
addClass(classes) {
- 480 :
if (!this.attribs) this.attribs = {};
- 481 :
if (!(this.attribs[CONST_ATTRIB_CLASS] || null)) this.attribs[CONST_ATTRIB_CLASS] = [];
- 482 :
else if (STRING === typeof this.attribs[CONST_ATTRIB_CLASS]) this.attribs[CONST_ATTRIB_CLASS] = [this.attribs[CONST_ATTRIB_CLASS]];
- 483 :
- 484 :
this.attribs[CONST_ATTRIB_CLASS].push(classes);
- 485 :
return this;
- 486 :
}
- 487 :
- 488 :
/**
- 489 :
* Vérifie si l'élément possède une classe en particulier
- 490 :
* @param {string} html_class Classe à vérifier
- 491 :
* @returns {boolean}
- 492 :
*/
- 493 :
hasClass(html_class){
- 494 :
if (!!this.attribs && !!this.attribs[CONST_ATTRIB_CLASS]) {
- 495 :
if (STRING === typeof this.attribs[CONST_ATTRIB_CLASS]) return html_class === this.attribs[CONST_ATTRIB_CLASS];
- 496 :
else return this.attribs[CONST_ATTRIB_CLASS].includes(html_class);
- 497 :
}
- 498 :
- 499 :
return false;
- 500 :
}
- 501 :
- 502 :
/**
- 503 :
* Ajoute du css initial à l'élément
- 504 :
* @param {string} key Propriété css (ex: display)
- 505 :
* @param {string} value Valeur css (ex : none)
- 506 :
* @returns Chaînage
- 507 :
*/
- 508 :
css(key, value) {
- 509 :
if (!this.attribs) this.attribs = {};
- 510 :
if (!(this.attribs['style'] || null)) this.attribs['style'] = {};
- 511 :
else if (STRING === typeof this.attribs['style']) {
- 512 :
const splited = this.attribs['style'].split(CONST_CSS_SEPARATOR);
- 513 :
this.attribs['style'] = {};
- 514 :
for (let index = 0, len = splited.length; index < len; ++index) {
- 515 :
const element = splited[index].split(CONST_CSS_ASSIGN);
- 516 :
this.attribs['style'][element[0]] = element[1];
- 517 :
}
- 518 :
}
- 519 :
- 520 :
this.attribs['style'][key] = value;
- 521 :
return this;
- 522 :
}
- 523 :
- 524 :
/**
- 525 :
* Ajoute un attribut à l'élément
- 526 :
* @param {string} key Nom de l'attribut
- 527 :
* @param {string | number | Boolean} value Valeur de l'attribut
- 528 :
* @returns Chaînage
- 529 :
*/
- 530 :
setAttr(key, value) {
- 531 :
if (!this.attribs) this.attribs = {};
- 532 :
- 533 :
this.attribs[key] = value;
- 534 :
return this;
- 535 :
}
- 536 :
- 537 :
/**
- 538 :
* Met un id à l'élément
- 539 :
* @param {string} id
- 540 :
* @returns Chaînage
- 541 :
*/
- 542 :
setId(id) {
- 543 :
return this.setAttr('id', id);
- 544 :
}
- 545 :
- 546 :
toString() {
- 547 :
return this.generate()[0].outerHTML;
- 548 :
}
- 549 :
- 550 :
_getStyle() {
- 551 :
if (!this.attribs['style'] || STRING === typeof this.attribs['style']) return this.attribs['style'] || EMPTY_STRING;
- 552 :
else {
- 553 :
let array = [];
- 554 :
for (let keys = Object.keys(this.attribs['style']), index = 0, len = keys.length; index < len; ++index) {
- 555 :
const key = keys[index];
- 556 :
const value = this.attribs['style'][key];
- 557 :
array.push([key, value].join(CONST_CSS_ASSIGN));
- 558 :
}
- 559 :
- 560 :
array = array.join(CONST_CSS_SEPARATOR);
- 561 :
- 562 :
return (EMPTY_STRING === array ? EMPTY_STRING : (array + CONST_CSS_SEPARATOR));
- 563 :
}
- 564 :
}
- 565 :
- 566 :
/**
- 567 :
* Génère un élément jquery à partir des données de cet élément.
- 568 :
*
- 569 :
* L'ajoute ensuite à un élément parent.
- 570 :
* @param {$} $parent Elément parent qui contiendra l'objet
- 571 :
* @param {Object} additionnal_attribs Attributs additionnels
- 572 :
* @returns {$}
- 573 :
*/
- 574 :
create($parent, additionnal_attribs = [])
- 575 :
{
- 576 :
return this.generate(additionnal_attribs).appendTo($parent);
- 577 :
}
- 578 :
- 579 :
/**
- 580 :
* Ajoute le html à l'élément jquery générer
- 581 :
* @param {$} $html Elément jquery
- 582 :
* @param {string} content html générer
- 583 :
* @returns {$}
- 584 :
* @private
- 585 :
*/
- 586 :
_generateContent($html, content) {
- 587 :
return $html.html(content);
- 588 :
}
- 589 :
- 590 :
/**
- 591 :
* Récupère un mel_html div
- 592 :
* @param {Object} attribs Attributs de l'élément
- 593 :
* @param {string} content Contenue de l'élément
- 594 :
* @returns {mel_html}
- 595 :
*/
- 596 :
static div(attribs = {}, content = '') {
- 597 :
return new mel_html(CONST_HTML_DIV, attribs, content);
- 598 :
}
- 599 :
}
- 600 :
- 601 :
Object.defineProperty(mel_html, 'EVENT_ON', {
- 602 :
enumerable: false,
- 603 :
configurable: false,
- 604 :
writable: false,
- 605 :
value:CONST_EVENT_ON
- 606 :
});
- 607 :
- 608 :
Object.defineProperty(mel_html, 'ATTRIB_NO_MULTI_BALISE', {
- 609 :
enumerable: false,
- 610 :
configurable: false,
- 611 :
writable: false,
- 612 :
value:CONST_ATTRIB_NO_MULTI_BALISE
- 613 :
});
- 614 :
- 615 :
Object.defineProperty(mel_html, 'select_html', {
- 616 :
enumerable: false,
- 617 :
configurable: false,
- 618 :
writable: false,
- 619 :
value:() => $(CONST_HTML_HTML)
- 620 :
});
- 621 :
- 622 :
/**
- 623 :
* Classe qui permet de générer du html.
- 624 :
*
- 625 :
* Accepte plusieurs mel_html enfants pour génrer son html
- 626 :
*/
- 627 :
class mel_html2 extends mel_html {
- 628 :
/**
- 629 :
* Constructeur de la classe
- 630 :
* @param {string} tag Balise de l'élément
- 631 :
* @param {Object} options - Les options du constructeur.
- 632 :
* @param {Object} options.attribs - Attributs de l'élément
- 633 :
* @param {[] | mel_html | string} options.contents - Eléments enfants
- 634 :
*/
- 635 :
constructor(tag, {attribs={}, contents=[]}) {
- 636 :
super(tag, attribs, EMPTY_STRING);
- 637 :
this._init()._setup(contents);
- 638 :
}
- 639 :
- 640 :
_init() {
- 641 :
this.jcontents = [];
- 642 :
return this;
- 643 :
}
- 644 :
- 645 :
_setup(contents = []) {
- 646 :
if (!Array.isArray(contents)) {
- 647 :
if ('string' === typeof contents) contents = [new mel_html('span', {}, contents)];
- 648 :
else contents = [contents];
- 649 :
}
- 650 :
- 651 :
this.jcontents = contents;
- 652 :
return this;
- 653 :
}
- 654 :
- 655 :
/**
- 656 :
* Ajoute un élément enfant
- 657 :
* @param {mel_html} mel_html Elément à ajouter
- 658 :
* @returns Chaînage
- 659 :
*/
- 660 :
addContent(mel_html) {
- 661 :
this.jcontents.push(mel_html);
- 662 :
mel_html.parent = this;
- 663 :
return this;
- 664 :
}
- 665 :
- 666 :
_generateContent($html) {
- 667 :
for (let index = 0, len = this.jcontents.length; index < len; ++index) {
- 668 :
const element = this.jcontents[index];
- 669 :
element.create($html);
- 670 :
}
- 671 :
- 672 :
return $html;
- 673 :
}
- 674 :
- 675 :
/**
- 676 :
* Ajoute cet élément à un html parent
- 677 :
* @param {mel_html2} mel_html2
- 678 :
* @returns Chaînage
- 679 :
*/
- 680 :
appendTo(mel_html2) {
- 681 :
mel_html2.addContent(this);
- 682 :
return this;
- 683 :
}
- 684 :
- 685 :
/**
- 686 :
* Taille des éléments enfants
- 687 :
* @returns {number}
- 688 :
*/
- 689 :
count() {
- 690 :
return this.jcontents.length;
- 691 :
}
- 692 :
- 693 :
/**
- 694 :
* Récupère un élément enfant par son id
- 695 :
* @param {string} id Id de l'élément à retrouver
- 696 :
* @returns {mel_html | null}
- 697 :
*/
- 698 :
find_by_id(id) {
- 699 :
return Enumerable.from(this.jcontents).where(x => x.attribs['id'] === id).firstOrDefault();
- 700 :
}
- 701 :
- 702 :
/**
- 703 :
* Récupère des éléments enfant par une classe
- 704 :
* @param {string} html_class Classe que l'on recherche
- 705 :
* @returns {Enumerable<mel_html>}
- 706 :
*/
- 707 :
find_by_class(html_class) {
- 708 :
return Enumerable.from(this.jcontents).where(x => x.hasClass(html_class));
- 709 :
}
- 710 :
- 711 :
/**
- 712 :
* Récupère le premier élément enfant
- 713 :
* @returns {mel_html}
- 714 :
*/
- 715 :
first() {
- 716 :
return this.jcontents[0];
- 717 :
}
- 718 :
- 719 :
/**
- 720 :
* Récupère le premier élément enfant ou une valeur par défaut
- 721 :
* @param {* | null} _default Renvoyer si first n'éxiste pas
- 722 :
* @returns {mel_html | * | null}
- 723 :
*/
- 724 :
firstOrDefault(_default = null) {
- 725 :
try {
- 726 :
return this.first();
- 727 :
} catch (error) {
- 728 :
return _default;
- 729 :
}
- 730 :
}
- 731 :
- 732 :
/**
- 733 :
* Créer un mel_html2 qui représente une div
- 734 :
* @param {Object} options - Les options du constructeur.
- 735 :
* @param {Object} options.attribs - Attributs de l'élément
- 736 :
* @param {[] | mel_html | string} options.contents - Eléments enfants
- 737 :
* @returns {mel_html2}
- 738 :
*/
- 739 :
static div({attribs={}, contents=[]}) {
- 740 :
return new mel_html2('div', {attribs, contents});
- 741 :
}
- 742 :
}
- 743 :
- 744 :
class mel_option extends mel_html{
- 745 :
constructor(value, text, attribs = [])
- 746 :
{
- 747 :
super(CONST_HTML_SELECT, attribs, text);
- 748 :
this.attribs[CONST_ATTRIB_VALUE] = value;
- 749 :
}
- 750 :
}
- 751 :
- 752 :
class amel_form_item extends mel_html {
- 753 :
constructor(tag, attribs = {}, content = EMPTY_STRING, ignore_default_action = false)
- 754 :
{
- 755 :
super(tag, attribs, content);
- 756 :
- 757 :
if (!ignore_default_action) {
- 758 :
if (!this.attribs[CONST_ATTRIB_CLASS]) this.attribs[CONST_ATTRIB_CLASS] = EMPTY_STRING;
- 759 :
- 760 :
if (!this.attribs[CONST_ATTRIB_VALUE]) {
- 761 :
this.attribs[CONST_ATTRIB_VALUE] = `${amel_form_item.CLASS_FORM_BASE} ${amel_form_item.CLASS_FORM_MEL}`;
- 762 :
}
- 763 :
- 764 :
if (!this.attribs[CONST_ATTRIB_CLASS].includes(amel_form_item.CLASS_FORM_BASE))
- 765 :
{
- 766 :
this.attribs[CONST_ATTRIB_CLASS] += ` ${amel_form_item.CLASS_FORM_BASE}`;
- 767 :
}
- 768 :
- 769 :
if (!this.attribs[CONST_ATTRIB_CLASS].includes(amel_form_item.CLASS_FORM_MEL)) this.attribs[CONST_ATTRIB_CLASS] += ` ${amel_form_item.CLASS_FORM_MEL}`;
- 770 :
}
- 771 :
- 772 :
this.onfocusout = new MelEvent();
- 773 :
this.onfocus = new MelEvent();
- 774 :
this.onchange = new MelEvent();
- 775 :
this.oninput = new MelEvent();
- 776 :
}
- 777 :
- 778 :
toFloatingLabel(label) {
- 779 :
let $label = new mel_html(CONST_HTML_DIV, {class:amel_form_item.CLASS_FORM_FLOATING}, this.generate({required:CONST_ATTRIB_REQUIRED})).generate();
- 780 :
return $label.append(new mel_html(CONST_HTML_LABEL, {for:this.attribs[CONST_ATTRIB_ID]}, label).generate());
- 781 :
}
- 782 :
- 783 :
generate(value, additionnal_attribs = {})
- 784 :
{
- 785 :
let generated = super.generate(additionnal_attribs).val(value);
- 786 :
- 787 :
if (this.onfocus.haveEvents()) {
- 788 :
generated.on(CONST_EVENT_ACTION_FOCUS, (event) => {
- 789 :
this.onfocus.call(event);
- 790 :
});
- 791 :
}
- 792 :
- 793 :
if (this.onfocusout.haveEvents()) {
- 794 :
generated.on(CONST_EVENT_ACTION_BLUR, (event) => {
- 795 :
this.onfocusout.call(event);
- 796 :
});
- 797 :
}
- 798 :
- 799 :
if (this.oninput.haveEvents()) {
- 800 :
generated.on(CONST_EVENT_ACTION_INPUT, (event) => {
- 801 :
this.oninput.call(event);
- 802 :
});
- 803 :
}
- 804 :
- 805 :
if (this.onchange.haveEvents()) {
- 806 :
generated.on(CONST_EVENT_ACTION_CHANGE, (event) => {
- 807 :
this.onchange.call(event);
- 808 :
});
- 809 :
}
- 810 :
- 811 :
return generated;
- 812 :
}
- 813 :
}
- 814 :
- 815 :
Object.defineProperty(amel_form_item, 'CLASS_FORM_BASE', {
- 816 :
enumerable: false,
- 817 :
configurable: false,
- 818 :
writable: false,
- 819 :
value:CONST_CLASS_INPUT_FORM_BASE
- 820 :
});
- 821 :
- 822 :
Object.defineProperty(amel_form_item, 'CLASS_FORM_MEL', {
- 823 :
enumerable: false,
- 824 :
configurable: false,
- 825 :
writable: false,
- 826 :
value:CONST_CLASS_INPUT_FORM_MEL
- 827 :
});
- 828 :
- 829 :
Object.defineProperty(amel_form_item, 'CLASS_FORM_FLOATING', {
- 830 :
enumerable: false,
- 831 :
configurable: false,
- 832 :
writable: false,
- 833 :
value:CONST_CLASS_INPUT_FORM_FLOATING
- 834 :
});
- 835 :
- 836 :
Object.defineProperty(amel_form_item, 'CLASS_FORM_FLOATING_FOCUS', {
- 837 :
enumerable: false,
- 838 :
configurable: false,
- 839 :
writable: false,
- 840 :
value:CONST_CLASS_INPUT_FORM_FLOATING_FOCUS
- 841 :
});
- 842 :
- 843 :
Object.defineProperty(amel_form_item, 'CLASS_INPUT_FORM_FLOATING_NOT_EMPTY', {
- 844 :
enumerable: false,
- 845 :
configurable: false,
- 846 :
writable: false,
- 847 :
value:CONST_CLASS_INPUT_FORM_FLOATING_NOT_EMPTY
- 848 :
});
- 849 :
- 850 :
class mel_field extends amel_form_item {
- 851 :
constructor(tag, attribs = {})
- 852 :
{
- 853 :
super(tag, attribs, '', true);
- 854 :
}
- 855 :
}
- 856 :
- 857 :
- 858 :
class mel_select extends amel_form_item{
- 859 :
constructor(attribs = {}, options = [])
- 860 :
{
- 861 :
super(CONST_HTML_SELECT, attribs, options);
- 862 :
}
- 863 :
- 864 :
_generateContent($html, content) {
- 865 :
for (const iterator of content) {
- 866 :
iterator.create($html);
- 867 :
}
- 868 :
- 869 :
return $html;
- 870 :
}
- 871 :
}
- 872 :
- 873 :
class mel_input extends amel_form_item
- 874 :
{
- 875 :
constructor(attribs = {})
- 876 :
{
- 877 :
super(CONST_HTML_INPUT, attribs, EMPTY_STRING);
- 878 :
}
- 879 :
- 880 :
static togglePasswordShowed(element) {
- 881 :
const INPUT_DATA = CONST_ATTRIB_FOR;
- 882 :
const IS_SHOWED_DATA = 'isShowed';
- 883 :
const DATA_VALID = 'yes';
- 884 :
const DATA_INVALID = 'no';
- 885 :
const ATTR = CONST_ATTRIB_TYPE;
- 886 :
const ATTR_PASSWORD = CONST_ATTRIB_TYPE_PASSWORD;
- 887 :
const ATTR_TEXT = CONST_ATTRIB_TYPE_TEXT;
- 888 :
element = $(element);
- 889 :
let $input = $(`${CONST_JQUERY_SELECTOR_ID}${element.data(INPUT_DATA)}`);
- 890 :
- 891 :
if (0 === $input.length) $input = top.$(`${CONST_JQUERY_SELECTOR_ID}${element.data(INPUT_DATA)}`);
- 892 :
- 893 :
if (0 < $input.length)
- 894 :
{
- 895 :
if (DATA_VALID === $input.data(IS_SHOWED_DATA)) {
- 896 :
$input.attr(ATTR, ATTR_PASSWORD);
- 897 :
$input.data(IS_SHOWED_DATA, DATA_INVALID);
- 898 :
}
- 899 :
else {
- 900 :
$input.attr(ATTR, ATTR_TEXT);
- 901 :
$input.data(IS_SHOWED_DATA, DATA_VALID);
- 902 :
}
- 903 :
}
- 904 :
- 905 :
mel_input.togglePasswordShowed.updateButton(element);
- 906 :
}
- 907 :
- 908 :
static floatingSetFocusClass(element, isOut = false) {
- 909 :
const DIV = CONST_ATTRIB_FOR;
- 910 :
const CLASS = amel_form_item.CLASS_FORM_FLOATING_FOCUS;
- 911 :
element = $(element);
- 912 :
let $div = $(`${CONST_JQUERY_SELECTOR_ID}${element.data(DIV)}`);
- 913 :
- 914 :
if (0 === $div.length) $div = top.$(`${CONST_JQUERY_SELECTOR_ID}${element.data(DIV)}`);
- 915 :
- 916 :
if ($div.length > 0) {
- 917 :
if (isOut) {
- 918 :
$div.removeClass(CLASS);
- 919 :
}
- 920 :
else {
- 921 :
$div.addClass(CLASS);
- 922 :
}
- 923 :
}
- 924 :
}
- 925 :
- 926 :
static floatingSetInput(element) {
- 927 :
const DIV = CONST_ATTRIB_FOR;
- 928 :
const CLASS = amel_form_item.CLASS_INPUT_FORM_FLOATING_NOT_EMPTY;
- 929 :
element = $(element);
- 930 :
let $div = $(`${CONST_JQUERY_SELECTOR_ID}${element.data(DIV)}`);
- 931 :
- 932 :
if ($div.length === 0) $div = top.$(`${CONST_JQUERY_SELECTOR_ID}${element.data(DIV)}`);
- 933 :
- 934 :
if ($div.length > 0) {
- 935 :
if (EMPTY_STRING !== element.val()) $div.addClass(CLASS);
- 936 :
else $div.removeClass(CLASS);
- 937 :
}
- 938 :
}
- 939 :
}
- 940 :
- 941 :
class mel_label_input extends mel_input {
- 942 :
constructor(id, type, label, attribs = {}) {
- 943 :
super(attribs);
- 944 :
- 945 :
this.id = id;
- 946 :
this.type = type;
- 947 :
this.label = label;
- 948 :
}
- 949 :
- 950 :
_before_generate() {
- 951 :
this.setId(this.id);
- 952 :
this.attribs.type = this.type;
- 953 :
}
- 954 :
- 955 :
generate(value, attribs = {}, parent_attribs = {}) {
- 956 :
let $generated = super.generate(value, attribs);
- 957 :
- 958 :
const html_label = new mel_html('label', {for:this.id}, this.label);
- 959 :
let $parent_div = new mel_html2('div', {
- 960 :
attribs:parent_attribs,
- 961 :
contents:html_label
- 962 :
}).generate();
- 963 :
- 964 :
$parent_div.append($generated);
- 965 :
$generated = null;
- 966 :
- 967 :
return $parent_div;
- 968 :
}
- 969 :
}
- 970 :
- 971 :
class mel_password extends mel_input {
- 972 :
constructor(attribs = {})
- 973 :
{
- 974 :
super(attribs);
- 975 :
this.attribs[CONST_ATTRIB_TYPE] = CONST_ATTRIB_TYPE_PASSWORD;
- 976 :
}
- 977 :
}
- 978 :
- 979 :
mel_input.togglePasswordShowed.updateButton = function ($event) {
- 980 :
const DATA_SHOW = 'icon-show';
- 981 :
const DATA_HIDE = 'icon-hide';
- 982 :
const BALISE = CONST_HTML_SPAN;
- 983 :
- 984 :
const icon_show = $event.data(DATA_SHOW);
- 985 :
- 986 :
if (!!icon_show) {
- 987 :
const icon_hide = $event.data(DATA_HIDE);
- 988 :
- 989 :
if (!!icon_hide) {
- 990 :
let $span = $event.find(BALISE);
- 991 :
- 992 :
if ($span.hasClass(icon_show)) {
- 993 :
$span.removeClass(icon_show).addClass(icon_hide);
- 994 :
} else {
- 995 :
$span.removeClass(icon_hide).addClass(icon_show);
- 996 :
}
- 997 :
}
- 998 :
}
- 999 :
- 1000 :
- 1001 :
}
- 1002 :
- 1003 :
class mel_password_with_button extends mel_password{
- 1004 :
constructor(id, input_id, attribs = {}, attribsOnParent = {}, attribsOnButton = {}) {
- 1005 :
super(attribs);
- 1006 :
this.id = id;
- 1007 :
this._id = input_id;
- 1008 :
this.main = new mel_html('div', attribsOnParent);
- 1009 :
this.button = new mel_button(attribsOnButton);
- 1010 :
this.button_span = new mel_html('span', {class:'icon-mel-eye'});
- 1011 :
- 1012 :
this.onfocus.push(function (event) {
- 1013 :
mel_input.floatingSetFocusClass(event.currentTarget, false);
- 1014 :
});
- 1015 :
- 1016 :
this.onfocusout.push(function (event) {
- 1017 :
mel_input.floatingSetFocusClass(event.currentTarget, true);
- 1018 :
});
- 1019 :
- 1020 :
this.oninput.push(function (event) {
- 1021 :
mel_input.floatingSetInput(event.currentTarget);
- 1022 :
});
- 1023 :
- 1024 :
this.button.onclick.push(function (event) {
- 1025 :
mel_input.togglePasswordShowed(event.currentTarget);
- 1026 :
});
- 1027 :
}
- 1028 :
- 1029 :
generate(value, label = 'Mot de passe', additionnal_attribs = {})
- 1030 :
{
- 1031 :
const DATA_FOR = 'data-for';
- 1032 :
const CLASS_INPUT_GROUP = 'input-group';
- 1033 :
const CLASS_RETURN = 'form-floating pixel-correction';
- 1034 :
const ATTR_ID = 'id';
- 1035 :
const ATTR_REQUIRED = 'required';
- 1036 :
const BALISE_LABEL = 'label';
- 1037 :
const BALISE_DIV = 'div';
- 1038 :
- 1039 :
const button_config = {
- 1040 :
'data-for':this._id,
- 1041 :
'data-icon-show':mel_password_with_button.password_show_button,
- 1042 :
'data-icon-hide':mel_password_with_button.password_hide_button,
- 1043 :
};
- 1044 :
const main_config = {class:CLASS_INPUT_GROUP};
- 1045 :
const return_config = {id:this.id, class:CLASS_RETURN};
- 1046 :
const label_config = {for:button_config[DATA_FOR]};
- 1047 :
- 1048 :
additionnal_attribs[DATA_FOR] = return_config.id;
- 1049 :
additionnal_attribs[ATTR_ID] = button_config[DATA_FOR];
- 1050 :
additionnal_attribs[ATTR_REQUIRED] = ATTR_REQUIRED;
- 1051 :
additionnal_attribs['class'] = 'input-mel';
- 1052 :
- 1053 :
let $input = super.generate(value, additionnal_attribs);
- 1054 :
let $button = new mel_html(BALISE_DIV, {class:'input-group-append'}).generate().append(this.button.generate(button_config).append(this.button_span.generate()));
- 1055 :
let $main = this.main.generate(main_config).append($input).append($button);
- 1056 :
let $label = new mel_html(BALISE_LABEL, label_config, label);
- 1057 :
- 1058 :
return new mel_html(BALISE_DIV).generate(return_config).append($main).append($label.generate());
- 1059 :
}
- 1060 :
}
- 1061 :
- 1062 :
Object.defineProperty(mel_password_with_button, 'password_show_button', {
- 1063 :
enumerable: false,
- 1064 :
configurable: false,
- 1065 :
writable: false,
- 1066 :
value:CONST_ICON_EYE
- 1067 :
});
- 1068 :
- 1069 :
Object.defineProperty(mel_password_with_button, 'password_hide_button', {
- 1070 :
enumerable: false,
- 1071 :
configurable: false,
- 1072 :
writable: false,
- 1073 :
value:CONST_ICON_EYE_CROSSED
- 1074 :
});
- 1075 :
- 1076 :
class mel_button extends mel_html {
- 1077 :
constructor(attribs = {}, content = EMPTY_STRING)
- 1078 :
{
- 1079 :
super(CONST_HTML_BUTTON, attribs, content);
- 1080 :
this.attribs[CONST_ATTRIB_CLASS] = mel_button.html_base_class_full;//'mel-button btn btn-secondary no-button-margin'
- 1081 :
}
- 1082 :
}
- 1083 :
- 1084 :
{
- 1085 :
let item = {};
- 1086 :
let bootstrap = {};
- 1087 :
Object.defineProperty(item, 'base', {
- 1088 :
enumerable: false,
- 1089 :
configurable: false,
- 1090 :
writable: false,
- 1091 :
value:CONST_CLASS_BUTTON_MEL
- 1092 :
});
- 1093 :
- 1094 :
Object.defineProperty(bootstrap, 'base', {
- 1095 :
enumerable: false,
- 1096 :
configurable: false,
- 1097 :
writable: false,
- 1098 :
value:CONST_CLASS_BUTTON_BASE
- 1099 :
});
- 1100 :
- 1101 :
Object.defineProperty(bootstrap, 'state', {
- 1102 :
enumerable: false,
- 1103 :
configurable: false,
- 1104 :
writable: false,
- 1105 :
value:CONST_CLASS_BUTTON_SECONDARY
- 1106 :
});
- 1107 :
- 1108 :
Object.defineProperty(item, 'bootstrap', {
- 1109 :
enumerable: false,
- 1110 :
configurable: false,
- 1111 :
writable: false,
- 1112 :
value:bootstrap
- 1113 :
});
- 1114 :
- 1115 :
Object.defineProperty(mel_button, 'html_base_class', {
- 1116 :
enumerable: false,
- 1117 :
configurable: false,
- 1118 :
writable: false,
- 1119 :
value:item
- 1120 :
});
- 1121 :
}
- 1122 :
- 1123 :
Object.defineProperty(mel_button, 'html_base_class_no_margin', {
- 1124 :
enumerable: false,
- 1125 :
configurable: false,
- 1126 :
writable: false,
- 1127 :
value:CONST_CLASS_BUTTON_MEL_NO_MARGIN
- 1128 :
});
- 1129 :
- 1130 :
Object.defineProperty(mel_button, 'html_base_class_success', {
- 1131 :
enumerable: false,
- 1132 :
configurable: false,
- 1133 :
writable: false,
- 1134 :
value:CONST_CLASS_BUTTON_SUCCESS
- 1135 :
});
- 1136 :
- 1137 :
Object.defineProperty(mel_button, 'html_base_class_danger', {
- 1138 :
enumerable: false,
- 1139 :
configurable: false,
- 1140 :
writable: false,
- 1141 :
value:CONST_CLASS_BUTTON_DANGER
- 1142 :
});
- 1143 :
- 1144 :
Object.defineProperty(mel_button, 'html_base_class_full', {
- 1145 :
enumerable: false,
- 1146 :
configurable: false,
- 1147 :
writable: false,
- 1148 :
value:`${mel_button.html_base_class.base} ${mel_button.html_base_class_no_margin} ${mel_button.html_base_class.bootstrap.base} ${mel_button.html_base_class.bootstrap.state}`
- 1149 :
});
- 1150 :
- 1151 :
class mel_tab extends mel_button{
- 1152 :
constructor(namespace, id, attribs={}, text) {
- 1153 :
super(attribs, text);
- 1154 :
this._init()._setup(id);
- 1155 :
}
- 1156 :
- 1157 :
_init() {
- 1158 :
this.namespace = EMPTY_STRING;
- 1159 :
this.id = EMPTY_STRING;
- 1160 :
/**
- 1161 :
* @type {mel_tabpanel}
- 1162 :
*/
- 1163 :
this.control = null;
- 1164 :
return this;
- 1165 :
}
- 1166 :
- 1167 :
_setup(namespace, id){
- 1168 :
this.id = id;
- 1169 :
this.namespace = namespace;
- 1170 :
return this;
- 1171 :
}
- 1172 :
- 1173 :
generate(attribs={}) {
- 1174 :
attribs['id'] = id;
- 1175 :
attribs['tabindex'] = -1;
- 1176 :
attribs['aria-controls'] = this.control?.attribs?.['id'];
- 1177 :
attribs['role'] = 'tab';
- 1178 :
attribs['type'] = 'button';
- 1179 :
attribs['aria-selected'] = attribs?.['aria-selected'] ?? false;
- 1180 :
attribs['class'] = this.namespace + ' mel-html-tab';
- 1181 :
attribs['data-tabnamespace'] = this.namespace;
- 1182 :
- 1183 :
this.onclick.push((e) => {
- 1184 :
e = $(e.currentTarget);
- 1185 :
MelAsync.forof($(`button.mel-html-tab.${e.data('tabnamespace')}`), async (iterator) => {
- 1186 :
$(iterator).removeClass('selected').attr('aria-selected', false);
- 1187 :
}, false).then(() => {
- 1188 :
e.addClass('selected').attr('aria-selected', true);
- 1189 :
});
- 1190 :
- 1191 :
MelAsync.forof($(`mel-html-tabpanel.mel-html-tab.${e.data('tabnamespace')}`), async (iterator) => {
- 1192 :
$(iterator).css('display', 'none');
- 1193 :
}, false).then(() => {
- 1194 :
$(`mel-html-tabpanel.mel-html-tab.${e.data('tabnamespace')}.${this.id}`);
- 1195 :
});
- 1196 :
});
- 1197 :
- 1198 :
this.onkeydown.push((event) => {
- 1199 :
let tabs = $(`button.mel-html-tab.${e.data('tabnamespace')}`);
- 1200 :
const key = event.keyCode;
- 1201 :
- 1202 :
let direction = 0;
- 1203 :
switch (key) {
- 1204 :
case this.keys.left:
- 1205 :
direction = -1;
- 1206 :
break;
- 1207 :
case this.keys.right:
- 1208 :
direction = 1;
- 1209 :
break;
- 1210 :
- 1211 :
case this.keys.home:
- 1212 :
$(tabs[0]).focus().click();
- 1213 :
break;
- 1214 :
case this.keys.end:
- 1215 :
$(tabs[tabs.length-1]).focus().click();
- 1216 :
break;
- 1217 :
- 1218 :
default:
- 1219 :
break;
- 1220 :
}
- 1221 :
- 1222 :
if (direction !== 0)
- 1223 :
{
- 1224 :
for (let index = 0; index < tabs.length; ++index) {
- 1225 :
const element = $(tabs[index]);
- 1226 :
- 1227 :
if (element.hasClass("selected") || element.hasClass("active"))
- 1228 :
{
- 1229 :
let id;
- 1230 :
if (index + direction < 0)
- 1231 :
id = tabs.length - 1;
- 1232 :
else if (index + direction >= tabs.length)
- 1233 :
id = 0;
- 1234 :
else
- 1235 :
id = index + direction;
- 1236 :
- 1237 :
$(tabs[id]).focus().click();
- 1238 :
- 1239 :
break;
- 1240 :
}
- 1241 :
}
- 1242 :
}
- 1243 :
});
- 1244 :
- 1245 :
return super.generate(attribs);
- 1246 :
}
- 1247 :
- 1248 :
select(selected) {
- 1249 :
attribs['aria-selected'] = selected;
- 1250 :
return this;
- 1251 :
}
- 1252 :
- 1253 :
setControl(controler) {
- 1254 :
this.control = controler;
- 1255 :
return this;
- 1256 :
}
- 1257 :
- 1258 :
}
- 1259 :
class mel_tablist extends mel_html {
- 1260 :
constructor(namespace, id, {
- 1261 :
attribs={},
- 1262 :
tabs=[],
- 1263 :
label=EMPTY_STRING
- 1264 :
}) {
- 1265 :
super('div', attribs);
- 1266 :
this._init()._setup(namespace, id, {tabs, label});
- 1267 :
}
- 1268 :
- 1269 :
_init() {
- 1270 :
/**
- 1271 :
* @type {mel_tab[]}
- 1272 :
*/
- 1273 :
this.tabs = [];
- 1274 :
this.id = EMPTY_STRING;
- 1275 :
this.label = EMPTY_STRING;
- 1276 :
this.namespace = EMPTY_STRING;
- 1277 :
return this;
- 1278 :
}
- 1279 :
- 1280 :
_setup(namespace, id, {tabs=[], label=EMPTY_STRING})
- 1281 :
{
- 1282 :
this.id = id;
- 1283 :
this.tabs = tabs;
- 1284 :
this.label = label;
- 1285 :
this.namespace = namespace;
- 1286 :
return this;
- 1287 :
}
- 1288 :
- 1289 :
generate(attribs={}){
- 1290 :
attribs['role'] = 'tablist';
- 1291 :
let $tablist = super.generate(attribs);
- 1292 :
- 1293 :
for (let index = 0, len = this.tabs.length; index < len; ++index) {
- 1294 :
this.tabs[index].generate().appendTo($tablist);
- 1295 :
}
- 1296 :
- 1297 :
new mel_html('label', {for:this.id, class:'sr-only'}).generate().appendTo($tablist);
- 1298 :
- 1299 :
return $tablist;
- 1300 :
}
- 1301 :
- 1302 :
/**
- 1303 :
*
- 1304 :
* @returns {mel_tab}
- 1305 :
*/
- 1306 :
getSelectedTab() {
- 1307 :
return Enumerable.from(this.tabs).where(x => x.attribs['aria-selected'] === true).firstOrDefault();
- 1308 :
}
- 1309 :
- 1310 :
/**
- 1311 :
*
- 1312 :
* @param {mel_tab} tab
- 1313 :
*/
- 1314 :
addTab(tab) {
- 1315 :
this.tabs.push(tab.setControl(this.pannel));
- 1316 :
return this;
- 1317 :
}
- 1318 :
}
- 1319 :
- 1320 :
class mel_tabpanel extends mel_html {
- 1321 :
constructor(namespace, tab, {attribs={}, contents=EMPTY_STRING, jquery_content = null}) {
- 1322 :
super('div', attribs, contents);
- 1323 :
this._init()._setup(tab, {jquery_content});
- 1324 :
}
- 1325 :
- 1326 :
_init() {
- 1327 :
this.namespace = EMPTY_STRING;
- 1328 :
/**
- 1329 :
* @type {mel_tab}
- 1330 :
*/
- 1331 :
this.tab = null;
- 1332 :
/**
- 1333 :
* @type {mel_html[]}
- 1334 :
*/
- 1335 :
this.pannels = [];
- 1336 :
this.jcontent = null;
- 1337 :
return this;
- 1338 :
}
- 1339 :
- 1340 :
_setup(namespace, tab, {jquery_content = null}) {
- 1341 :
this.tab = tab;
- 1342 :
this.jcontent = jquery_content;
- 1343 :
this.namespace = namespace;
- 1344 :
return this;
- 1345 :
}
- 1346 :
- 1347 :
generate(attribs={}){
- 1348 :
attribs['aria-labelledby'] = this.tab.id;
- 1349 :
attribs['tabindex'] = 0;
- 1350 :
attribs['class'] = `${this.tab.id} ${this.namespace} mel-html-tabpanel`;
- 1351 :
let $generated = super.generate(attribs);
- 1352 :
- 1353 :
if (!!this.jcontent) this.jcontent.appendTo($generated);
- 1354 :
- 1355 :
return $generated;
- 1356 :
}
- 1357 :
}
- 1358 :
- 1359 :
class mel_tabs extends mel_html {
- 1360 :
constructor(id, label, {attribs={}, tablist_attribs={}}) {
- 1361 :
super('div', attribs);
- 1362 :
this._init()._setup(id, label, {tablist_attribs});
- 1363 :
}
- 1364 :
- 1365 :
_init() {
- 1366 :
/**
- 1367 :
* @type {mel_tablist}
- 1368 :
*/
- 1369 :
this.tabs = null;
- 1370 :
/**
- 1371 :
* @type {mel_tabpanel[]}
- 1372 :
*/
- 1373 :
this.contents = null;
- 1374 :
return this;
- 1375 :
}
- 1376 :
- 1377 :
_setup(id, label, {tablist_attribs={}}) {
- 1378 :
this.tabs = new mel_tablist(id, {label, attribs:tablist_attribs})
- 1379 :
this.contents = [];
- 1380 :
return this;
- 1381 :
}
- 1382 :
- 1383 :
add(id, tabtext, pannel, selectedTab = false) {
- 1384 :
let tab = new mel_tab(id, {}, tabtext);
- 1385 :
let mel_pannel = new mel_tabpanel(tab, {jquery_content:pannel});
- 1386 :
this.tabs.addTab(tab.select(selectedTab).setControl(mel_pannel));
- 1387 :
this.contents.push(mel_pannel);
- 1388 :
tab = (mel_pannel = null, null);
- 1389 :
return this;
- 1390 :
}
- 1391 :
- 1392 :
generate({attribs={}, tablist_attribs={}}) {
- 1393 :
let $generated = super.generate(attribs);
- 1394 :
this.tabs.generate(tablist_attribs).appendTo($generated);
- 1395 :
- 1396 :
const selected_tab = this.tabs.getSelectedTab();
- 1397 :
- 1398 :
for (let index = 0, len = this.contents.length, content; index < len; ++index) {
- 1399 :
const element = this.contents[index];
- 1400 :
content = this.contents.generate();
- 1401 :
- 1402 :
if (!!selected_tab && selected_tab.id === element.tab.id) content.css('display', '');
- 1403 :
else content.css('display', 'none');
- 1404 :
- 1405 :
content.appendTo($generated);
- 1406 :
}
- 1407 :
- 1408 :
return $generated;
- 1409 :
- 1410 :
}
- 1411 :
- 1412 :
}
- 1413 :
- 1414 :
class mel_iframe extends mel_html {
- 1415 :
constructor(src, attribs = {}) {
- 1416 :
super('iframe', attribs);
- 1417 :
this.src = src;
- 1418 :
this.onload = new MelEvent();
- 1419 :
}
- 1420 :
- 1421 :
generate(extra_attribs = {}) {
- 1422 :
if (Array.isArray(extra_attribs)) extra_attribs = {};
- 1423 :
- 1424 :
extra_attribs[mel_html.ATTRIB_NO_MULTI_BALISE] = true;
- 1425 :
extra_attribs.src = this.src;
- 1426 :
return super.generate(extra_attribs).on('load', (e) => {
- 1427 :
this.onload.call(e);
- 1428 :
});
- 1429 :
}
- 1430 :
}