Skip to content

Commit 1a6f430

Browse files
committed
Add share menu, group buttons #252
1 parent 343cc56 commit 1a6f430

File tree

10 files changed

+187
-96
lines changed

10 files changed

+187
-96
lines changed

build/go-generate/minifyStaticContent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,6 @@ func fileExists(filename string) bool {
137137
// Auto-generated content below, do not modify
138138
// Version codes can be changed in updateVersionNumbers.go
139139

140-
const jsAdminVersion = 9
140+
const jsAdminVersion = 10
141141
const jsE2EVersion = 5
142-
const cssMainVersion = 4
142+
const cssMainVersion = 5

build/go-generate/updateVersionNumbers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import (
1111
"strings"
1212
)
1313

14-
const versionJsAdmin = 9
14+
const versionJsAdmin = 10
1515
const versionJsDropzone = 5
16-
const versionJsE2EAdmin = 5
17-
const versionCssMain = 4
16+
const versionJsE2EAdmin = 6
17+
const versionCssMain = 5
1818

1919
const fileMain = "../../cmd/gokapi/Main.go"
2020
const fileMinify = "../../build/go-generate/minifyStaticContent.go"

internal/webserver/web/static/css/min/gokapi.min.4.css renamed to internal/webserver/web/static/css/min/gokapi.min.5.css

File renamed without changes.

internal/webserver/web/static/js/admin_ui_allPages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// go generate ./...
44

55

6-
var clipboard = new ClipboardJS('.btn');
6+
var clipboard = new ClipboardJS('.copyurl');
77

88
var toastId;
99

internal/webserver/web/static/js/admin_ui_upload.js

Lines changed: 134 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -689,12 +689,11 @@ function addRow(item) {
689689
}
690690
cellDownloadCount.innerText = item.DownloadCount;
691691

692-
// === URL Link ===
693692
const link = document.createElement('a');
694693
link.href = item.UrlDownload;
695694
link.target = '_blank';
696695
link.style.color = 'inherit';
697-
link.id = 'url-href-'+item.Id;
696+
link.id = 'url-href-' + item.Id;
698697
link.textContent = item.Id;
699698

700699
cellUrl.appendChild(link);
@@ -707,12 +706,37 @@ function addRow(item) {
707706
cellUrl.appendChild(icon);
708707
}
709708

709+
cellButtons.appendChild(createButtonGroup(item));
710+
711+
712+
cellFilename.classList.add('newItem');
713+
cellFileSize.classList.add('newItem');
714+
cellRemainingDownloads.classList.add('newItem');
715+
cellStoredUntil.classList.add('newItem');
716+
cellDownloadCount.classList.add('newItem');
717+
cellUrl.classList.add('newItem');
718+
cellButtons.classList.add('newItem');
719+
cellFileSize.setAttribute('data-order', item.SizeBytes);
720+
721+
changeRowCount(true, row);
722+
return item.Id;
723+
}
724+
725+
function createButtonGroup(item) {
726+
const groupContainer = document.createElement("div");
727+
groupContainer.className = "btn-toolbar";
728+
groupContainer.setAttribute("role", "toolbar");
729+
730+
const group1 = document.createElement("div");
731+
group1.className = "btn-group me-2";
732+
group1.setAttribute("role", "group");
733+
710734
// === Button: Copy URL ===
711735
const copyUrlBtn = document.createElement('button');
712736
copyUrlBtn.type = 'button';
713737
copyUrlBtn.className = 'copyurl btn btn-outline-light btn-sm';
714738
copyUrlBtn.dataset.clipboardText = item.UrlDownload;
715-
copyUrlBtn.id = 'url-button-'+item.Id;
739+
copyUrlBtn.id = 'url-button-' + item.Id;
716740
copyUrlBtn.title = 'Copy URL';
717741

718742
const copyIcon = document.createElement('i');
@@ -724,61 +748,95 @@ function addRow(item) {
724748
showToast(1000);
725749
});
726750

727-
cellButtons.appendChild(copyUrlBtn);
728-
cellButtons.appendChild(document.createTextNode(' '));
729-
730-
// === Button: Copy Hotlink ===
731-
const hotlinkBtn = document.createElement('button');
732-
hotlinkBtn.type = 'button';
733-
hotlinkBtn.className = 'copyurl btn btn-outline-light btn-sm';
734-
hotlinkBtn.title = 'Copy Hotlink';
735-
736-
const hotlinkIcon = document.createElement('i');
737-
hotlinkIcon.className = 'bi bi-copy';
738-
hotlinkBtn.appendChild(hotlinkIcon);
739-
hotlinkBtn.appendChild(document.createTextNode(' Hotlink'));
740-
741-
if (item.UrlHotlink) {
742-
hotlinkBtn.dataset.clipboardText = item.UrlHotlink;
743-
hotlinkBtn.addEventListener('click', () => {
744-
showToast(1000);
745-
});
751+
group1.appendChild(copyUrlBtn);
752+
753+
// Dropdown toggle for Hotlink
754+
const btnDropdown1 = document.createElement("button");
755+
btnDropdown1.type = "button";
756+
btnDropdown1.className = "btn btn-outline-light btn-sm dropdown-toggle dropdown-toggle-split";
757+
btnDropdown1.setAttribute("data-bs-toggle", "dropdown");
758+
btnDropdown1.setAttribute("aria-expanded", "false");
759+
group1.appendChild(btnDropdown1);
760+
761+
const dropdown1 = document.createElement("ul");
762+
dropdown1.className = "dropdown-menu dropdown-menu-end";
763+
dropdown1.setAttribute("data-bs-theme", "dark");
764+
765+
const liDr1 = document.createElement("li");
766+
const aDr1 = document.createElement("a");
767+
if (item.UrlHotlink !== "") {
768+
aDr1.className = "dropdown-item copyurl";
769+
aDr1.title = "Copy hotlink";
770+
aDr1.setAttribute("data-clipboard-text", item.UrlHotlink);
771+
aDr1.onclick = () => showToast(1000);
772+
aDr1.innerHTML = `<i class="bi bi-copy"></i> Hotlink`;
746773
} else {
747-
hotlinkBtn.disabled = true;
748-
}
749-
750-
cellButtons.appendChild(hotlinkBtn);
751-
cellButtons.appendChild(document.createTextNode(' '));
752-
753-
// === Button: QR Code ===
754-
const qrBtn = document.createElement('button');
755-
qrBtn.type = 'button';
756-
qrBtn.className = 'btn btn-outline-light btn-sm';
757-
qrBtn.title = 'QR Code';
758-
qrBtn.id = 'qrcode-'+item.Id;
759-
760-
const qrIcon = document.createElement('i');
761-
qrIcon.className = 'bi bi-qr-code';
762-
qrBtn.appendChild(qrIcon);
763-
764-
qrBtn.addEventListener('click', () => {
765-
showQrCode(item.UrlDownload);
766-
});
767-
768-
cellButtons.appendChild(qrBtn);
769-
cellButtons.appendChild(document.createTextNode(' '));
774+
aDr1.className = "dropdown-item";
775+
aDr1.innerText = "Hotlink not available";
776+
}
777+
liDr1.appendChild(aDr1);
778+
dropdown1.appendChild(liDr1);
779+
group1.appendChild(dropdown1);
780+
781+
// Share button
782+
const btnShare = document.createElement("button");
783+
btnShare.type = "button";
784+
btnShare.className = "btn btn-outline-light btn-sm";
785+
btnShare.title = "Share";
786+
btnShare.onclick = () => shareUrl(item.Id);
787+
btnShare.innerHTML = `<i class="bi bi-share"></i>`;
788+
group1.appendChild(btnShare);
789+
790+
791+
// Dropdown toggle
792+
const btnDropdown2 = document.createElement("button");
793+
btnDropdown2.type = "button";
794+
btnDropdown2.className = "btn btn-outline-light btn-sm dropdown-toggle dropdown-toggle-split";
795+
btnDropdown2.setAttribute("data-bs-toggle", "dropdown");
796+
btnDropdown2.setAttribute("aria-expanded", "false");
797+
group1.appendChild(btnDropdown2);
798+
799+
const dropdown2 = document.createElement("ul");
800+
dropdown2.className = "dropdown-menu dropdown-menu-end";
801+
dropdown2.setAttribute("data-bs-theme", "dark");
802+
803+
const qrLi = document.createElement("li");
804+
const qrA = document.createElement("a");
805+
qrA.className = "dropdown-item";
806+
qrA.id = `qrcode-${item.Id}`;
807+
qrA.title = "Open QR Code";
808+
qrA.onclick = () => showQrCode(item.UrlDownload);
809+
qrA.innerHTML = `<i class="bi bi-qr-code"></i> QR Code`;
810+
qrLi.appendChild(qrA);
811+
dropdown2.appendChild(qrLi);
812+
813+
const emailLi = document.createElement("li");
814+
const emailA = document.createElement("a");
815+
emailA.className = "dropdown-item";
816+
emailA.title = "Share via email";
817+
emailA.target = "_blank";
818+
emailA.href = `mailto:?body=${encodeURIComponent(item.UrlDownload)}`;
819+
emailA.innerHTML = `<i class="bi bi-envelope"></i> Email`;
820+
emailLi.appendChild(emailA);
821+
dropdown2.appendChild(emailLi);
822+
group1.appendChild(dropdown2);
823+
824+
// Button group for Edit/Delete
825+
const group2 = document.createElement("div");
826+
group2.className = "btn-group me-2";
827+
group2.setAttribute("role", "group");
770828

771829
// === Button: Edit ===
772-
const editBtn = document.createElement('button');
773-
editBtn.type = 'button';
774-
editBtn.className = 'btn btn-outline-light btn-sm';
775-
editBtn.title = 'Edit';
830+
const btnEdit = document.createElement('button');
831+
btnEdit.type = 'button';
832+
btnEdit.className = 'btn btn-outline-light btn-sm';
833+
btnEdit.title = 'Edit';
776834

777835
const editIcon = document.createElement('i');
778836
editIcon.className = 'bi bi-pencil';
779-
editBtn.appendChild(editIcon);
837+
btnEdit.appendChild(editIcon);
780838

781-
editBtn.addEventListener('click', () => {
839+
btnEdit.addEventListener('click', () => {
782840
showEditModal(
783841
item.Name,
784842
item.Id,
@@ -792,38 +850,28 @@ function addRow(item) {
792850
);
793851
});
794852

795-
cellButtons.appendChild(editBtn);
796-
cellButtons.appendChild(document.createTextNode(' '));
853+
group2.appendChild(btnEdit);
797854

798855
// === Button: Delete ===
799-
const deleteBtn = document.createElement('button');
800-
deleteBtn.type = 'button';
801-
deleteBtn.className = 'btn btn-outline-danger btn-sm';
802-
deleteBtn.title = 'Delete';
803-
deleteBtn.id = 'button-delete-'+item.Id;
856+
const btnDelete = document.createElement('button');
857+
btnDelete.type = 'button';
858+
btnDelete.className = 'btn btn-outline-danger btn-sm';
859+
btnDelete.title = 'Delete';
860+
btnDelete.id = 'button-delete-' + item.Id;
804861

805862
const deleteIcon = document.createElement('i');
806863
deleteIcon.className = 'bi bi-trash3';
807-
deleteBtn.appendChild(deleteIcon);
864+
btnDelete.appendChild(deleteIcon);
808865

809-
deleteBtn.addEventListener('click', () => {
866+
btnDelete.addEventListener('click', () => {
810867
deleteFile(item.Id);
811868
});
869+
group2.appendChild(btnDelete);
812870

813-
cellButtons.appendChild(deleteBtn);
814-
815-
816-
cellFilename.classList.add('newItem');
817-
cellFileSize.classList.add('newItem');
818-
cellRemainingDownloads.classList.add('newItem');
819-
cellStoredUntil.classList.add('newItem');
820-
cellDownloadCount.classList.add('newItem');
821-
cellUrl.classList.add('newItem');
822-
cellButtons.classList.add('newItem');
823-
cellFileSize.setAttribute('data-order', item.SizeBytes);
871+
groupContainer.appendChild(group1);
872+
groupContainer.appendChild(group2);
824873

825-
changeRowCount(true, row);
826-
return item.Id;
874+
return groupContainer;
827875
}
828876

829877
function sanitizeId(str) {
@@ -895,7 +943,7 @@ function showToastFileDeletion(id) {
895943
}
896944

897945
function hideFileToast() {
898-
document.getElementById("toastnotificationUndo").classList.remove("show");
946+
document.getElementById("toastnotificationUndo").classList.remove("show");
899947
}
900948

901949
function handleUndo(button) {
@@ -909,3 +957,15 @@ function handleUndo(button) {
909957
console.error('Error:', error);
910958
});
911959
}
960+
961+
function shareUrl(id) {
962+
if (!navigator.share) {
963+
return;
964+
}
965+
let filename = document.getElementById("cell-name-" + id).innerText;
966+
let url = document.getElementById("url-href-" + id).getAttribute("href");
967+
navigator.share({
968+
title: filename,
969+
url: url,
970+
})
971+
}

internal/webserver/web/static/js/end2end_admin.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ function decryptFileEntry(id, filename, cipher) {
170170
let datatable = $('#maintable').DataTable();
171171
const rows = datatable.rows().nodes();
172172

173+
174+
173175
for (let i = 0; i < rows.length; i++) {
174176
const cell = datatable.cell(i, 0).node();
175177
if ("cell-name-" + id === $(cell).attr("id")) {
@@ -180,7 +182,7 @@ function decryptFileEntry(id, filename, cipher) {
180182
cellNode.textContent = filename;
181183
if (!url.includes(cipher)) {
182184
if (IncludeFilename) {
183-
url = url.replace("/Encrypted%20File", "/" + encodeURI(filename));
185+
url = url.replace("/Encrypted%20File", "/" + encodeURIComponent(filename));
184186
}
185187
url = url + "#" + cipher;
186188
urlLink.setAttribute("href", url);
@@ -192,6 +194,7 @@ function decryptFileEntry(id, filename, cipher) {
192194
let button = buttonNode.querySelector("button");
193195
button.setAttribute("data-clipboard-text", url);
194196
document.getElementById("qrcode-"+id).onclick = function() {showQrCode(url);};
197+
document.getElementById("email-"+id).href = "mailto:?body="+encodeURIComponent(url);
195198
datatable.cell(i, 6).node(buttonNode);
196199
break;
197200
}

0 commit comments

Comments
 (0)