// ==UserScript==
// @name AAC Enhanced plus AAC Utils
// @namespace http://tampermonkey.net/
// @version 1.10.13
// @copyright 2025, Asriel (https://gf.qytechs.cn/de/users/1375984-asriel-aac) 2022, Reimu(https://github.com/ReiwuKleiwu/AAC-Utils)
// @license MIT
// @description Adds custom UI enhancements
// @author Asriel / Nick S. aka. Slash
// @icon https://i.ibb.co/z5CJ5zv/revanced.png
// @supportURL https://gf.qytechs.cn/de/scripts/511351-aac-enhanced-plus-aac-utils/feedback
// @include /^https?:\/\/(www\.)?anime\.academy\/.*/
// @grant none
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// ==/UserScript==
(function() {
'use strict';
function addGlobalStyle(css) {
let head, style;
head = document.getElementsByTagName('head')[0];
if (!head) {
return;
}
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
addGlobalStyle(`
'.autocomplete-flex {' +
' background-color: #484b52;' +
' font-weight: 600;' +
' display: flex;' +
' align-items: center;' +
' gap: 10px;' +
' padding: 5px;' +
'}' +
'.autocomplete-flex:hover {' +
' background-color: #5f646e;' +
'}' +
'' +
'.autocomplete-flex:focus {' +
' background-color: #5f646e;' +
'}' +
'' +
'.name-link:hover {' +
' text-decoration: none;' +
'}' +
'.autocomplete-icon {' +
' width: 45px !important;' +
' height: 45px !important;' +
' border-radius: 50%;' +
'}' +
'.chatMessage {' +
' transition: padding 0.4s ease 0s;' +
'}' +
'.chatMessage:hover {' +
' padding-top: 5px;' +
' padding-bottom: 5px;' +
' position: relative;' +
' background-color: #5f646e !important;' +
' border-radius: 3px;' +
' transition: padding 0.4s ease 0s;' +
'}' +
'.messageIcons {' +
' display: flex;' +
' justify-content: center;' +
' align-items: center;' +
' height: 32px;' +
' width: 32px;' +
' background-color: #484b52;' +
' position: absolute;' +
' right: 0;' +
' top: -20px;' +
' display: none;' +
' border-radius: 3px;' +
'}' +
'.messageIcons:hover {' +
' background-color: #5f646e;' +
' filter: drop-shadow(5px 7px 14px black);' +
'}' +
'' +
'.collapsible-wrap {' +
' margin: 10px 0 10px 0;' +
'}' +
'' +
'.collapsible-button {' +
' cursor: pointer;' +
' padding: 18px;' +
' width: 100%;' +
' text-align: left;' +
' outline: none;' +
' font-size: 15px;' +
'}' +
'' +
'.collapsible-button:focus {' +
' transition: background-color 0.5s ease;' +
' background-color: #3e1e80 !important;' +
'}' +
'' +
'.collapsible-button:hover {' +
' transition: background-color 0.5s ease;' +
'}' +
'' +
'.active {' +
' border-bottom-right-radius: 0 !important;' +
' border-bottom-left-radius: 0 !important;' +
' background-color: #3e1e80 !important;' +
'}' +
'' +
'.collapsible-button:after {' +
" content: '\\002B';" +
' font-weight: bold;' +
' float: right;' +
' margin-left: 5px;' +
'}' +
'' +
'.active:after {' +
" content: '\\2212';" +
'}' +
'' +
'.collapsible-content {' +
' padding: 0 10px;' +
' max-height: 0;' +
' overflow: hidden;' +
' transition: max-height 0.2s ease-out;' +
' background-color: #2c2f33;' +
' border-bottom-left-radius: 3px;' +
' border-bottom-right-radius: 3px;' +
'}' +
'' +
'.avatar-grid {' +
' width: 100%;' +
' display: grid;' +
' grid-template-columns: repeat(auto-fill, 8em);' +
' grid-gap: 10px 15px;' +
'}' +
'' +
'.avatar-div {' +
' height: 80px;' +
' width: 80px;' +
' display: flex;' +
' align-items: center;' +
' justify-content: center;' +
' gap: 5px;' +
'}' +
'' +
'.avatar-div:hover {' +
' background-color: #484b52;' +
' transition: background-color 0.5s ease;' +
' border-radius: 3px;' +
'}' +
'' +
'.avatarIcon {' +
' height: 20px;' +
' width: 20px;' +
' background-color: #3e1e80;' +
' border-radius: 50%;' +
' display: none;' +
' align-items: center;' +
' justify-content: center;' +
'}' +
'' +
'.avatarIcon:hover {' +
' background-color: #6b36d9;' +
' filter: drop-shadow(5px 7px 14px #2c2f33);' +
' transition: background-color 0.5s ease;' +
'}' +
'' +
'.ionicon {' +
' width: 13px;' +
' height: 13px;' +
' fill: #ddd;' +
'}' +
'' +
'.collection-selection {' +
' position: absolute;' +
' z-index: 10000;' +
' margin-left: auto;' +
' margin-right: auto;' +
' right: 0;' +
' left: 0;' +
' top: 80px;' +
' width: 300px;' +
' background-color: #484b52;' +
' padding: 10px;' +
' text-align: center;' +
' overflow: hidden scroll;' +
' border-radius: 3px;' +
' max-height: 200px;' +
'}' +
'' +
'.collection-selectable {' +
' font-weight: 700;' +
' padding: 10px 0;' +
' margin-bottom: 5px;' +
'}' +
'' +
'.collection-selectable:hover {' +
' background-color: #3e1e80;' +
' border-radius: 3px;' +
' transition: background-color 0.5s ease;' +
' filter: drop-shadow(5px 7px 14px #2c2f33);' +
'}' +
'' +
'#createCollectionBtn {' +
' font-weight: 700;' +
'}' +
'' +
'.removeCategory-btn {' +
' background-color: #fd2f2f;' +
'}' +
'' +
'.request-delete-collection {' +
' position: absolute;' +
' z-index: 10000;' +
' margin-left: auto;' +
' margin-right: auto;' +
' right: 0;' +
' left: 0;' +
' top: 80px;' +
' width: 300px;' +
' background-color: #484b52;' +
' padding: 10px;' +
' text-align: center;' +
' overflow: hidden scroll;' +
' border-radius: 3px;' +
' max-height: 200px;' +
'}' +
'' +
'.message-image {' +
' width: 100%;' +
' height: auto;' +
' border-radius: 3px;' +
'}' +
'' +
'.message-image-container {' +
' margin-top: 5px;' +
'}' +
'' +
'#username-results {' +
' border: none;' +
' max-height: 200px;' +
' overflow: hidden scroll;' +
' max-width: 30%;' +
' position: absolute;' +
' left: 0;' +
' right: 0;' +
' bottom: calc(100% + 8px);' +
' margin-left: 8px;' +
' border-radius: 5px;' +
'}' +
''
`);
const scriptName = GM_info.script.name;
const scriptVersion = GM_info.script.version;
window.aacEnhancedScriptID = `${scriptName.replace(/\s+/g, '-')}-${scriptVersion}`;
console.log(window.aacEnhancedScriptID);
// Necessary for autoreconnect
window.onbeforeunload = null;
// Access the AngularJS scope
const scope = angular.element(document.getElementById('topbar')).scope();
// Global Socket Hook
const globalSocketReady = new Event('globalSocketReady');
io.Socket.prototype.o_emit = io.Socket.prototype.o_emit || io.Socket.prototype.emit;
io.Socket.prototype.emit = function (eventName, ...args) {
if (!window.socket) {
window.socket = this;
window.dispatchEvent(globalSocketReady);
}
window.dispatchEvent(new CustomEvent('socketEmit', { detail: { eventName: eventName, args: [...args] } }));
return this.o_emit(eventName, ...args);
};
/************************************
*
*
* Autoreconnect Modul
*
*
************************************/
const disconnectReasons = [
'transport error',
'transport close',
'io client disconnect',
'io server disconnect',
'ping timeout',
];
const disconnected = JSON.parse(localStorage.getItem('disconnected'));
if (disconnected) {
localStorage.setItem('disconnected', JSON.stringify(false));
window.addEventListener('globalSocketReady', () => {
setTimeout(() => {
window.socket.emit('moveAvatar', JSON.parse(localStorage.getItem('avatarPosition')));
}, 1500);
});
}
window.addEventListener('socketEmit', (event) => {
if (event.detail.eventName === 'moveAvatar') {
localStorage.setItem('avatarPosition', JSON.stringify(event.detail.args[0]));
}
if (event.detail.eventName === 'disconnect' && disconnectReasons.includes(event.detail.args[0])) {
localStorage.setItem('disconnected', JSON.stringify(true));
location.reload();
}
});
/************************************
*
*
* Chatverlaufs Modul
*
*
************************************/
const maxStoredMessagesPerRoom = 500;
const maxMessageAge = 1000 * 60 * 60 * 2; // 2 hours
window.addEventListener('globalSocketReady', () => {
window.socket.on('updateChatLines', (data) => {
const currentRoom = window.location.href.split('=')[1];
let roomData;
if (!localStorage.hasOwnProperty('rooms')) {
localStorage.setItem('rooms', JSON.stringify({}));
}
if (!JSON.parse(localStorage.getItem('rooms')).hasOwnProperty(currentRoom)) {
roomData = JSON.parse(localStorage.getItem('rooms'));
roomData[currentRoom] = {
messages: [],
};
roomData = JSON.stringify(roomData);
localStorage.setItem('rooms', roomData);
}
roomData = JSON.parse(localStorage.getItem('rooms'));
if (data.user !== 'System') roomData[currentRoom].messages.push(data);
if (roomData[currentRoom].messages.length > maxStoredMessagesPerRoom) roomData[currentRoom].messages.splice(0, 1);
roomData = JSON.stringify(roomData);
localStorage.setItem('rooms', roomData);
});
window.addEventListener('socketEmit', (event) => {
if (event.detail.eventName === 'changeRoom') {
setTimeout(() => {
restoreChatlogs();
}, 100);
}
});
restoreChatlogs();
});
function restoreChatlogs() {
let currentRoomChatlogs = undefined;
if (JSON.parse(localStorage.getItem('rooms'))) {
if (JSON.parse(localStorage.getItem('rooms'))[window.location.href.split('=')[1]]) {
currentRoomChatlogs = JSON.parse(localStorage.getItem('rooms'))[window.location.href.split('=')[1]].messages;
}
} else {
return;
}
if (currentRoomChatlogs) {
setTimeout(() => {
for (const messageData of currentRoomChatlogs) {
if (messageData.user !== 'System' && Date.now() - messageData.timestamp < maxMessageAge) {
const message = {
hasPremium: messageData.hasPremium,
msg: messageData.chatLine,
festername: messageData.festername,
house: messageData.house ? messageData.house : null,
color: undefined,
user: messageData.user + ': ',
timestamp: `${new Date(messageData.timestamp).toLocaleDateString('de-DE')} - ${new Date(
messageData.timestamp
)
.toLocaleTimeString('de-DE')
.slice(0, -3)} Uhr`,
};
scope.chatmsgs.push(message);
document.getElementById('topbar').click(); // Refresh the chat
}
}
}, 1500);
}
}
/************************************
*
*
* Autocomplete usernames Modul
*
*
************************************/
const chatArea = document.getElementById('graphicChatArea');
chatArea.style.border = 'none';
const messageForm = document.getElementsByName('chatMsgForm')[0];
const messageInput = document.getElementById('chatline');
messageInput.setAttribute('onKeyUp', 'showResults(this.value)');
const resultDiv = document.createElement('div');
resultDiv.setAttribute('id', 'username-results');
messageForm.appendChild(resultDiv);
function showResults(value) {
const result = document.getElementById('username-results');
result.style.display = 'block';
if (!value.includes('@')) {
result.style.display = 'none';
}
result.innerHTML = '';
let list = '';
const users = window.autocompleteMatch(value);
for (const user in users) {
list += `<a class="name-link"><div class="autocomplete-flex autocomplete-list" onclick="replaceName(this.children[1].innerHTML)" tabindex="0"><img class="autocomplete-icon" src="/img/publicimg/skinthumbnails/${
users[user].imgthumb
}"><div class="name-wrap">${users[user].username.split('@')[1]}</div></div></a>`;
}
result.innerHTML = `<ul style="padding: 0px; margin: 0px;">${list}</ul>`;
const autocompleteListElements = document.getElementsByClassName('autocomplete-list');
for (const element of autocompleteListElements) {
element.addEventListener('keyup', function (event) {
if (event.keyCode === 13) {
window.replaceName(this.children[1].innerHTML);
}
});
}
}
function autocompleteMatch(input) {
if (input === '') {
return [];
}
const scope = angular.element(document.getElementById('topbar')).scope();
const users = scope.chatterlist.filter((user) => user.room === scope.roomData.name);
const userObjects = users.map((user) => {
return { ...user, username: `@${user.username}` };
});
const reg = new RegExp(`\\B@(${input.split('@')[1]}.*)$`, 'i');
return userObjects.filter((user) => {
if (user.username.match(reg)) {
return user;
}
});
}
function replaceName(username) {
const scope = angular.element(document.getElementById('topbar')).scope();
const messageInput = document.getElementById('chatline');
scope.chatline = scope.chatline.replace(/\B@(\w*)$/, `${username} `);
const resultDiv = document.getElementById('username-results');
resultDiv.style.display = 'none';
messageInput.focus();
}
window.replaceName = replaceName;
window.showResults = showResults;
window.autocompleteMatch = autocompleteMatch;
// Main Application Namespace
const AACApp = {
init: function () {
console.log("[AAC Enhanced] Initializing...");
this.loadModules();
},
loadModules: function () {
ChatLogger.init(); // 🔹 Chat Logger initialized seamlessly
TopWrapperIcon.init();
WallpaperChanger.init();
ChatArea.init();
}
};
/************************************
*
*
* Video Präferenzen Modul
*
*
************************************/
const enableVideosInput = document.getElementById('checkAllowVideo');
const enableVideos =
JSON.parse(localStorage.getItem('enableVideos')) === undefined
? true
: JSON.parse(localStorage.getItem('enableVideos'));
scope.allowVideos = enableVideos;
enableVideosInput.checked = enableVideos;
enableVideosInput.addEventListener('change', function () {
localStorage.setItem('enableVideos', JSON.stringify(this.checked));
});
/************************************
*
*
* Microphone colorsaver Modul
*
*
************************************/
const microphoneBackgroundColor = JSON.parse(localStorage.getItem('microphoneBackgroundColor'));
const microphoneTextColor = JSON.parse(localStorage.getItem('microphoneTextColor'));
if (microphoneBackgroundColor && microphoneTextColor) {
window.addEventListener('globalSocketReady', () => {
setTimeout(() => {
window.socket.emit('applyMicrophoneColor', {
microphoneBackgroundColor: microphoneBackgroundColor,
microphoneTextColor: microphoneTextColor,
});
}, 1500);
});
}
window.addEventListener('socketEmit', (event) => {
if (event.detail.eventName === 'applyMicrophoneColor') {
localStorage.setItem('microphoneBackgroundColor', JSON.stringify(event.detail.args[0].microphoneBackgroundColor));
localStorage.setItem('microphoneTextColor', JSON.stringify(event.detail.args[0].microphoneTextColor));
}
});
/************************************
*
*
*DM loading Fix Modul
*
*
************************************/
window.addEventListener('globalSocketReady', () => {
window.socket.on('getPNList', () => {
const scope = angular.element(document.getElementById('topbar')).scope();
scope.loading = false;
});
});
/************************************
*
*
*Top Wrapper & Icon Modul
*
*
************************************/
const TopWrapperIcon = {
init: function() {
this.addIconToTopWrapper();
},
addIconToTopWrapper: function() {
const topWrapper = document.querySelector('.area');
if (topWrapper) {
const iconButton = this.createIconButton();
iconButton.addEventListener('click', () => Menu.createPlaceholderMenu());
topWrapper.appendChild(iconButton);
} else {
console.warn('[AAC Enhanced] Top wrapper not found. Icon could not be added.');
}
},
createIconButton: function() {
const iconButton = document.createElement('div');
iconButton.id = 'aac-topWrapperIcon';
iconButton.style.width = '40px';
iconButton.style.height = '40px';
iconButton.style.borderRadius = '50%';
iconButton.style.display = 'flex';
iconButton.style.alignItems = 'center';
iconButton.style.justifyContent = 'center';
iconButton.style.cursor = 'pointer';
iconButton.style.marginRight = '10px';
iconButton.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.2)';
const iconImage = document.createElement('img');
iconImage.src = 'https://i.ibb.co/z5CJ5zv/revanced.png';
iconImage.alt = 'Menu Icon';
iconImage.style.width = '100%';
iconImage.style.height = '100%';
iconImage.style.borderRadius = '50%';
iconButton.appendChild(iconImage);
return iconButton;
}
};
/************************************
*
*
*Menü Modul
*
*
************************************/
const Menu = {
createPlaceholderMenu: function() {
const existingMenu = document.querySelector('#aac-placeholderMenu');
if (existingMenu) {
existingMenu.remove();
return;
}
const menu = this.createMenuElement();
document.body.appendChild(menu);
ChatArea.updateToggleButton();
this.updateToggleLeftbarButton();
},
createMenuElement: function() {
const menu = document.createElement('div');
menu.id = 'aac-placeholderMenu';
const iconButton = document.querySelector('#aac-topWrapperIcon');
const iconButtonRect = iconButton.getBoundingClientRect();
menu.style.position = 'absolute';
menu.style.top = `${iconButtonRect.bottom + window.scrollY + 10}px`;
menu.style.left = `${iconButtonRect.left + window.scrollX}px`;
menu.style.zIndex = '10001';
menu.style.padding = '20px';
menu.style.backgroundColor = '#fff';
menu.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
menu.style.borderRadius = '10px';
menu.style.textAlign = 'center';
const title = this.createTitleElement();
const wallpaperSectionTitle = document.createElement('h4');
wallpaperSectionTitle.innerText = 'Wallpaper Einstellungen';
wallpaperSectionTitle.style.marginTop = '20px';
wallpaperSectionTitle.style.marginBottom = '10px';
const wallpaperChangerButton = WallpaperChanger.createWallpaperChangerButton();
const savedWallpapersButton = WallpaperChanger.createSavedWallpapersButton();
const uiSettingsSectionTitle = document.createElement('h4');
uiSettingsSectionTitle.innerText = 'UI Einstellungen';
uiSettingsSectionTitle.style.marginTop = '20px';
uiSettingsSectionTitle.style.marginBottom = '10px';
const toggleChatAreaButton = ChatArea.createToggleChatAreaButton();
const toggleLeftbarButton = this.createToggleLeftbarButton();
// Add Reset Button to UI Settings
const resetChatAreaButton = document.createElement('button');
resetChatAreaButton.innerText = 'Chat Fenster Position zurücksetzen';
resetChatAreaButton.style.padding = '10px';
resetChatAreaButton.style.backgroundColor = '#573699';
resetChatAreaButton.style.color = '#fff';
resetChatAreaButton.style.border = 'none';
resetChatAreaButton.style.borderRadius = '5px';
resetChatAreaButton.style.cursor = 'pointer';
resetChatAreaButton.style.marginBottom = '10px';
resetChatAreaButton.addEventListener('click', () => ChatArea.resetChatAreaPosition());
// PNG Management Section
const pngSectionTitle = document.createElement('h4');
pngSectionTitle.innerText = 'PNG Management';
pngSectionTitle.style.marginTop = '20px';
pngSectionTitle.style.marginBottom = '10px';
const pngManagerButton = this.createPngManagerButton();
const closeButton = this.createCloseButton();
menu.appendChild(title);
menu.appendChild(wallpaperSectionTitle);
menu.appendChild(wallpaperChangerButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(savedWallpapersButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(uiSettingsSectionTitle);
menu.appendChild(toggleChatAreaButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(toggleLeftbarButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(resetChatAreaButton); // Moved here
menu.appendChild(document.createElement('br'));
// Append PNG Management section
menu.appendChild(pngSectionTitle);
menu.appendChild(pngManagerButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(closeButton);
return menu;
},
createTitleElement: function() {
const title = document.createElement('h3');
title.innerText = 'AC-Enhanced Settings';
title.style.marginBottom = '20px';
return title;
},
createToggleLeftbarButton: function() {
const toggleLeftbarButton = document.createElement('button');
toggleLeftbarButton.id = 'aac-toggleLeftbarButton';
toggleLeftbarButton.style.padding = '10px';
toggleLeftbarButton.style.color = '#fff';
toggleLeftbarButton.style.border = 'none';
toggleLeftbarButton.style.borderRadius = '5px';
toggleLeftbarButton.style.cursor = 'pointer';
toggleLeftbarButton.style.marginBottom = '10px';
toggleLeftbarButton.addEventListener('click', () => Menu.toggleLeftbarVisibility());
return toggleLeftbarButton;
},
createResetChatAreaButton: function() {
const resetButton = document.createElement('button');
resetButton.innerText = 'Chat Fenster Position zurücksetzen';
resetButton.style.padding = '10px';
resetButton.style.backgroundColor = '#573699';
resetButton.style.color = '#fff';
resetButton.style.border = 'none';
resetButton.style.borderRadius = '5px';
resetButton.style.cursor = 'pointer';
resetButton.style.marginBottom = '10px';
resetButton.addEventListener('click', () => ChatArea.resetChatAreaPosition());
return resetButton;
},
createPngManagerButton: function() {
const pngManagerButton = document.createElement('button');
pngManagerButton.innerText = 'PNG Management';
pngManagerButton.style.padding = '10px';
pngManagerButton.style.backgroundColor = '#573699';
pngManagerButton.style.color = '#fff';
pngManagerButton.style.border = 'none';
pngManagerButton.style.borderRadius = '5px';
pngManagerButton.style.cursor = 'pointer';
pngManagerButton.style.marginBottom = '10px';
pngManagerButton.addEventListener('click', () => {
PngManager.createPngMenu();
});
return pngManagerButton;
},
createCloseButton: function() {
const closeButton = document.createElement('button');
closeButton.innerText = 'Schließen';
closeButton.style.padding = '10px';
closeButton.style.backgroundColor = '#ccc';
closeButton.style.color = '#000';
closeButton.style.border = 'none';
closeButton.style.borderRadius = '5px';
closeButton.style.cursor = 'pointer';
closeButton.addEventListener('click', () => {
const menu = document.querySelector('#aac-placeholderMenu');
if (menu) menu.remove();
});
return closeButton;
},
toggleLeftbarVisibility: function() {
const leftbar = document.querySelector('#leftbar');
const chatBox = document.querySelector('#chatverlaufbox');
if (!leftbar) return;
if (leftbar.style.visibility === 'hidden') {
leftbar.style.transition = 'visibility 0s, opacity 0.5s linear';
leftbar.style.opacity = '1';
leftbar.style.visibility = 'visible';
leftbar.style.pointerEvents = 'auto';
if (chatBox) chatBox.style.left = '250px';
localStorage.setItem('aac-leftbarVisibility', 'visible');
} else {
leftbar.style.transition = 'visibility 0s 0.5s, opacity 0.5s linear';
leftbar.style.opacity = '0';
leftbar.style.visibility = 'hidden';
leftbar.style.pointerEvents = 'none';
if (chatBox) chatBox.style.left = '0';
localStorage.setItem('aac-leftbarVisibility', 'hidden');
}
this.updateToggleLeftbarButton();
}
};
Menu.updateToggleLeftbarButton = function() {
const toggleLeftbarButton = document.querySelector('#aac-toggleLeftbarButton');
const leftbarVisible = localStorage.getItem('aac-leftbarVisibility') !== 'hidden';
if (toggleLeftbarButton) {
if (leftbarVisible) {
toggleLeftbarButton.innerText = 'User Liste verstecken';
toggleLeftbarButton.style.backgroundColor = '#573699';
} else {
toggleLeftbarButton.innerText = 'User Liste zeigen';
toggleLeftbarButton.style.backgroundColor = '#FF0000';
}
}
};
// Initialize the leftbar visibility state on load
document.addEventListener('DOMContentLoaded', () => {
sessionStorage.removeItem('aac-wallpaperChanged');
sessionStorage.removeItem('aac-chatAreaButtonState');
const leftbar = document.querySelector('#leftbar');
const chatBox = document.querySelector('#chatverlaufbox');
const toggleLeftbarButton = document.querySelector('#aac-toggleLeftbarButton');
if (leftbar) {
const leftbarVisible = localStorage.getItem('aac-leftbarVisibility') !== 'hidden';
leftbar.style.transition = 'visibility 0s, opacity 0.5s linear';
leftbar.style.opacity = leftbarVisible ? '1' : '0';
leftbar.style.visibility = leftbarVisible ? 'visible' : 'hidden';
leftbar.style.pointerEvents = leftbarVisible ? 'auto' : 'none';
if (chatBox) {
chatBox.style.left = leftbarVisible ? '250px' : '0'; // Ensure consistent positioning for chatbox
}
if (toggleLeftbarButton) {
toggleLeftbarButton.innerText = leftbarVisible ? 'User Liste verstecken' : 'User Liste zeigen';
toggleLeftbarButton.style.backgroundColor = leftbarVisible ? '#573699' : '#FF0000';
}
}
window.onbeforeunload = () => {}; // Disable confirmation popup when reloading the page
});
/************************************
*
*
* PNG "Sticker" Modul
*
*
************************************/
const PngManager = {
init: function() {
$(document).ready(() => {
this.loadSavedPngs();
});
},
loadSavedPngs: function() {
const savedPngs = JSON.parse(localStorage.getItem('aac-savedPngs') || '[]');
savedPngs.forEach((png, index) => {
if (png.active) {
this.createPngElement(png.url, index);
}
});
},
createPngMenu: function() {
const existingMenu = document.querySelector('#aac-pngMenu');
if (existingMenu) {
existingMenu.remove();
return;
}
const menu = document.createElement('div');
menu.id = 'aac-pngMenu';
menu.style.position = 'fixed';
menu.style.top = '50%';
menu.style.left = '50%';
menu.style.transform = 'translate(-50%, -50%)';
menu.style.zIndex = '10001';
menu.style.padding = '20px';
menu.style.backgroundColor = '#fff';
menu.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
menu.style.borderRadius = '10px';
menu.style.textAlign = 'center';
const title = document.createElement('h3');
title.innerText = 'PNG Management';
title.style.marginBottom = '20px';
menu.appendChild(title);
// Toggle Handles Button
const toggleHandlesButton = document.createElement('button');
toggleHandlesButton.innerText = 'Toggle Handles';
toggleHandlesButton.style.padding = '10px';
toggleHandlesButton.style.backgroundColor = '#573699';
toggleHandlesButton.style.color = '#fff';
toggleHandlesButton.style.border = 'none';
toggleHandlesButton.style.borderRadius = '5px';
toggleHandlesButton.style.cursor = 'pointer';
toggleHandlesButton.style.marginBottom = '10px';
toggleHandlesButton.addEventListener('click', () => {
const handles = document.querySelectorAll('.aac-png-handle');
const areHandlesVisible = handles[0].style.display !== 'none';
handles.forEach(handle => {
handle.style.display = areHandlesVisible ? 'none' : 'block';
});
// Save state to localStorage
localStorage.setItem('aac-png-handles-visible', !areHandlesVisible);
});
menu.appendChild(toggleHandlesButton);
const savedPngs = JSON.parse(localStorage.getItem('aac-savedPngs') || '[]');
savedPngs.forEach((png, index) => {
const pngContainer = document.createElement('div');
pngContainer.style.display = 'flex';
pngContainer.style.alignItems = 'center';
pngContainer.style.marginBottom = '10px';
const thumbnail = document.createElement('img');
thumbnail.src = png.url;
thumbnail.alt = png.name || `PNG ${index + 1}`;
thumbnail.style.width = '50px';
thumbnail.style.height = '50px';
thumbnail.style.objectFit = 'cover';
thumbnail.style.borderRadius = '5px';
thumbnail.style.marginRight = '10px';
const activateButton = document.createElement('button');
activateButton.innerText = png.active ? 'Ausblenden' : 'Einblenden';
activateButton.style.padding = '10px';
activateButton.style.marginRight = '5px';
activateButton.style.backgroundColor = png.active ? '#FF0000' : '#573699';
activateButton.style.color = '#fff';
activateButton.style.border = 'none';
activateButton.style.borderRadius = '5px';
activateButton.style.cursor = 'pointer';
activateButton.addEventListener('click', () => {
png.active = !png.active;
savedPngs[index] = png;
localStorage.setItem('aac-savedPngs', JSON.stringify(savedPngs));
if (png.active) {
this.createPngElement(png.url, index);
} else {
const existingPng = document.querySelector(`#aac-png-${index}`);
if (existingPng) existingPng.remove();
}
activateButton.innerText = png.active ? 'Ausblenden' : 'Einblenden';
activateButton.style.backgroundColor = png.active ? '#FF0000' : '#573699';
});
const deleteButton = document.createElement('button');
deleteButton.innerText = '✕';
deleteButton.style.marginLeft = '5px';
deleteButton.style.padding = '2px';
deleteButton.style.width = '20px';
deleteButton.style.height = '20px';
deleteButton.style.backgroundColor = '#FF0000';
deleteButton.style.color = '#fff';
deleteButton.style.border = 'none';
deleteButton.style.borderRadius = '3px';
deleteButton.style.cursor = 'pointer';
deleteButton.addEventListener('click', () => {
savedPngs.splice(index, 1);
localStorage.setItem('aac-savedPngs', JSON.stringify(savedPngs));
// Remove the entire container (including handles)
const existingPngContainer = document.querySelector(`#aac-png-container-${index}`);
if (existingPngContainer) existingPngContainer.remove();
menu.remove();
this.createPngMenu();
});
pngContainer.appendChild(thumbnail);
pngContainer.appendChild(activateButton);
pngContainer.appendChild(deleteButton);
menu.appendChild(pngContainer);
});
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/png';
fileInput.style.marginBottom = '10px';
fileInput.style.display = 'block';
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
if (file.size > 2560 * 2560) {
alert('Die PNG-Datei ist zu groß. Bitte wählen Sie eine Datei, die kleiner als 2,5 MB ist.');
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const pngUrl = e.target.result;
let savedPngs = JSON.parse(localStorage.getItem('aac-savedPngs') || '[]');
if (savedPngs.length >= 5) {
alert('Du kannst maximal 5 PNG-Dateien speichern. Bitte lösche eine, bevor du eine neue hinzufügst.');
return;
}
savedPngs.push({ url: pngUrl, name: file.name, active: false });
localStorage.setItem('aac-savedPngs', JSON.stringify(savedPngs));
menu.remove();
this.createPngMenu();
};
reader.readAsDataURL(file);
}
});
const closeButton = document.createElement('button');
closeButton.innerText = 'Schließen';
closeButton.style.marginTop = '20px';
closeButton.style.padding = '10px';
closeButton.style.backgroundColor = '#ccc';
closeButton.style.color = '#000';
closeButton.style.border = 'none';
closeButton.style.borderRadius = '5px';
closeButton.style.cursor = 'pointer';
closeButton.addEventListener('click', () => {
menu.remove();
});
menu.appendChild(fileInput);
menu.appendChild(closeButton);
document.body.appendChild(menu);
},
createResizeHandle: function() {
const resizeHandle = document.createElement('div');
resizeHandle.classList.add('aac-png-handle');
resizeHandle.style.width = '15px';
resizeHandle.style.height = '15px';
resizeHandle.style.backgroundColor = '#573699'; // Purple for resizing
resizeHandle.style.border = '2px solid #fff';
resizeHandle.style.position = 'absolute';
resizeHandle.style.right = '0';
resizeHandle.style.bottom = '0';
resizeHandle.style.cursor = 'se-resize';
resizeHandle.title = 'Resize'; // Tooltip
return resizeHandle;
},
createRotateHandle: function() {
const rotateHandle = document.createElement('div');
rotateHandle.classList.add('aac-png-handle');
rotateHandle.style.width = '15px';
rotateHandle.style.height = '15px';
rotateHandle.style.backgroundColor = '#FF0000'; // Red for rotating
rotateHandle.style.border = '2px solid #fff';
rotateHandle.style.position = 'absolute';
rotateHandle.style.top = '0';
rotateHandle.style.right = '0';
rotateHandle.style.cursor = 'grab';
rotateHandle.title = 'Rotate'; // Tooltip
return rotateHandle;
},
createPngElement: function(url, index) {
const pngElement = document.createElement('img');
pngElement.src = url;
pngElement.id = `aac-png-${index}`;
// Set initial styles for the PNG
pngElement.style.position = 'absolute'; // Position relative to the container
pngElement.style.width = '150px';
pngElement.style.height = '150px';
pngElement.style.cursor = 'move';
pngElement.style.transformOrigin = 'center center'; // For rotation
// Container for the PNG and handles
const pngContainer = document.createElement('div');
pngContainer.id = `aac-png-container-${index}`; // Unique ID for the container
pngContainer.style.position = 'fixed';
pngContainer.style.top = '100px';
pngContainer.style.left = '100px';
pngContainer.style.zIndex = '10002';
pngContainer.style.pointerEvents = 'auto';
// Append the PNG to the container
pngContainer.appendChild(pngElement);
// Create and append handles
const resizeHandle = this.createResizeHandle();
const rotateHandle = this.createRotateHandle();
pngContainer.appendChild(resizeHandle);
pngContainer.appendChild(rotateHandle);
// Append the container to the body
document.body.appendChild(pngContainer);
let isDragging = false;
let isResizing = false;
let isRotating = false;
let startX, startY, initialLeft, initialTop, initialWidth, initialHeight, initialAngle;
// Dragging logic
pngContainer.addEventListener('mousedown', (e) => {
if (e.target === resizeHandle || e.target === rotateHandle) {
return; // Ignore mousedown on handles for dragging
}
e.preventDefault();
isDragging = true;
startX = e.clientX;
startY = e.clientY;
initialLeft = parseInt(pngContainer.style.left, 10) || 0;
initialTop = parseInt(pngContainer.style.top, 10) || 0;
pngElement.style.opacity = '0.6';
});
// Resizing logic
resizeHandle.addEventListener('mousedown', (e) => {
e.preventDefault();
isResizing = true;
startX = e.clientX;
startY = e.clientY;
initialWidth = pngElement.offsetWidth;
initialHeight = pngElement.offsetHeight;
});
// Rotating logic
rotateHandle.addEventListener('mousedown', (e) => {
e.preventDefault();
isRotating = true;
startX = e.clientX;
startY = e.clientY;
const transform = pngElement.style.transform;
initialAngle = transform ? parseFloat(transform.replace('rotate(', '').replace('deg)', '')) : 0;
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
const newLeft = initialLeft + deltaX;
const newTop = initialTop + deltaY;
// Update container position
pngContainer.style.left = `${newLeft}px`;
pngContainer.style.top = `${newTop}px`;
}
if (isResizing) {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
const newWidth = initialWidth + deltaX;
const newHeight = initialHeight + deltaY;
// Ensure minimum size
if (newWidth > 50 && newHeight > 50) {
pngElement.style.width = `${newWidth}px`;
pngElement.style.height = `${newHeight}px`;
}
}
if (isRotating) {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
const angle = initialAngle + Math.atan2(deltaY, deltaX) * (180 / Math.PI);
pngElement.style.transform = `rotate(${angle}deg)`;
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
isResizing = false;
isRotating = false;
pngElement.style.opacity = '1';
});
}
};
// Load handle visibility state on page load
document.addEventListener('DOMContentLoaded', () => {
const handlesVisible = localStorage.getItem('aac-png-handles-visible') === 'true';
const handles = document.querySelectorAll('.aac-png-handle');
handles.forEach(handle => {
handle.style.display = handlesVisible ? 'block' : 'none';
});
});
/************************************
*
*
* Wallpaper Modul
*
*
************************************/
const WallpaperChanger = {
init: function() {
this.applySavedBackground();
},
applySavedBackground: function() {
const savedImageUrl = localStorage.getItem('aac-customBackgroundUrl');
if (savedImageUrl) {
this.applyCustomBackground(savedImageUrl);
} else {
this.resetToDefaultBackground();
}
},
applyCustomBackground: function(url) {
if (url) {
document.documentElement.style.cssText = `
background-image: url("${url}") !important;
background-color: #000 !important;
background-position: center center !important;
background-attachment: fixed !important;
background-size: cover !important;
background-repeat: no-repeat !important;
`;
document.body.style.cssText = `
background-image: url("${url}") !important;
background-color: #000 !important;
background-position: center center !important;
background-attachment: fixed !important;
background-size: cover !important;
background-repeat: no-repeat !important;
`;
}
},
resetToDefaultBackground: function() {
document.documentElement.style.cssText = '';
document.body.style.cssText = '';
localStorage.removeItem('aac-customBackgroundUrl');
},
createWallpaperChangerButton: function() {
const button = document.createElement('button');
button.innerText = 'Hintergrund ändern'; // Change Wallpaper -> Hintergrund ändern
button.style.padding = '10px';
button.style.backgroundColor = '#573699';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.marginBottom = '10px';
button.addEventListener('click', () => {
WallpaperChanger.createInputMenu();
const menu = document.querySelector('#aac-placeholderMenu');
if (menu) menu.remove();
});
return button;
},
createSavedWallpapersButton: function() {
const button = document.createElement('button');
button.innerText = 'Gespeicherte Hintergründe'; // Saved Wallpapers -> Gespeicherte Hintergründe
button.style.padding = '10px';
button.style.backgroundColor = '#573699';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.marginBottom = '10px';
button.addEventListener('click', () => {
WallpaperChanger.createSavedWallpapersMenu();
});
return button;
},
createSavedWallpapersMenu: function() {
const menu = document.createElement('div');
menu.style.position = 'fixed';
menu.style.top = '50%';
menu.style.left = '50%';
menu.style.transform = 'translate(-50%, -50%)';
menu.style.zIndex = '10001';
menu.style.padding = '20px';
menu.style.backgroundColor = '#fff';
menu.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
menu.style.borderRadius = '10px';
menu.style.textAlign = 'center';
const title = document.createElement('h3');
title.innerText = 'Gespeicherte Hintergründe';
title.style.marginBottom = '20px';
menu.appendChild(title);
const savedWallpapers = JSON.parse(localStorage.getItem('aac-savedWallpapers') || '[]');
savedWallpapers.forEach((wallpaper, index) => {
const wallpaperContainer = document.createElement('div');
wallpaperContainer.style.display = 'flex';
wallpaperContainer.style.alignItems = 'center';
wallpaperContainer.style.marginBottom = '10px';
const thumbnail = document.createElement('img');
thumbnail.src = wallpaper.url;
thumbnail.alt = wallpaper.name || `Wallpaper ${index + 1}`;
thumbnail.style.width = '50px';
thumbnail.style.height = '50px';
thumbnail.style.objectFit = 'cover';
thumbnail.style.borderRadius = '5px';
thumbnail.style.marginRight = '10px';
const wallpaperButton = document.createElement('button');
wallpaperButton.innerText = wallpaper.name || `Wallpaper ${index + 1}`;
wallpaperButton.style.padding = '10px';
wallpaperButton.style.backgroundColor = '#573699';
wallpaperButton.style.color = '#fff';
wallpaperButton.style.border = 'none';
wallpaperButton.style.borderRadius = '5px';
wallpaperButton.style.cursor = 'pointer';
wallpaperButton.style.marginRight = '5px';
wallpaperButton.addEventListener('click', () => {
WallpaperChanger.applyCustomBackground(wallpaper.url);
localStorage.setItem('aac-customBackgroundUrl', wallpaper.url); // Save the applied wallpaper URL
});
const deleteButton = document.createElement('button');
deleteButton.innerText = '✕';
deleteButton.style.marginLeft = '5px';
deleteButton.style.padding = '2px';
deleteButton.style.width = '20px';
deleteButton.style.height = '20px';
deleteButton.style.backgroundColor = '#FF0000';
deleteButton.style.color = '#fff';
deleteButton.style.border = 'none';
deleteButton.style.borderRadius = '3px';
deleteButton.style.cursor = 'pointer';
deleteButton.addEventListener('click', () => {
let savedWallpapers = JSON.parse(localStorage.getItem('aac-savedWallpapers') || '[]');
// Remove the selected wallpaper
savedWallpapers.splice(index, 1);
localStorage.setItem('aac-savedWallpapers', JSON.stringify(savedWallpapers));
// Remove the wallpaper container
wallpaperContainer.remove();
// Refresh the menu to reflect the change
menu.remove();
WallpaperChanger.createSavedWallpapersMenu();
});
wallpaperContainer.appendChild(thumbnail);
wallpaperContainer.appendChild(wallpaperButton);
wallpaperContainer.appendChild(deleteButton);
menu.appendChild(wallpaperContainer);
});
// Add a button to reset to the default wallpaper
const resetButton = document.createElement('button');
resetButton.innerText = 'Standardhintergrund wiederherstellen'; // Reset to Default Background
resetButton.style.marginTop = '20px';
resetButton.style.padding = '10px';
resetButton.style.backgroundColor = '#ccc';
resetButton.style.color = '#000';
resetButton.style.border = 'none';
resetButton.style.borderRadius = '5px';
resetButton.style.cursor = 'pointer';
resetButton.addEventListener('click', () => {
WallpaperChanger.resetToDefaultBackground();
menu.remove();
});
menu.appendChild(resetButton);
const closeButton = document.createElement('button');
closeButton.innerText = 'Schließen';
closeButton.style.marginTop = '10px';
closeButton.style.padding = '10px';
closeButton.style.backgroundColor = '#ccc';
closeButton.style.color = '#000';
closeButton.style.border = 'none';
closeButton.style.borderRadius = '5px';
closeButton.style.cursor = 'pointer';
closeButton.addEventListener('click', () => {
menu.remove();
});
menu.appendChild(closeButton);
document.body.appendChild(menu);
},
createInputMenu: function() {
const menu = document.createElement('div');
menu.style.position = 'fixed';
menu.style.top = '50%';
menu.style.left = '50%';
menu.style.transform = 'translate(-50%, -50%)';
menu.style.zIndex = '10001';
menu.style.padding = '20px';
menu.style.backgroundColor = '#fff';
menu.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
menu.style.borderRadius = '10px';
menu.style.textAlign = 'center';
const input = document.createElement('input');
input.type = 'text';
input.placeholder = 'Bild-URL hier eingeben...'; // Enter image URL here...
input.value = localStorage.getItem('aac-customBackgroundUrl') || '';
input.style.width = '300px';
input.style.padding = '10px';
input.style.marginBottom = '10px';
input.style.border = '1px solid #ccc';
input.style.borderRadius = '5px';
const nameInput = document.createElement('input');
nameInput.type = 'text';
nameInput.placeholder = 'Geben Sie den Namen des Hintergrunds ein...'; // Enter wallpaper name...
nameInput.style.width = '300px';
nameInput.style.padding = '10px';
nameInput.style.marginBottom = '10px';
nameInput.style.border = '1px solid #ccc';
nameInput.style.borderRadius = '5px';
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'image/*';
fileInput.style.marginBottom = '10px';
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
// Check if file size exceeds 1 MB (1 MB = 1024 * 1024 bytes)
if (file.size > 2.5 * 1024 * 1024) {
alert('Die Bilddatei ist zu groß. Bitte wählen Sie eine Datei, die kleiner als 2,5 MB ist.');
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const imageUrl = e.target.result;
input.value = imageUrl;
};
reader.readAsDataURL(file);
}
});
const applyButton = document.createElement('button');
applyButton.innerText = 'Hintergrund anwenden'; // Apply Background -> Hintergrund anwenden
applyButton.style.marginLeft = '10px';
applyButton.style.padding = '10px';
applyButton.style.backgroundColor = '#573699';
applyButton.style.color = '#fff';
applyButton.style.border = 'none';
applyButton.style.borderRadius = '5px';
applyButton.style.cursor = 'pointer';
applyButton.addEventListener('click', () => {
const imageUrl = input.value.trim();
const wallpaperName = nameInput.value.trim();
if (imageUrl && wallpaperName) {
localStorage.setItem('aac-customBackgroundUrl', imageUrl);
WallpaperChanger.applyCustomBackground(imageUrl);
sessionStorage.setItem('aac-wallpaperChanged', 'true');
menu.remove();
} else {
alert('Bitte geben Sie eine gültige URL und einen Namen ein.'); // Please enter a valid URL and name.
}
});
const saveButton = document.createElement('button');
saveButton.innerText = 'Hintergrund speichern'; // Save Wallpaper -> Hintergrund speichern
saveButton.style.marginTop = '10px';
saveButton.style.padding = '10px';
saveButton.style.backgroundColor = '#573699';
saveButton.style.color = '#fff';
saveButton.style.border = 'none';
saveButton.style.borderRadius = '5px';
saveButton.style.cursor = 'pointer';
saveButton.addEventListener('click', () => {
const imageUrl = input.value.trim();
const wallpaperName = nameInput.value.trim();
if (imageUrl && wallpaperName) {
let savedWallpapers = JSON.parse(localStorage.getItem('aac-savedWallpapers') || '[]');
if (savedWallpapers.length >= 5) {
alert('Du kannst maximal 5 Hintergründe speichern. Bitte lösche einen, bevor du einen neuen hinzufügst.'); // You can save a maximum of 5 wallpapers. Please delete one before adding a new one.
return;
}
WallpaperChanger.saveWallpaper(imageUrl, wallpaperName);
alert('Hintergrund erfolgreich gespeichert.'); // Wallpaper saved successfully.
} else {
alert('Bitte geben Sie eine gültige URL und einen Namen ein.'); // Please enter a valid URL and name.
}
});
const closeButton = document.createElement('button');
closeButton.innerText = 'Schließen'; // Close -> Schließen
closeButton.style.marginTop = '10px';
closeButton.style.padding = '10px';
closeButton.style.backgroundColor = '#ccc';
closeButton.style.color = '#000';
closeButton.style.border = 'none';
closeButton.style.borderRadius = '5px';
closeButton.style.cursor = 'pointer';
closeButton.addEventListener('click', () => {
menu.remove();
});
menu.appendChild(input);
menu.appendChild(document.createElement('br'));
menu.appendChild(nameInput);
menu.appendChild(document.createElement('br'));
menu.appendChild(fileInput);
menu.appendChild(applyButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(saveButton);
menu.appendChild(document.createElement('br'));
menu.appendChild(closeButton);
document.body.appendChild(menu);
},
saveWallpaper: function(url, name) {
let savedWallpapers = JSON.parse(localStorage.getItem('aac-savedWallpapers') || '[]');
if (!savedWallpapers.some(wallpaper => wallpaper.url === url)) {
savedWallpapers.push({ url, name });
localStorage.setItem('aac-savedWallpapers', JSON.stringify(savedWallpapers));
}
},
deleteWallpaper: function(index) {
let savedWallpapers = JSON.parse(localStorage.getItem('aac-savedWallpapers') || '[]');
savedWallpapers.splice(index, 1);
localStorage.setItem('aac-savedWallpapers', JSON.stringify(savedWallpapers));
}
};
/************************************
*
*
* Chat Area Modul
*
*
************************************/
const ChatArea = {
isDraggable: false,
init: function() {
this.chatArea = document.querySelector('#graphicChatArea');
if (this.chatArea) {
this.centerChatArea();
this.chatArea.style.position = 'absolute';
const savedState = localStorage.getItem('aac-isChatAreaDraggable');
if (savedState === 'true') {
this.enableDraggable();
}
}
},
centerChatArea: function() {
if (this.chatArea) {
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const chatWidth = this.chatArea.offsetWidth;
const chatHeight = this.chatArea.offsetHeight;
this.chatArea.style.left = `${(windowWidth - chatWidth) / 2}px`;
this.chatArea.style.top = `${(windowHeight - chatHeight) / 2}px`;
}
},
resetChatAreaPosition: function() {
this.centerChatArea();
console.log('[AAC Enhanced] Chat area position reset to center.');
},
toggleDraggable: function() {
if (!this.chatArea) return;
if (this.isDraggable) {
this.disableDraggable();
} else {
this.enableDraggable();
}
this.updateToggleButton();
},
enableDraggable: function() {
this.isDraggable = true;
localStorage.setItem('aac-isChatAreaDraggable', 'true');
sessionStorage.setItem('aac-chatAreaButtonState', 'true');
$(this.chatArea).draggable({
containment: 'document',
start: function() {
ChatArea.chatArea.classList.add('ui-draggable-enabled');
},
stop: function() {
ChatArea.chatArea.classList.remove('ui-draggable-enabled');
}
});
console.log('[AAC Enhanced] Chat area is now draggable.');
},
disableDraggable: function() {
this.isDraggable = false;
localStorage.setItem('aac-isChatAreaDraggable', 'false');
if ($(this.chatArea).draggable('instance')) {
$(this.chatArea).draggable('destroy');
}
console.log('[AAC Enhanced] Draggable functionality has been disabled.');
},
updateToggleButton: function() {
const toggleButton = document.querySelector('#aac-toggleChatAreaButton');
if (toggleButton) {
if (this.isDraggable) {
toggleButton.innerText = 'Verschiebbare Chat-Bereich deaktivieren'; // Disable Draggable Chat Area
toggleButton.style.backgroundColor = '#FF0000';
} else {
toggleButton.innerText = 'Verschiebbare Chat-Bereich aktivieren'; // Enable Draggable Chat Area
toggleButton.style.backgroundColor = '#573699';
}
}
},
createToggleChatAreaButton: function() {
const button = document.createElement('button');
button.id = 'aac-toggleChatAreaButton';
button.style.padding = '10px';
button.style.color = '#fff';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.marginBottom = '10px';
button.addEventListener('click', () => ChatArea.toggleDraggable());
return button;
}
};
/************************************
*
*
*Reply Modul & Image in Chat Modul
*
*
************************************/
const messageDiv = document.getElementsByClassName('chatverlauf')[0];
const messageObserverConfig = { childList: true };
const messagesMutationCallback = function (mutationsList) {
for (const mutation of mutationsList) {
// Reply-Message
if (mutation.addedNodes.length) {
const message = mutation.addedNodes[0];
const chatMessageDiv = message.querySelectorAll(`[ng-bind-html^='chatmsg.msg']`)[0];
const messageContent = chatMessageDiv.textContent;
const isSystemMessage = message.classList.contains('systemMsg');
const isEmojiMessage = message.querySelectorAll(`[ng-if='chatmsg.emojiImage']`).length > 0;
const isOwnMessage = messageContent.startsWith(': ');
message.style.paddingLeft = '1px';
if (isEmojiMessage) {
continue;
}
if (isSystemMessage) {
continue;
}
message.classList.add('chatMessage');
const messageIconsDiv = document.createElement('div');
messageIconsDiv.classList.add('messageIcons');
messageIconsDiv.innerHTML =
'<svg aria-hidden="true" class="svg-inline--fa fa-quote-right fa-w-16" focusable="false" data-prefix="fa" data-icon="quote-right" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" data-fa-i2svg=""><path fill="#d2d2d2" d="M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z"></path></svg>';
message.appendChild(messageIconsDiv);
message.addEventListener('mouseover', function () {
const iconDiv = this.children[this.children.length - 1];
iconDiv.style.display = 'flex';
});
message.addEventListener('mouseout', function () {
const iconDiv = this.children[this.children.length - 1];
iconDiv.style.display = 'none';
});
messageIconsDiv.addEventListener('click', function () {
const scope = angular.element(document.getElementById('topbar')).scope();
const messageInput = document.getElementById('chatline');
let username = '';
if (!isOwnMessage) {
username = chatMessageDiv.previousElementSibling.textContent.slice(0, -1);
} else {
username = chatMessageDiv.previousElementSibling.textContent;
}
if (scope.chatline === undefined) {
scope.chatline = '';
}
if (!isOwnMessage) {
scope.chatline += ` @${username} "${messageContent}" `;
} else {
scope.chatline += ` @${username} "${messageContent.split(': ')[1]}" `;
}
messageInput.focus();
});
/************************************
*
*
*View Images in chat Modul
*
*
************************************/
const imageUrlRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:png|jpg|jpeg|gif|svg))`);
const isImageUrl = messageContent.match(imageUrlRegex);
if (isImageUrl) {
const imageUrl = isImageUrl[0];
const imageDiv = document.createElement('div');
const imageElement = document.createElement('img');
imageDiv.setAttribute('class', 'message-image-container');
imageElement.setAttribute('class', 'message-image');
imageElement.src = imageUrl;
imageDiv.appendChild(imageElement);
chatMessageDiv.appendChild(imageDiv);
}
}
}
};
const messagesObserver = new MutationObserver(messagesMutationCallback);
messagesObserver.observe(messageDiv, messageObserverConfig);
/************************************
*
*
* Avatar-Collections Modul
*
*
************************************/
if (!localStorage.hasOwnProperty('collections')) {
localStorage.setItem('collections', JSON.stringify({ 'Keine Kategorie': { isDefault: true } }));
}
if (!localStorage.hasOwnProperty('avatars')) {
localStorage.setItem('avatars', JSON.stringify({}));
}
window.addEventListener('globalSocketReady', () => {
window.socket.on('getAvatarcase', (data) => {
const avatars = data.avatars;
const storageAvatars = JSON.parse(localStorage.getItem('avatars'));
for (const avatar of avatars) {
if (!storageAvatars[avatar.avatarid]) {
storageAvatars[avatar.avatarid] = {
id: avatar.avatarid,
img: avatar.img,
imgthumb: avatar.imgthumb,
collection: 'Keine Kategorie',
};
}
}
localStorage.setItem('avatars', JSON.stringify(storageAvatars));
});
window.socket.emit('getAvatarcase');
});
window.addEventListener('socketEmit', (event) => {
if (event.detail.eventName === 'deleteAvatar') {
// Remove Avatar properly in case it gets deleted
const avatarID = event.detail.args[0].avatarid;
const avatarDiv = document.querySelectorAll(`[id^='${avatarID}']`)[0];
avatarDiv.remove();
const storageAvatars = JSON.parse(localStorage.getItem('avatars'));
delete storageAvatars[avatarID];
localStorage.setItem('avatars', JSON.stringify(storageAvatars));
}
});
window.addAvatarToCollection = function (avatarID, collection) {
const collections = JSON.parse(localStorage.getItem('collections'));
if (!collections[collection]) {
console.log(`Collection '${collection}' doesn't exist!`);
return false;
}
const storageAvatars = JSON.parse(localStorage.getItem('avatars'));
if (!storageAvatars[avatarID]) {
console.log(`Avatar '${avatarID}' doesn't exist!`);
return false;
}
storageAvatars[avatarID].collection = collection;
localStorage.setItem('avatars', JSON.stringify(storageAvatars));
return true;
};
window.removeAvatarFromCollection = function (avatarID) {
const storageAvatars = JSON.parse(localStorage.getItem('avatars'));
if (!storageAvatars[avatarID]) {
console.log(`Avatar '${avatarID}' doesn't exist!`);
return false;
}
storageAvatars[avatarID].collection = 'Keine Kategorie';
localStorage.setItem('avatars', JSON.stringify(storageAvatars));
return true;
};
window.addCollection = function (collection) {
const collections = JSON.parse(localStorage.getItem('collections'));
if (collections[collection]) {
console.log(`Collection ${collection} already exists!`);
return false;
}
collections[collection] = {
isDefault: false,
};
localStorage.setItem('collections', JSON.stringify(collections));
return true;
};
window.deleteCollection = function (collection) {
const collections = JSON.parse(localStorage.getItem('collections'));
if (!collections[collection]) {
console.log(`Collection '${collection}' doesn't exist!`);
return false;
}
if (collections[collection].isDefault) {
console.log(`Default collections such as '${collection}' must not be deleted!`);
return false;
}
const storageAvatars = JSON.parse(localStorage.getItem('avatars'));
for (const avatar in storageAvatars) {
if (storageAvatars[avatar].collection === collection) {
storageAvatars[avatar].collection = 'Keine Kategorie';
}
}
localStorage.setItem('avatars', JSON.stringify(storageAvatars));
delete collections[collection];
localStorage.setItem('collections', JSON.stringify(collections));
return true;
};
// View
const avatarcaseObserverConfig = { childList: true };
const avatarcaseDiv = document.querySelector('[ng-hide="disconnectedClient"]').children[1];
const avatarcaseMutationCallback = function (mutationsList) {
for (const mutation of mutationsList) {
for (const node of mutation.addedNodes) {
if (node.id === 'avatarcase') {
const acSelfAvatarElements = document.querySelectorAll('[ng-repeat="ownedAva in ownedAvas track by $index"]');
setTimeout(() => {
for (const element of acSelfAvatarElements) {
element.remove();
}
}, 1200);
const collections = JSON.parse(localStorage.getItem('collections'));
const avatarCaseDiv = document.getElementsByClassName('avatarcase_main')[0];
for (const collection in collections) {
const collapsibleWrap = createCategoryElement(collection, node, avatarCaseDiv);
avatarCaseDiv.append(collapsibleWrap);
}
const newCollectionFormDiv = document.createElement('div');
const newCollectionInput = document.createElement('input');
const newCollectionSubmitButton = document.createElement('button');
newCollectionSubmitButton.textContent = 'Neue Kategorie erstellen';
newCollectionSubmitButton.id = 'createCollectionBtn';
newCollectionInput.id = 'createCollectionInput';
newCollectionFormDiv.appendChild(newCollectionInput);
newCollectionFormDiv.appendChild(newCollectionSubmitButton);
newCollectionSubmitButton.addEventListener('click', function () {
const input = document.getElementById('createCollectionInput');
if (input.value !== '') {
const successfullyAdded = window.addCollection(input.value);
if (successfullyAdded) {
const collapsbileWrap = createCategoryElement(input.value, node);
avatarCaseDiv.insertBefore(collapsbileWrap, newCollectionFormDiv);
}
}
});
avatarCaseDiv.appendChild(newCollectionFormDiv);
}
}
}
};
function createCategoryElement(collection, node) {
const scope = angular.element(document.getElementById('topbar')).scope();
const collapsibleWrap = document.createElement('div');
const collapsibleButton = document.createElement('button');
const collapsibleContent = document.createElement('div');
const avatarGrid = document.createElement('div');
const removeCategoryButton = document.createElement('button');
collapsibleWrap.setAttribute('class', 'collapsible-wrap');
collapsibleWrap.setAttribute('id', collection);
collapsibleButton.setAttribute('class', 'collapsible-button');
collapsibleContent.setAttribute('class', 'collapsible-content');
removeCategoryButton.setAttribute('class', 'removeCategory-btn');
avatarGrid.setAttribute('class', 'avatar-grid');
collapsibleButton.textContent = collection;
removeCategoryButton.textContent = 'Kategorie löschen';
removeCategoryButton.addEventListener('click', function () {
window.selectedCollection = this.parentElement.parentElement.id;
const requestDeleteCollectionDiv = document.createElement('div');
const cancelRequestBtn = document.createElement('button');
const acceptRequestBtn = document.createElement('button');
requestDeleteCollectionDiv.setAttribute('class', 'request-delete-collection');
requestDeleteCollectionDiv.textContent = `Kategorie "${window.selectedCollection}" wirklich löschen?`;
acceptRequestBtn.textContent = 'löschen';
cancelRequestBtn.textContent = 'abbrechen';
acceptRequestBtn.addEventListener('click', function () {
const deletionSuccessfull = window.deleteCollection(window.selectedCollection);
if (deletionSuccessfull) {
const defaultCategory = document.getElementById('Keine Kategorie');
const selecetedCategory = document.getElementById(window.selectedCollection);
for (const avatar of selecetedCategory.children[1].children[0].children) {
avatar.children[avatar.childElementCount - 1].remove();
createAddToCollectionIcon(avatar, node);
defaultCategory.children[1].children[0].appendChild(avatar);
}
selecetedCategory.remove();
}
this.parentElement.remove();
});
cancelRequestBtn.addEventListener('click', function () {
this.parentElement.remove();
});
requestDeleteCollectionDiv.appendChild(cancelRequestBtn);
requestDeleteCollectionDiv.appendChild(acceptRequestBtn);
node.appendChild(requestDeleteCollectionDiv);
});
collapsibleContent.appendChild(avatarGrid);
if (collection !== 'Keine Kategorie') {
collapsibleContent.appendChild(removeCategoryButton);
}
collapsibleWrap.appendChild(collapsibleButton);
collapsibleWrap.appendChild(collapsibleContent);
const avatars = JSON.parse(localStorage.getItem('avatars'));
for (const avatar in avatars) {
if (avatars[avatar].collection === collection) {
const avatarDiv = document.createElement('div');
const deleteIconDiv = document.createElement('div');
const selectIconDiv = document.createElement('div');
avatarDiv.id = `${avatars[avatar].id}-${avatars[avatar].img}`;
avatarDiv.setAttribute('class', 'avatar-div');
avatarDiv.style.backgroundImage = `url('/img/publicimg/skinthumbnails/${avatars[avatar].imgthumb}')`;
deleteIconDiv.setAttribute('class', 'avatarIcon');
selectIconDiv.setAttribute('class', 'avatarIcon');
deleteIconDiv.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Trash</title><path d="M296 64h-80a7.91 7.91 0 00-8 8v24h96V72a7.91 7.91 0 00-8-8z" fill="none"/><path d="M432 96h-96V72a40 40 0 00-40-40h-80a40 40 0 00-40 40v24H80a16 16 0 000 32h17l19 304.92c1.42 26.85 22 47.08 48 47.08h184c26.13 0 46.3-19.78 48-47l19-305h17a16 16 0 000-32zM192.57 416H192a16 16 0 01-16-15.43l-8-224a16 16 0 1132-1.14l8 224A16 16 0 01192.57 416zM272 400a16 16 0 01-32 0V176a16 16 0 0132 0zm32-304h-96V72a7.91 7.91 0 018-8h80a7.91 7.91 0 018 8zm32 304.57A16 16 0 01320 416h-.58A16 16 0 01304 399.43l8-224a16 16 0 1132 1.14z"/></svg>';
selectIconDiv.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Shirt</title><path d="M256 96c33.08 0 60.71-25.78 64-58 .3-3-3-6-6-6a13 13 0 00-4.74.9c-.2.08-21.1 8.1-53.26 8.1s-53.1-8-53.26-8.1a16.21 16.21 0 00-5.3-.9h-.06a5.69 5.69 0 00-5.38 6c3.35 32.16 31 58 64 58z"/><path d="M485.29 89.9L356 44.64a4 4 0 00-5.27 3.16 96 96 0 01-189.38 0 4 4 0 00-5.35-3.16L26.71 89.9A16 16 0 0016.28 108l16.63 88a16 16 0 0013.92 12.9l48.88 5.52a8 8 0 017.1 8.19l-7.33 240.9a16 16 0 009.1 14.94A17.49 17.49 0 00112 480h288a17.49 17.49 0 007.42-1.55 16 16 0 009.1-14.94l-7.33-240.9a8 8 0 017.1-8.19l48.88-5.52a16 16 0 0013.92-12.9l16.63-88a16 16 0 00-10.43-18.1z"/></svg>';
avatarDiv.appendChild(deleteIconDiv);
avatarDiv.appendChild(selectIconDiv);
selectIconDiv.addEventListener('click', function () {
scope.changeAvatarTexture(this.parentElement.id.split('-')[1]);
});
deleteIconDiv.addEventListener('click', function () {
scope.requestDeleteAvatar({ avatarid: this.parentElement.id.split('-')[0] });
});
if (collection === 'Keine Kategorie') {
createAddToCollectionIcon(avatarDiv, node);
} else {
createRemoveFromCollectionIcon(avatarDiv, node);
}
avatarDiv.addEventListener('mouseover', function () {
for (const child of this.children) {
child.style.display = 'flex';
}
});
avatarDiv.addEventListener('mouseout', function () {
for (const child of this.children) {
child.style.display = 'none';
}
});
avatarGrid.appendChild(avatarDiv);
}
}
collapsibleButton.addEventListener('click', function () {
this.classList.toggle('active');
const content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + 'px';
}
});
return collapsibleWrap;
}
function createAddToCollectionIcon(avatarDiv, node) {
const addToCollectionIcon = document.createElement('div');
addToCollectionIcon.setAttribute('class', 'avatarIcon');
addToCollectionIcon.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Bag Add</title><path d="M454.66 169.4A31.86 31.86 0 00432 160h-64v-16a112 112 0 00-224 0v16H80a32 32 0 00-32 32v216c0 39 33 72 72 72h272a72.22 72.22 0 0050.48-20.55 69.48 69.48 0 0021.52-50.2V192a31.78 31.78 0 00-9.34-22.6zM320 336h-48v48a16 16 0 01-32 0v-48h-48a16 16 0 010-32h48v-48a16 16 0 0132 0v48h48a16 16 0 010 32zm16-176H176v-16a80 80 0 01160 0z"/></svg>';
addToCollectionIcon.addEventListener('click', function () {
const collections = JSON.parse(localStorage.getItem('collections'));
window.selectedAvatar = this.parentElement.id.split('-')[0];
const collectionSelection = document.createElement('div');
const cancelSelectionBtn = document.createElement('button');
cancelSelectionBtn.textContent = 'abbrechen';
collectionSelection.setAttribute('class', 'collection-selection');
for (const collection in collections) {
const collectionSelectable = document.createElement('div');
collectionSelectable.setAttribute('class', 'collection-selectable');
collectionSelectable.textContent = collection;
collectionSelection.appendChild(collectionSelectable);
collectionSelectable.addEventListener('click', function () {
window.addAvatarToCollection(window.selectedAvatar, this.textContent);
const avatarDiv = document.querySelectorAll(`[id^='${window.selectedAvatar}']`)[0];
const newCollectionDiv = document.getElementById(this.textContent).children[1].children[0];
avatarDiv.children[avatarDiv.childElementCount - 1].remove();
createRemoveFromCollectionIcon(avatarDiv, node);
for (const child of avatarDiv.children) {
child.style.display = 'none';
}
newCollectionDiv.appendChild(avatarDiv);
this.parentElement.remove();
});
}
cancelSelectionBtn.addEventListener('click', function () {
this.parentElement.remove();
});
collectionSelection.appendChild(cancelSelectionBtn);
node.appendChild(collectionSelection);
});
avatarDiv.appendChild(addToCollectionIcon);
}
function createRemoveFromCollectionIcon(avatarDiv, node) {
const removeFromCollectionIcon = document.createElement('div');
removeFromCollectionIcon.setAttribute('class', 'avatarIcon');
removeFromCollectionIcon.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Bag Remove</title><path d="M454.66 169.4A31.86 31.86 0 00432 160h-64v-16a112 112 0 00-224 0v16H80a32 32 0 00-32 32v216c0 39 33 72 72 72h272a72.22 72.22 0 0050.48-20.55 69.48 69.48 0 0021.52-50.2V192a31.78 31.78 0 00-9.34-22.6zM320 336H192a16 16 0 010-32h128a16 16 0 010 32zm16-176H176v-16a80 80 0 01160 0z"/></svg>';
removeFromCollectionIcon.addEventListener('click', function () {
const avatarDiv = this.parentElement;
const newCollectionDiv = document.getElementById('Keine Kategorie').children[1].children[0];
avatarDiv.children[avatarDiv.childElementCount - 1].remove();
createAddToCollectionIcon(avatarDiv, node);
for (const child of avatarDiv.children) {
child.style.display = 'none';
}
window.removeAvatarFromCollection(avatarDiv.id.split('-')[0]);
newCollectionDiv.appendChild(avatarDiv);
});
avatarDiv.appendChild(removeFromCollectionIcon);
}
const avatarcaseObserver = new MutationObserver(avatarcaseMutationCallback);
avatarcaseObserver.observe(avatarcaseDiv, avatarcaseObserverConfig);
/************************************
*
*
* Marktplatz Popup Modul
*
*
************************************/
function createMarktplatzPanel() {
// Create Marktplatz Panel box
const panelBox = document.createElement('div');
panelBox.id = 'marktplatzPanel';
panelBox.style.position = 'fixed';
panelBox.style.width = '600px';
panelBox.style.height = '700px';
panelBox.style.backgroundColor = '#1e1e1e';
panelBox.style.color = '#f0f0f0';
panelBox.style.border = '1px solid #333';
panelBox.style.borderRadius = '5px';
panelBox.style.zIndex = '10000';
panelBox.style.overflow = 'auto';
panelBox.style.resize = 'both';
panelBox.style.cursor = 'default';
panelBox.style.userSelect = 'text';
// Center the popup on the screen
panelBox.style.left = '50%';
panelBox.style.top = '50%';
panelBox.style.transform = 'translate(-50%, -50%)';
// Create a title bar for the panel box
const titleBar = document.createElement('div');
titleBar.style.cursor = 'move';
titleBar.style.padding = '5px';
titleBar.style.backgroundColor = '#333';
titleBar.style.color = '#f0f0f0';
titleBar.style.fontWeight = 'bold';
titleBar.innerHTML = 'Marktplatz Panel (Drag Title Bar to Move)';
titleBar.style.display = 'flex';
titleBar.style.justifyContent = 'space-between';
titleBar.style.alignItems = 'center';
// Create a close button
const closeButton = document.createElement('button');
closeButton.innerText = '×';
closeButton.style.background = '#ff4d4d';
closeButton.style.color = '#fff';
closeButton.style.border = 'none';
closeButton.style.fontSize = '16px';
closeButton.style.width = '25px';
closeButton.style.height = '25px';
closeButton.style.borderRadius = '50%';
closeButton.style.cursor = 'pointer';
closeButton.style.textAlign = 'center';
closeButton.style.lineHeight = '25px';
closeButton.style.fontWeight = 'bold';
closeButton.style.marginRight = '5px';
closeButton.addEventListener('click', function (event) {
event.stopPropagation(); // Prevent drag triggering when clicking close
panelBox.remove();
});
// Append close button and title bar
titleBar.appendChild(closeButton);
panelBox.appendChild(titleBar);
// Create a container to load Marktplatz content
const contentContainer = document.createElement('div');
contentContainer.style.width = '100%';
contentContainer.style.height = 'calc(100% - 30px)'; // Adjusting height for the title bar
contentContainer.style.overflow = 'auto';
contentContainer.style.background = '#282828';
contentContainer.style.padding = '5px';
panelBox.appendChild(contentContainer);
// Load the Marktplatz page inside an iframe to ensure full functionality
const iframe = document.createElement('iframe');
iframe.src = 'https://anime.academy/marktplatz';
iframe.style.width = '100%';
iframe.style.height = '100%';
iframe.style.border = 'none';
iframe.style.background = '#1e1e1e';
contentContainer.appendChild(iframe);
// Append the panel box to the document body
document.body.appendChild(panelBox);
// Drag functionality for the title bar only
let isDragging = false;
let offsetX, offsetY;
titleBar.addEventListener('mousedown', function (e) {
isDragging = true;
offsetX = e.clientX - panelBox.getBoundingClientRect().left;
offsetY = e.clientY - panelBox.getBoundingClientRect().top;
});
document.addEventListener('mousemove', function (e) {
if (isDragging) {
panelBox.style.left = `${e.clientX - offsetX}px`;
panelBox.style.top = `${e.clientY - offsetY}px`;
panelBox.style.transform = 'none';
}
});
document.addEventListener('mouseup', function () {
isDragging = false;
});
}
function attachMarktplatzListener() {
document.addEventListener('click', function (event) {
const target = event.target.closest('a[href="/marktplatz"]');
if (target) {
event.preventDefault(); // Prevent default opening in new tab
if (!document.getElementById('marktplatzPanel')) {
createMarktplatzPanel();
}
}
});
}
attachMarktplatzListener();
/************************************
*
*
* Chat Logger Module
*
*
************************************/
const ChatLogger = {
CHAT_LOG_STORAGE_KEY: "aac_chat_logs",
MAX_LOG_SIZE: 5000,
init: function () {
console.log("[Chat Logger] Initializing...");
this.setupSocketHook();
this.createDownloadButton();
},
setupSocketHook: function () {
if (!window.socket) {
console.warn("[Chat Logger] No socket detected. Hooking into system...");
io.Socket.prototype.o_emit = io.Socket.prototype.o_emit || io.Socket.prototype.emit;
io.Socket.prototype.emit = function (eventName, ...args) {
if (!window.socket) {
window.socket = this;
window.dispatchEvent(new Event('globalSocketReady'));
}
return this.o_emit(eventName, ...args);
};
}
let attempt = 0;
let checkInterval = setInterval(() => {
attempt++;
if (window.socket) {
console.log("[Chat Logger] Socket found, starting logger...");
clearInterval(checkInterval);
ChatLogger.listenForChatMessages();
return;
}
console.log(`[Chat Logger] Waiting for socket... (Attempt ${attempt})`);
if (attempt > 20) {
clearInterval(checkInterval);
console.error("[Chat Logger] Failed to detect socket.");
}
}, 1000);
},
listenForChatMessages: function () {
if (!window.socket) {
console.error("[Chat Logger] No socket connection found! Retrying...");
setTimeout(ChatLogger.listenForChatMessages, 1000);
return;
}
console.log("[Chat Logger] Attaching listener for chat messages...");
window.socket.on('updateChatLines', (data) => {
console.log("[Chat Logger] Received chat message event:", data);
if (!data || !data.chatLine) {
console.warn("[Chat Logger] Empty or undefined message received.");
return;
}
const currentRoom = window.location.href.split('=')[1];
ChatLogger.saveChatMessage(currentRoom, data.user, data.chatLine);
});
},
saveChatMessage: function (room, user, message) {
if (!message || message.trim() === "") return;
let chatLogs = JSON.parse(localStorage.getItem(ChatLogger.CHAT_LOG_STORAGE_KEY)) || {};
if (!chatLogs[room]) {
chatLogs[room] = [];
}
chatLogs[room].push({
timestamp: Date.now(),
user: user,
message: message
});
if (chatLogs[room].length > ChatLogger.MAX_LOG_SIZE) {
chatLogs[room].shift();
}
localStorage.setItem(ChatLogger.CHAT_LOG_STORAGE_KEY, JSON.stringify(chatLogs));
console.log(`[Chat Logger] Stored message: ${user}: ${message}`);
},
exportChatLogs: function () {
let chatLogs = JSON.parse(localStorage.getItem(ChatLogger.CHAT_LOG_STORAGE_KEY)) || {};
if (Object.keys(chatLogs).length === 0) {
alert("No chat logs available.");
console.warn("[Chat Logger] No logs found.");
return;
}
let logText = "";
for (let room in chatLogs) {
logText += `Room: ${room}\n====================\n`;
logText += chatLogs[room].map(log =>
`[${new Date(log.timestamp).toLocaleString()}] ${log.user}: ${log.message}`
).join("\n") + "\n\n";
}
let now = new Date();
let formattedTime = now.toISOString().replace(/T/, '_').replace(/:/g, '-').split('.')[0];
let fileName = `chatlog_${formattedTime}.txt`;
let blob = new Blob([logText], { type: "text/plain" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
console.log(`[Chat Logger] Chat logs downloaded as: ${fileName}`);
},
createDownloadButton: function () {
setTimeout(() => {
let existingButton = document.getElementById("downloadChatLogsBtn");
if (existingButton) return;
let chatControls = document.querySelector(".controller");
if (!chatControls) {
console.warn("[Chat Logger] Could not find .controller div!");
return;
}
let button = document.createElement("span");
button.id = "downloadChatLogsBtn";
button.innerText = "💾 Logs";
button.style.padding = "5px 10px";
button.style.fontSize = "12px";
button.style.background = "#4CAF50";
button.style.color = "#fff";
button.style.borderRadius = "4px";
button.style.cursor = "pointer";
button.style.display = "inline-block";
button.style.marginLeft = "15px";
button.style.opacity = "0.85";
button.addEventListener("mouseenter", () => {
button.style.opacity = "1";
});
button.addEventListener("mouseleave", () => {
button.style.opacity = "0.85";
});
button.addEventListener("click", ChatLogger.exportChatLogs);
chatControls.appendChild(button);
console.log("[Chat Logger] Button added inside chat controls.");
}, 2000);
}
};
/************************************************************************************************************************************************************************************
*
*
************************************************************************************************************************************************************************************
************************************************************************************************************************************************************************************
*
*
*
* Mainpage Stuff
*
*
*
************************************************************************************************************************************************************************************
************************************************************************************************************************************************************************************
*
*
************************************************************************************************************************************************************************************/
/************************************
*
*
* Show All Online Users Module
*
*
************************************/
function fixOnlineUsers() {
console.log("🔍 Looking for .onlineUsers...");
const onlineUsersContainer = document.querySelector(".onlineUsers");
if (!onlineUsersContainer) {
console.warn("⚠️ .onlineUsers not found! Retrying in 1 second...");
setTimeout(fixOnlineUsers, 1000);
return;
}
console.log("✅ Found .onlineUsers! Removing limit...");
// Get AngularJS scope
const scope = angular.element(onlineUsersContainer).scope();
if (!scope || !scope.usersOnline) {
console.warn("⚠️ Angular scope not found! Retrying...");
setTimeout(fixOnlineUsers, 1000);
return;
}
// Remove the limit and force AngularJS to update
scope.$apply(function () {
scope.usersOnlineLimit = scope.usersOnline.length; // Set limit to total users
});
console.log(`✅ Showing all online users (${scope.usersOnline.length} total)`);
}
// Wait until AngularJS is ready
document.addEventListener("DOMContentLoaded", fixOnlineUsers);
AACApp.init();
})();