// ==UserScript==
// @name Messenger Hide Chat List
// @namespace imxitiz's-Script
// @version 2.1
// @grant none
// @license GNU GPLv3
// @author imxitiz
// @match https://www.messenger.com/*
// @description Hide or show the Messenger chat list based on user interaction. Includes features for resizing and locking Chat list visibility.
// ==/UserScript==
(function () {
"use strict";
let hasInitialized = false;
const hideThreshold = 20; // Threshold in pixels to determine if sidebar should be hidden
let eventParent;
let isResizing = false;
let userDefinedFlexBasis =
parseFloat(getLocalStorageItem("userDefinedFlexBasis")) || 30;
let userResizedOnce =
getSessionStorageItem("userResizedOnce") === "true" || false;
let active = parseInt(getSessionStorageItem("active")) || 0;
// active states:
// 0 - Normal behavior: sidebar hidden on hover
// 1 - Always visible
// 2 - Always hidden(lock)
// 3 - Always hidden(hiddent but not locked)
let lockPosition = JSON.parse(getSessionStorageItem("lockPosition")) || {
x: 0,
y: 0,
};
const clickThreshold = 80; // Threshold in pixels for precise unlocking
let wrongLockedPlaceAttempt = 0;
// Helper functions for storage
function setSessionStorageItem(key, value) {
sessionStorage.setItem(key, value);
}
function getSessionStorageItem(key) {
return sessionStorage.getItem(key);
}
function setLocalStorageItem(key, value) {
localStorage.setItem(key, value);
}
function getLocalStorageItem(key) {
return localStorage.getItem(key);
}
// Create and append the resize handle to the sidebar
function createResizeHandle() {
try {
const sidebar = document.querySelector(
'div[aria-label="Thread list"]'
);
if (!sidebar) {
throw new Error("Sidebar element not found");
}
// Create resize handle only if it doesn't already exist
if (!document.getElementById("resize-handle")) {
const resizeHandle = document.createElement("div");
resizeHandle.id = "resize-handle";
resizeHandle.style.width = "10px";
resizeHandle.style.height = "100%";
resizeHandle.style.position = "absolute";
resizeHandle.style.top = "0";
resizeHandle.style.right = "0";
resizeHandle.style.cursor = "ew-resize";
resizeHandle.style.backgroundColor = userResizedOnce ? "transparent" : "red";
resizeHandle.style.zIndex = "1000";
sidebar.appendChild(resizeHandle);
// Add event listeners for resizing
resizeHandle.addEventListener("mousedown", function () {
isResizing = true;
document.addEventListener("mousemove", resizeChatList);
document.addEventListener("mouseup", stopResize);
});
}
} catch (error) {
console.error("Error creating resize handle: ", error);
setTimeout(createResizeHandle, 1000); // Retry after 1 second if there's an error
}
}
// Update sidebar visibility based on user interactions and settings
function updateSidebarVisibility() {
const sidebar = document.querySelector('div[aria-label="Thread list"]');
const inboxSwitcher = document.querySelector(
'div[aria-label="Inbox switcher"]'
);
if (sidebar && inboxSwitcher) {
if (!hasInitialized) {
sidebar.style.maxWidth = "0"; // Initial max-width
sidebar.style.minWidth = "0"; // Ensure consistent width
sidebar.style.margin = "0";
hasInitialized = true;
createResizeHandle(); // Create resize handle on initial setup
}
const isMouseOverSidebar =
isMouseOver(sidebar) || isMouseOver(inboxSwitcher);
if (active === 1) {
// Always show the sidebar
sidebar.style.maxWidth = `${userDefinedFlexBasis}%`;
sidebar.style.minWidth = `${userDefinedFlexBasis}%`;
sidebar.style.margin = "0";
} else if (active === 2 || active === 3) {
// Always hide the sidebar
sidebar.style.maxWidth = "0";
sidebar.style.minWidth = "0";
} else {
// Normal behavior
if (
isMouseOverSidebar ||
eventParent.clientX <= hideThreshold ||
isResizing
) {
// Show sidebar
sidebar.style.maxWidth = `${userDefinedFlexBasis}%`;
sidebar.style.minWidth = `${userDefinedFlexBasis}%`;
sidebar.style.margin = "0";
} else {
// Hide sidebar
sidebar.style.maxWidth = "0";
sidebar.style.minWidth = "0";
}
}
}
}
// Resize the chat list while the mouse is moving
function resizeChatList(e) {
if (isResizing) {
const sidebar = document.querySelector(
'div[aria-label="Thread list"]'
);
const containerWidth = sidebar.parentElement.clientWidth;
let newFlexBasis =
((e.clientX - sidebar.getBoundingClientRect().left) /
containerWidth) *
100;
if (newFlexBasis >= 10 && newFlexBasis <= 100) {
userDefinedFlexBasis = newFlexBasis;
sidebar.style.maxWidth = `${userDefinedFlexBasis}%`;
sidebar.style.minWidth = `${userDefinedFlexBasis}%`;
}
if (!userResizedOnce) {
userResizedOnce = true;
setSessionStorageItem("userResizedOnce", "true");
let resizeHandle = document.getElementById("resize-handle");
resizeHandle.style.backgroundColor = "transparent";
}
setLocalStorageItem("userDefinedFlexBasis", userDefinedFlexBasis);
}
}
// Stop resizing when the mouse button is released
function stopResize() {
isResizing = false;
document.removeEventListener("mousemove", resizeChatList);
document.removeEventListener("mouseup", stopResize);
}
// Check if mouse is over the element or its children
function isMouseOver(element) {
return element.contains(eventParent.target);
}
// Calculate distance between two points
function calculateDistance(pos1, pos2) {
return Math.sqrt(
Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2)
);
}
// Check if mouse is near the locked position
function isNearLockPosition(x, y, lockPosition) {
const distance = calculateDistance(lockPosition, { x, y });
return distance <= clickThreshold;
}
// Helper function to show notifications
function showNotification(message, time = 5000) {
// if previous notification found, remove it
const previousNotification =
document.querySelector("div[role='alert']");
if (previousNotification) {
document.body.removeChild(previousNotification);
}
const notification = document.createElement("div");
notification.setAttribute("role", "alert");
notification.textContent = message;
notification.style.position = "fixed";
notification.style.top = "50%";
notification.style.left = "50%";
notification.style.transform = "translate(-50%, -50%)";
notification.style.padding = "10px";
notification.style.backgroundColor = "#333";
notification.style.color = "#fff";
notification.style.fontFamily = "Arial, sans-serif";
notification.style.fontSize = "20px";
notification.style.borderRadius = "5px";
notification.style.zIndex = "100000";
notification.style.opacity = "0";
notification.style.transition = "opacity 0.5s";
document.body.appendChild(notification);
// Fade in the notification
setTimeout(() => {
notification.style.opacity = "1";
}, 100);
// Fade out and remove the notification after 3 seconds
setTimeout(() => {
notification.style.opacity = "0";
setTimeout(() => {
if (document.body.contains(notification))
document.body.removeChild(notification);
}, 500);
}, time);
}
// Triple click event listener
function handleClick(event, clickcount = 0) {
if (event.detail === 3 || clickcount === 3) {
const inboxSwitcher = document.querySelector(
'div[aria-label="Inbox switcher"]'
);
if (active === 0) {
if (isMouseOver(inboxSwitcher)) {
active = 1;
showNotification("Now chat list is always visible.", 3000);
} else {
// if triple right click then lock hidden
if (event.button === 2) {
active = 2;
lockPosition = { x: event.clientX, y: event.clientY };
setSessionStorageItem(
"lockPosition",
JSON.stringify(lockPosition)
);
showNotification(
"You have to triple click exactly here to unlock the chat list."
);
} else {
// else or if triple left click then unlocked hidden
active = 3;
showNotification(
"Now chat list is always hidden, but not locked."
);
}
}
} else if (active === 1) {
if (isMouseOver(inboxSwitcher)) {
active = 0;
showNotification("Now chat list is shown on hover.", 3000);
} else {
if (event.button === 2) {
active = 2;
lockPosition = { x: event.clientX, y: event.clientY };
setSessionStorageItem(
"lockPosition",
JSON.stringify(lockPosition)
);
showNotification(
"You have to triple click exactly here to unlock the chat list."
);
} else {
active = 3;
showNotification(
"Now chat list is always hidden, but not locked."
);
}
}
} else if (active === 2) {
if (
isNearLockPosition(
event.clientX,
event.clientY,
lockPosition
)
) {
active = 0;
wrongLockedPlaceAttempt = 0;
showNotification("Chat list unlocked successfully.");
} else {
wrongLockedPlaceAttempt++;
if (wrongLockedPlaceAttempt >= 10) {
showNotification(
"You can always logout and login again to reset the lock position."
);
} else {
if (wrongLockedPlaceAttempt >= 5) {
showNotification(
"Please logout and login again to reset the lock position."
);
}
}
const clickPosition = {
x: event.clientX,
y: event.clientY,
};
const distance = calculateDistance(
lockPosition,
clickPosition
);
if (distance <= clickThreshold * 1.2) {
showNotification(
"You are near the locked position, try again!!!"
);
}
}
} else {
if (isMouseOver(inboxSwitcher)) {
active = 1;
showNotification("Now chat list is always visible.", 3000);
} else {
if (event.button === 2) {
active = 2;
lockPosition = { x: event.clientX, y: event.clientY };
setSessionStorageItem(
"lockPosition",
JSON.stringify(lockPosition)
);
showNotification(
"You have to triple click exactly here to unlock the chat list."
);
} else {
active = 0;
showNotification(
"Now chat list is shown on hover.",
3000
);
}
}
}
setSessionStorageItem("active", active);
}
}
// Initialize the script
function init() {
document.addEventListener("mousemove", function (event) {
eventParent = event;
updateSidebarVisibility();
});
document.addEventListener("click", handleClick);
let lastRightClickTime = 0;
let rightClickCount = 0;
document.addEventListener("contextmenu", function (event) {
const avoidElements = [
"IMG",
"VIDEO",
"AUDIO",
"SOURCE",
"A",
"BUTTON",
"INPUT",
"SELECT",
"TEXTAREA",
"IFRAME",
"EMBED",
"OBJECT",
"CANVAS",
"SVG",
];
if (
avoidElements.includes(event.target.tagName) ||
event.target.isContentEditable
) {
return;
}
event.preventDefault();
const currentTime = new Date().getTime();
if (currentTime - lastRightClickTime < 500) {
rightClickCount++;
} else {
rightClickCount = 1;
}
lastRightClickTime = currentTime;
handleClick(event, rightClickCount);
});
}
init();
})();