|
8 | 8 |
|
9 | 9 | use Chamilo\CoreBundle\Entity\ConferenceActivity; |
10 | 10 | use Chamilo\CoreBundle\Entity\ConferenceMeeting; |
| 11 | +use Chamilo\CoreBundle\Enums\ActionIcon; |
11 | 12 | use Chamilo\CourseBundle\Entity\CGroup; |
12 | 13 |
|
13 | 14 | $course_plugin = 'bbb'; // Needed to load plugin lang variables. |
|
435 | 436 | if ($conferenceManager && $allowToEdit) { |
436 | 437 | $form = new FormValidator('start_conference', 'post', $conferenceUrl); |
437 | 438 | $form->addElement('hidden', 'action', 'start'); |
438 | | - $ajaxUrl = api_get_path(WEB_PATH).'main/inc/ajax/plugin.ajax.php?plugin=bbb&a=list_documents&'.api_get_cidreq(); |
| 439 | + $ajaxUrl = api_get_path(WEB_PATH).'main/inc/ajax/plugin.ajax.php?plugin=bbb&a=list_documents&'.api_get_cidreq(); |
| 440 | + $maxTotalMb = (int) api_get_course_plugin_setting('bbb', 'bbb_preupload_max_total_mb', $courseInfo); |
| 441 | + if ($maxTotalMb <= 0) { $maxTotalMb = 20; } |
| 442 | + |
| 443 | + $title = htmlspecialchars(get_lang('Pre-upload Documents'), ENT_QUOTES); |
| 444 | + $help = htmlspecialchars(get_lang('Select the PDF or PPTX files you want to pre-load as slides for the conference.'), ENT_QUOTES); |
| 445 | + $loadingTxt = htmlspecialchars(get_lang('Loading'), ENT_QUOTES); |
| 446 | + $noDocsTxt = htmlspecialchars(get_lang('No documents found'), ENT_QUOTES); |
| 447 | + $failTxt = htmlspecialchars(get_lang('Failed to load documents'), ENT_QUOTES); |
| 448 | + $maxLabel = htmlspecialchars(sprintf(get_lang('Max total: %d MB'), $maxTotalMb), ENT_QUOTES); |
| 449 | + |
| 450 | + $iconHtml = Display::getMdiIcon( |
| 451 | + ActionIcon::UPLOAD, |
| 452 | + 'ch-tool-icon', |
| 453 | + null, |
| 454 | + ICON_SIZE_MEDIUM, |
| 455 | + $title |
| 456 | + ); |
439 | 457 |
|
440 | | - // Pre-upload UI: fetch available course docs and render as checkboxes. |
441 | 458 | $preuploadHtml = ' |
442 | | - <details id="preupload-documents" class="mt-4 border rounded p-3 bg-gray-100"> |
443 | | - <summary class="font-semibold cursor-pointer">'.get_lang('Pre-upload Documents').'</summary> |
444 | | - <div class="mt-2 text-gray-700"> |
445 | | - <p class="text-sm mb-2">'.get_lang('Select the PDF or PPTX files you want to pre-load as slides for the conference.').'</p> |
446 | | - <div id="preupload-list">'.get_lang('Loading').'…</div> |
447 | | - </div> |
448 | | - </details> |
449 | | - <script> |
450 | | - document.addEventListener("DOMContentLoaded", function() { |
451 | | - var det = document.getElementById("preupload-documents"); |
452 | | - if (!det) return; |
453 | | - det.addEventListener("toggle", function once() { |
454 | | - if (!det.open) return; |
455 | | - det.removeEventListener("toggle", once); |
456 | | - fetch("'.$ajaxUrl.'", {credentials:"same-origin"}) |
| 459 | +<div class="bbb-preupload" style="position:relative;"> |
| 460 | + <button type="button" id="bbb-pre-btn" |
| 461 | + class="btn btn--icon" |
| 462 | + title="'.$title.'" |
| 463 | + style="position:absolute; right:0; top:-8px;"> |
| 464 | + '.$iconHtml.' |
| 465 | + </button> |
| 466 | +
|
| 467 | + <div id="bbb-pre-pop" class="hidden" |
| 468 | + style="position:absolute; right:0; top:28px; z-index:50; |
| 469 | + width:340px; background:#fff; border:1px solid #e5e7eb; |
| 470 | + border-radius:8px; box-shadow:0 8px 24px rgba(0,0,0,.12); |
| 471 | + padding:10px;"> |
| 472 | + <div class="text-sm" style="margin-bottom:6px; color:#475569;">'.$help.'</div> |
| 473 | + <div id="preupload-list" |
| 474 | + class="text-sm" |
| 475 | + style="max-height:220px; overflow:auto; border:1px solid #eef2f7; |
| 476 | + border-radius:6px; padding:8px; color:#0f172a;"> |
| 477 | + '.$loadingTxt.'… |
| 478 | + </div> |
| 479 | + <div class="text-xs" style="margin-top:6px; color:#64748b;"> |
| 480 | + '.$maxLabel.' — <span id="preupload-total">0</span> MB |
| 481 | + </div> |
| 482 | + </div> |
| 483 | +</div> |
| 484 | +
|
| 485 | +<script> |
| 486 | +(function(){ |
| 487 | + var btn = document.getElementById("bbb-pre-btn"); |
| 488 | + var pop = document.getElementById("bbb-pre-pop"); |
| 489 | + var list = document.getElementById("preupload-list"); |
| 490 | + var loaded = false; |
| 491 | + var ajax = "'.$ajaxUrl.'"; |
| 492 | + var maxMb = '.$maxTotalMb.'; |
| 493 | +
|
| 494 | + function esc(t){ |
| 495 | + return String(t).replace(/[&<>\"\\\']/g, function(s){ |
| 496 | + return {"&":"&","<":"<",">":">","\\"":""","\\\'":"'"}[s]; |
| 497 | + }); |
| 498 | + } |
| 499 | +
|
| 500 | + function togglePop(){ |
| 501 | + if (pop.classList.contains("hidden")) { |
| 502 | + pop.classList.remove("hidden"); |
| 503 | + if (!loaded) { |
| 504 | + loaded = true; |
| 505 | + fetch(ajax, {credentials:"same-origin"}) |
457 | 506 | .then(function(r){ return r.json(); }) |
458 | | - .then(function(docs){ |
459 | | - var c = document.getElementById("preupload-list"); |
460 | | - if (!Array.isArray(docs) || !docs.length) { |
461 | | - c.innerHTML = \'<p class="text-sm text-gray-500">'.addslashes(get_lang('No documents found.')).'</p>\'; |
462 | | - return; |
463 | | - } |
464 | | - var filtered = docs.filter(function(doc){ |
465 | | - return (doc.filename || "").match(/\\.(pdf|ppt|pptx|odp)$/i); |
466 | | - }); |
467 | | - if (!filtered.length) { |
468 | | - c.innerHTML = \'<p class="text-sm text-gray-500">'.addslashes(get_lang('No documents found.')).'</p>\'; |
469 | | - return; |
470 | | - } |
471 | | - c.innerHTML = filtered.map(function(doc){ |
472 | | - var data = JSON.stringify({url:doc.url, filename:doc.filename}).replace(/"/g, """); |
473 | | - return \'<label class="block"><input type="checkbox" name="documents[]" value="\' + data + \'"> \' + (doc.filename || "") + \'</label>\'; |
474 | | - }).join(""); |
475 | | - }) |
| 507 | + .then(renderList) |
476 | 508 | .catch(function(){ |
477 | | - document.getElementById("preupload-list").innerHTML = |
478 | | - \'<p class="text-sm text-red-500">'.addslashes(get_lang('Failed to load documents.')).'</p>\'; |
| 509 | + list.innerHTML = \'<p class="text-sm" style="color:#dc2626">'.$failTxt.'</p>\'; |
479 | 510 | }); |
480 | | - }); |
| 511 | + } |
| 512 | + } else { |
| 513 | + pop.classList.add("hidden"); |
| 514 | + } |
| 515 | + } |
| 516 | +
|
| 517 | + function clickOutside(e){ |
| 518 | + if (!pop.contains(e.target) && !btn.contains(e.target)) { |
| 519 | + pop.classList.add("hidden"); |
| 520 | + } |
| 521 | + } |
| 522 | +
|
| 523 | + function renderList(docs){ |
| 524 | + var items = Array.isArray(docs) ? docs.filter(function(d){ |
| 525 | + return (d.filename||"").match(/\\.(pdf|ppt|pptx|odp)$/i); |
| 526 | + }) : []; |
| 527 | +
|
| 528 | + if (!items.length) { |
| 529 | + list.innerHTML = \'<p class="text-sm" style="color:#64748b">'.$noDocsTxt.'</p>\'; |
| 530 | + return; |
| 531 | + } |
| 532 | +
|
| 533 | + list.innerHTML = items.map(function(doc){ |
| 534 | + var data = JSON.stringify({url:doc.url, filename:doc.filename, size:doc.size}).replace(/"/g,"""); |
| 535 | + return \'<label class="flex items-center gap-2" style="display:flex;align-items:center;gap:.5rem;margin:.25rem 0;">\' |
| 536 | + + \'<input type="checkbox" class="h-4 w-4" name="documents[]" value="\' + data + \'" />\' |
| 537 | + + \'<span class="truncate">\' + esc(doc.filename||"") + \'</span>\' |
| 538 | + + \'</label>\'; |
| 539 | + }).join(""); |
| 540 | +
|
| 541 | + list.addEventListener("change", recalcTotal, true); |
| 542 | + } |
| 543 | +
|
| 544 | + function recalcTotal(){ |
| 545 | + var boxes = list.querySelectorAll(\'input[type="checkbox"]:checked\'); |
| 546 | + var total = 0; |
| 547 | + boxes.forEach(function(b){ |
| 548 | + try { var o = JSON.parse(b.value.replace(/"/g, \'"\')); total += (o.size||0); } catch(e){} |
481 | 549 | }); |
482 | | - </script>'; |
| 550 | + var mb = (total/1048576).toFixed(1); |
| 551 | + var out = document.getElementById("preupload-total"); |
| 552 | + if (out) out.textContent = mb; |
| 553 | +
|
| 554 | + var submit = document.querySelector(\'form[name="start_conference"] [type="submit"]\'); |
| 555 | + if (submit) submit.disabled = (total > maxMb * 1048576); |
| 556 | + } |
| 557 | +
|
| 558 | + if (btn) btn.addEventListener("click", togglePop); |
| 559 | + document.addEventListener("click", clickOutside); |
| 560 | +})(); |
| 561 | +</script>'; |
483 | 562 |
|
484 | 563 | $form->addElement('html', $preuploadHtml); |
485 | 564 | $form->addElement( |
|
0 commit comments