diff --git a/launch.html b/launch.html
index 3e4482e..7d77e56 100644
--- a/launch.html
+++ b/launch.html
@@ -249,6 +249,29 @@
color: #0066cc;
}
+ .adhoc-result {
+ margin-top: 24px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #f0fff4;
+ color: #1a7f37;
+ }
+
+ .adhoc-link {
+ margin-top: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+
+ .adhoc-link a {
+ font-family: monospace;
+ word-break: break-all;
+ color: #0066cc;
+ }
+
@keyframes spin {
to {
transform: rotate(360deg);
@@ -315,6 +338,15 @@
background: #1a3a5a;
color: #99ccff;
}
+
+ :root.dark .adhoc-result {
+ background: #1c3527;
+ color: #7ee2a8;
+ }
+
+ :root.dark .adhoc-link a {
+ color: #99ccff;
+ }
@@ -549,10 +581,21 @@
+
+
+
+
Your adhoc meeting link:
+
+
Meeting created! Download your calendar file and open it to import the meeting into your personal calendar.
@@ -685,6 +728,10 @@
successMessage: "Meeting created! Download your calendar file and open it to import the meeting into your personal calendar.",
downloadButton: "Download ICS File",
createNewButton: "Create New Meeting",
+ adhocButton: "Create Adhoc Link",
+ adhocLinkLabel: "Your adhoc meeting link:",
+ copyLinkButton: "Copy Link",
+ copiedLabel: "Copied!",
meetingNameRequired: "Please enter a meeting name",
meetingNameInvalid: "Meeting name may only contain letters, numbers and hyphens",
startTimeRequired: "Please select a start time",
@@ -775,6 +822,10 @@
successMessage: "Meeting erstellt! Laden Sie Ihre Kalenderdatei herunter und öffnen Sie diese, um das Meeting in Ihren persönlichen Kalender zu importieren.",
downloadButton: "ICS-Datei herunterladen",
createNewButton: "Neues Meeting erstellen",
+ adhocButton: "Adhoc-Link erstellen",
+ adhocLinkLabel: "Ihr Adhoc-Meeting-Link:",
+ copyLinkButton: "Link kopieren",
+ copiedLabel: "Kopiert!",
meetingNameRequired: "Bitte geben Sie einen Meeting-Namen ein",
meetingNameInvalid: "Der Meeting-Name darf nur Buchstaben, Zahlen und Bindestriche enthalten",
startTimeRequired: "Bitte wählen Sie eine Startzeit",
@@ -864,6 +915,10 @@
successMessage: "Réunion créée ! Téléchargez votre fichier calendrier et ouvrez-le pour importer la réunion dans votre calendrier personnel.",
downloadButton: "Télécharger le fichier ICS",
createNewButton: "Créer une nouvelle réunion",
+ adhocButton: "Créer un lien adhoc",
+ adhocLinkLabel: "Votre lien de réunion adhoc :",
+ copyLinkButton: "Copier le lien",
+ copiedLabel: "Copié !",
meetingNameRequired: "Veuillez entrer un nom de réunion",
meetingNameInvalid: "Le nom de la réunion ne peut contenir que des lettres, des chiffres et des tirets",
startTimeRequired: "Veuillez sélectionner une heure de début",
@@ -947,6 +1002,10 @@
successMessage: "会议已创建!请下载您的日历文件并打开它,将会议导入您的个人日历。",
downloadButton: "下载 ICS 文件",
createNewButton: "创建新会议",
+ adhocButton: "创建临时链接",
+ adhocLinkLabel: "您的临时会议链接:",
+ copyLinkButton: "复制链接",
+ copiedLabel: "已复制!",
meetingNameRequired: "请输入会议名称",
meetingNameInvalid: "会议名称只能包含字母、数字和连字符",
startTimeRequired: "请选择开始时间",
@@ -1243,9 +1302,13 @@
const meetingEndInput = document.getElementById("meetingEnd");
const meetingOrganizerInput = document.getElementById("meetingOrganizer");
const createMeetingButton = document.getElementById("createMeetingButton");
+ const createAdhocButton = document.getElementById("createAdhocButton");
const cancelCreateButton = document.getElementById("cancelCreateButton");
const icsSuccess = document.getElementById("icsSuccess");
const downloadIcsLink = document.getElementById("downloadIcsLink");
+ const adhocResult = document.getElementById("adhocResult");
+ const adhocLink = document.getElementById("adhocLink");
+ const copyAdhocLinkButton = document.getElementById("copyAdhocLinkButton");
/* Language menu DOM elements */
const langMenu = document.getElementById("langMenu");
@@ -1778,6 +1841,7 @@ END:VCALENDAR`;
meetingEndInput.value = '';
meetingOrganizerInput.value = '';
icsSuccess.classList.add("hidden");
+ adhocResult.classList.add("hidden");
/* Set default start and end times */
const start = roundMinutes(new Date());
@@ -1843,11 +1907,60 @@ END:VCALENDAR`;
/* Show success message */
icsSuccess.classList.remove("hidden");
-
+ adhocResult.classList.add("hidden");
+
/* Scroll to success message */
icsSuccess.scrollIntoView({ behavior: 'smooth' });
}
+ /* ============================================================
+ * ADHOC LINK
+ * ============================================================
+ */
+
+ function createAdhocLink() {
+ const meetingName = meetingNameInput.value.trim();
+
+ if (!meetingName) {
+ alert(getTranslation('creator.meetingNameRequired') || 'Please enter a meeting name');
+ return;
+ }
+
+ if (!ROOM_PATTERN.test(createRoomName(meetingName))) {
+ alert(getTranslation('creator.meetingNameInvalid') || 'Meeting name may only contain letters, numbers and hyphens');
+ return;
+ }
+
+ const roomName = createRoomName(meetingName);
+ const url = `https://${CONFIG.jitsiLauncher}/launch.html?room=${encodeURIComponent(roomName)}`;
+
+ adhocLink.href = url;
+ adhocLink.textContent = url;
+ icsSuccess.classList.add("hidden");
+ adhocResult.classList.remove("hidden");
+ adhocResult.scrollIntoView({ behavior: 'smooth' });
+ }
+
+ async function copyAdhocLink() {
+ const url = adhocLink.href;
+
+ try {
+ await navigator.clipboard.writeText(url);
+ } catch (error) {
+ const input = document.createElement('textarea');
+ input.value = url;
+ document.body.appendChild(input);
+ input.select();
+ document.execCommand('copy');
+ document.body.removeChild(input);
+ }
+
+ copyAdhocLinkButton.textContent = getTranslation('creator.copiedLabel') || 'Copied!';
+ setTimeout(() => {
+ copyAdhocLinkButton.textContent = getTranslation('creator.copyLinkButton') || 'Copy Link';
+ }, 2000);
+ }
+
function cancelCreateMeeting() {
meetingCreator.classList.add("hidden");
@@ -1980,6 +2093,16 @@ END:VCALENDAR`;
createMeeting
);
+ createAdhocButton.addEventListener(
+ "click",
+ createAdhocLink
+ );
+
+ copyAdhocLinkButton.addEventListener(
+ "click",
+ copyAdhocLink
+ );
+
cancelCreateButton.addEventListener(
"click",
cancelCreateMeeting