add more group setting messages & fix leaving empty groups & fix image cropper default zoom
This commit is contained in:
parent
a8c0ae8f18
commit
e975598a40
12 changed files with 288 additions and 66 deletions
154
webroot/main.js
154
webroot/main.js
|
|
@ -3170,7 +3170,7 @@ async function generateMessagesHtml(entries, isPinnedContext = false) {
|
|||
content = processBlah(content);
|
||||
|
||||
if (msg.type && msg.type.startsWith("larp.info")) {
|
||||
if (msg.type === "larp.info.pin" || msg.type === "larp.info.unpin" || msg.type === "larp.info.join" || msg.type === "larp.info.leave" || msg.type === "larp.info.create" || msg.type === "larp.info.history" || msg.type === "larp.info.kick" || msg.type === "larp.info.transfer_owner") {
|
||||
if (msg.type === "larp.info.pin" || msg.type === "larp.info.unpin" || msg.type === "larp.info.join" || msg.type === "larp.info.leave" || msg.type === "larp.info.create" || msg.type === "larp.info.history" || msg.type === "larp.info.kick" || msg.type === "larp.info.transfer_owner" || msg.type === "larp.info.name" || msg.type === "larp.info.pfp" || msg.type === "larp.info.pfp_removed") {
|
||||
let authorName = processBlah("title.unknown");
|
||||
if (msg.author && msg.author !== "0") {
|
||||
if (!dmUsernameCache[msg.author]) {
|
||||
|
|
@ -3196,6 +3196,9 @@ async function generateMessagesHtml(entries, isPinnedContext = false) {
|
|||
else if (msg.type === "larp.info.history") actionStr = "group.history.changed.by";
|
||||
else if (msg.type === "larp.info.kick") actionStr = "group.user.kicked.by";
|
||||
else if (msg.type === "larp.info.transfer_owner") actionStr = "group.owner.transferred.by";
|
||||
else if (msg.type === "larp.info.name") actionStr = "group.name.changed.by";
|
||||
else if (msg.type === "larp.info.pfp") actionStr = "group.pfp.changed.by";
|
||||
else if (msg.type === "larp.info.pfp_removed") actionStr = "group.pfp.removed.by";
|
||||
|
||||
let clickableAuthor = `<span onclick="event.stopPropagation(); openProfile('${msg.author}')" style="cursor: pointer; font-weight: bold;">${authorName}</span>`;
|
||||
|
||||
|
|
@ -3203,8 +3206,9 @@ async function generateMessagesHtml(entries, isPinnedContext = false) {
|
|||
if (msg.type.endsWith(".pin") || msg.type.endsWith(".unpin")) {
|
||||
let clickableMsg = `<span onclick="event.stopPropagation(); scrollToPinnedMessage(event, '${msg.pervious}')" style="cursor: pointer; font-weight: bold; color: rgba(255, 255, 255, 0.9);">${processBlah('title.message.lowercase')}</span>`;
|
||||
content = textStr.replace("{0}", clickableAuthor).replace("{1}", clickableMsg);
|
||||
} else if (msg.type === "larp.info.history") {
|
||||
content = textStr.replace("{0}", clickableAuthor).replace("{1}", content);
|
||||
} else if (msg.type === "larp.info.history" || msg.type === "larp.info.name") {
|
||||
let escapedContent = escapeHtml(content);
|
||||
content = textStr.replace("{0}", clickableAuthor).replace("{1}", escapedContent);
|
||||
} else if (msg.type === "larp.info.kick" || msg.type === "larp.info.transfer_owner") {
|
||||
let targetUsername = "";
|
||||
let targetId = "";
|
||||
|
|
@ -4478,6 +4482,7 @@ let cropperImageObj = null;
|
|||
let cropperPosX = 0;
|
||||
let cropperPosY = 0;
|
||||
let cropperBaseZoom = 1;
|
||||
let cropperZoom = 1;
|
||||
let cropperOriginalType = '';
|
||||
let cropperOriginalB64 = '';
|
||||
|
||||
|
|
@ -4509,9 +4514,10 @@ function openCropper(input, type) {
|
|||
}
|
||||
|
||||
function initCropper() {
|
||||
document.getElementById('cropper-popup-container').classList.add('show');
|
||||
|
||||
let container = document.getElementById('cropper-viewport-container');
|
||||
let imgEl = document.getElementById('cropper-image');
|
||||
let zoomSlider = document.getElementById('cropper-zoom');
|
||||
|
||||
// Set aspect ratio
|
||||
let targetWidth = cropperType === 'avatar' || cropperType === 'group-avatar' ? 512 : 494;
|
||||
|
|
@ -4533,16 +4539,12 @@ function initCropper() {
|
|||
let scaleX = containerWidth / imgWidth;
|
||||
let scaleY = (containerWidth * (targetHeight / targetWidth)) / imgHeight;
|
||||
cropperBaseZoom = Math.max(scaleX, scaleY);
|
||||
|
||||
zoomSlider.min = cropperBaseZoom;
|
||||
zoomSlider.max = cropperBaseZoom * 5;
|
||||
zoomSlider.value = cropperBaseZoom;
|
||||
cropperZoom = cropperBaseZoom;
|
||||
|
||||
cropperPosX = 0;
|
||||
cropperPosY = 0;
|
||||
|
||||
updateCropperTransform();
|
||||
document.getElementById('cropper-popup-container').classList.add('show');
|
||||
}
|
||||
|
||||
function updateCropperZoom() {
|
||||
|
|
@ -4550,21 +4552,40 @@ function updateCropperZoom() {
|
|||
}
|
||||
|
||||
function updateCropperTransform() {
|
||||
let zoom = parseFloat(document.getElementById('cropper-zoom').value);
|
||||
let imgEl = document.getElementById('cropper-image');
|
||||
let container = document.getElementById('cropper-viewport-container');
|
||||
|
||||
if (cropperImageObj) {
|
||||
let containerWidth = container.clientWidth || 300;
|
||||
let targetWidth = cropperType === 'avatar' || cropperType === 'group-avatar' ? 512 : 494;
|
||||
let targetHeight = cropperType === 'avatar' || cropperType === 'group-avatar' ? targetWidth : 200;
|
||||
let containerHeight = container.clientHeight || (containerWidth * (targetHeight / targetWidth));
|
||||
|
||||
let scaleX = containerWidth / cropperImageObj.width;
|
||||
let scaleY = containerHeight / cropperImageObj.height;
|
||||
cropperBaseZoom = Math.max(scaleX, scaleY);
|
||||
|
||||
if (cropperZoom < cropperBaseZoom) cropperZoom = cropperBaseZoom;
|
||||
if (cropperZoom > cropperBaseZoom * 5) cropperZoom = cropperBaseZoom * 5;
|
||||
|
||||
let zoom = cropperZoom;
|
||||
let scaledW = cropperImageObj.width * zoom;
|
||||
let scaledH = cropperImageObj.height * zoom;
|
||||
|
||||
let minX = container.clientWidth - scaledW;
|
||||
containerWidth = container.clientWidth || 300;
|
||||
containerHeight = container.clientHeight || (containerWidth * (targetHeight / targetWidth));
|
||||
|
||||
let minX = containerWidth - scaledW;
|
||||
let minY = containerHeight - scaledH;
|
||||
let maxX = 0;
|
||||
let minY = container.clientHeight - scaledH;
|
||||
let maxY = 0;
|
||||
|
||||
if (minX > maxX) minX = maxX;
|
||||
if (minY > maxY) minY = maxY;
|
||||
if (scaledW < containerWidth) {
|
||||
minX = maxX = (containerWidth - scaledW) / 2;
|
||||
}
|
||||
if (scaledH < containerHeight) {
|
||||
minY = maxY = (containerHeight - scaledH) / 2;
|
||||
}
|
||||
|
||||
if (cropperPosX < minX) cropperPosX = minX;
|
||||
if (cropperPosX > maxX) cropperPosX = maxX;
|
||||
|
|
@ -4572,7 +4593,7 @@ function updateCropperTransform() {
|
|||
if (cropperPosY > maxY) cropperPosY = maxY;
|
||||
}
|
||||
|
||||
imgEl.style.transform = `translate(${cropperPosX}px, ${cropperPosY}px) scale(${zoom})`;
|
||||
imgEl.style.transform = `translate(${cropperPosX}px, ${cropperPosY}px) scale(${cropperZoom})`;
|
||||
}
|
||||
|
||||
function closeCropper() {
|
||||
|
|
@ -4580,16 +4601,16 @@ function closeCropper() {
|
|||
}
|
||||
|
||||
async function confirmCropper() {
|
||||
let zoom = parseFloat(document.getElementById('cropper-zoom').value);
|
||||
let container = document.getElementById('cropper-viewport-container');
|
||||
|
||||
let targetWidth = cropperType === 'avatar' || cropperType === 'group-avatar' ? 512 : 988;
|
||||
let targetHeight = cropperType === 'avatar' || cropperType === 'group-avatar' ? 512 : 400;
|
||||
let scaleRatio = targetWidth / container.clientWidth;
|
||||
|
||||
let scaleRatio = targetWidth / (container.clientWidth || 300);
|
||||
let drawX = cropperPosX * scaleRatio;
|
||||
let drawY = cropperPosY * scaleRatio;
|
||||
let drawW = cropperImageObj.width * zoom * scaleRatio;
|
||||
let drawH = cropperImageObj.height * zoom * scaleRatio;
|
||||
let drawW = cropperImageObj.width * cropperZoom * scaleRatio;
|
||||
let drawH = cropperImageObj.height * cropperZoom * scaleRatio;
|
||||
|
||||
let b64;
|
||||
let newSrc;
|
||||
|
|
@ -4794,9 +4815,20 @@ async function confirmCropper() {
|
|||
}
|
||||
|
||||
|
||||
let container = document.getElementById('cropper-viewport-container');
|
||||
if (container) {
|
||||
let cropperContainer = document.getElementById('cropper-viewport-container');
|
||||
if (cropperContainer) {
|
||||
let initialPinchDistance = null;
|
||||
let initialPinchZoom = null;
|
||||
|
||||
const startDrag = (e) => {
|
||||
if (e.touches && e.touches.length === 2) {
|
||||
isDraggingCropper = false;
|
||||
let dx = e.touches[0].clientX - e.touches[1].clientX;
|
||||
let dy = e.touches[0].clientY - e.touches[1].clientY;
|
||||
initialPinchDistance = Math.sqrt(dx*dx + dy*dy);
|
||||
initialPinchZoom = cropperZoom;
|
||||
return;
|
||||
}
|
||||
isDraggingCropper = true;
|
||||
startDragX = e.clientX || (e.touches && e.touches[0].clientX);
|
||||
startDragY = e.clientY || (e.touches && e.touches[0].clientY);
|
||||
|
|
@ -4806,6 +4838,30 @@ if (container) {
|
|||
};
|
||||
|
||||
const onDrag = (e) => {
|
||||
if (e.touches && e.touches.length === 2 && initialPinchDistance !== null) {
|
||||
let dx = e.touches[0].clientX - e.touches[1].clientX;
|
||||
let dy = e.touches[0].clientY - e.touches[1].clientY;
|
||||
let distance = Math.sqrt(dx*dx + dy*dy);
|
||||
let zoomFactor = distance / initialPinchDistance;
|
||||
|
||||
let oldZoom = cropperZoom;
|
||||
cropperZoom = initialPinchZoom * zoomFactor;
|
||||
|
||||
if (cropperZoom < cropperBaseZoom) cropperZoom = cropperBaseZoom;
|
||||
if (cropperZoom > cropperBaseZoom * 5) cropperZoom = cropperBaseZoom * 5;
|
||||
|
||||
let zoomRatio = cropperZoom / oldZoom;
|
||||
|
||||
let cw = cropperContainer.clientWidth || 300;
|
||||
let ch = cropperContainer.clientHeight || 300;
|
||||
|
||||
cropperPosX = (cropperPosX - cw/2) * zoomRatio + cw/2;
|
||||
cropperPosY = (cropperPosY - ch/2) * zoomRatio + ch/2;
|
||||
|
||||
updateCropperTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDraggingCropper) return;
|
||||
let clientX = e.clientX || (e.touches && e.touches[0].clientX);
|
||||
let clientY = e.clientY || (e.touches && e.touches[0].clientY);
|
||||
|
|
@ -4814,16 +4870,57 @@ if (container) {
|
|||
updateCropperTransform();
|
||||
};
|
||||
|
||||
const endDrag = () => {
|
||||
isDraggingCropper = false;
|
||||
const endDrag = (e) => {
|
||||
if (e.touches && e.touches.length < 2) {
|
||||
initialPinchDistance = null;
|
||||
initialPinchZoom = null;
|
||||
}
|
||||
if (e.touches && e.touches.length === 1) {
|
||||
isDraggingCropper = true;
|
||||
startDragX = e.touches[0].clientX;
|
||||
startDragY = e.touches[0].clientY;
|
||||
startPosX = cropperPosX;
|
||||
startPosY = cropperPosY;
|
||||
} else {
|
||||
isDraggingCropper = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onWheel = (e) => {
|
||||
if (document.getElementById('cropper-popup-container').classList.contains('show')) {
|
||||
e.preventDefault();
|
||||
let oldZoom = cropperZoom;
|
||||
let zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
|
||||
cropperZoom *= zoomFactor;
|
||||
if (cropperZoom < cropperBaseZoom) cropperZoom = cropperBaseZoom;
|
||||
if (cropperZoom > cropperBaseZoom * 5) cropperZoom = cropperBaseZoom * 5;
|
||||
|
||||
let zoomRatio = cropperZoom / oldZoom;
|
||||
|
||||
let rect = cropperContainer.getBoundingClientRect();
|
||||
let mouseX = e.clientX - rect.left;
|
||||
let mouseY = e.clientY - rect.top;
|
||||
|
||||
cropperPosX = (cropperPosX - mouseX) * zoomRatio + mouseX;
|
||||
cropperPosY = (cropperPosY - mouseY) * zoomRatio + mouseY;
|
||||
|
||||
updateCropperTransform();
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener('mousedown', startDrag);
|
||||
container.addEventListener('touchstart', startDrag, {passive: true});
|
||||
cropperContainer.addEventListener('mousedown', startDrag);
|
||||
cropperContainer.addEventListener('touchstart', startDrag, {passive: true});
|
||||
document.addEventListener('mousemove', onDrag);
|
||||
document.addEventListener('touchmove', onDrag, {passive: true});
|
||||
document.addEventListener('touchmove', onDrag, {passive: false});
|
||||
document.addEventListener('mouseup', endDrag);
|
||||
document.addEventListener('touchend', endDrag);
|
||||
cropperContainer.addEventListener('wheel', onWheel, {passive: false});
|
||||
|
||||
new ResizeObserver(() => {
|
||||
if (document.getElementById('cropper-popup-container').classList.contains('show')) {
|
||||
updateCropperTransform();
|
||||
}
|
||||
}).observe(cropperContainer);
|
||||
}
|
||||
|
||||
function updateDmListUI(roomId, isRead, type = 'dms', timestamp = null) {
|
||||
|
|
@ -5291,7 +5388,7 @@ async function confirmLeaveGroup(groupId) {
|
|||
try {
|
||||
let payload = JSON.stringify({ string1: groupId });
|
||||
let res = await fetchEncrypted("group/leave", payload);
|
||||
if (res === "success") {
|
||||
if (res === "success" || res === "error:not.a.member" || res === "error:group.not.found") {
|
||||
if (currentDmId === groupId) {
|
||||
currentDmId = null;
|
||||
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
||||
|
|
@ -5302,6 +5399,9 @@ async function confirmLeaveGroup(groupId) {
|
|||
}
|
||||
}
|
||||
refreshGroups(0, false);
|
||||
if (res !== "success") {
|
||||
showBlahNotification(res);
|
||||
}
|
||||
} else if (res.startsWith("error:")) {
|
||||
showBlahNotification(res);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue