LMS360 - Chặn Thời Gian

Giao diện hiện đại + Chặn bộ đếm + Kéo thả

// ==UserScript==
// @name         LMS360 - Chặn Thời Gian
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Giao diện hiện đại + Chặn bộ đếm + Kéo thả
// @author       Vo Quan
// @match        *://lms360.edu.vn/*
// @license MIT
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

let isEnabled = false; // Luôn mặc định bật khi load trang

    function blockTimers() {
        if (!isEnabled) return;

        console.log("[Script] Đã chặn bộ đếm thời gian!");

        window.setInterval = () => 0;
        window.setTimeout = () => 0;

        for (let i = 1; i < 99999; i++) {
            clearInterval(i);
            clearTimeout(i);
        }

        document.addEventListener("visibilitychange", e => e.stopImmediatePropagation(), true);
        window.onbeforeunload = null;
        window.onunload = null;

        window.addEventListener("beforeunload", e => e.stopImmediatePropagation(), true);
        performance.now = () => 0;
    }

    // ============ Timer ============

    let timerInterval;
    let seconds = 0;

    function startTimer() {
        const display = document.getElementById("timer-display");
        clearInterval(timerInterval);
        seconds = 0;
        display.textContent = "00:00:00";

        timerInterval = setInterval(() => {
            seconds++;
            let hrs = String(Math.floor(seconds / 3600)).padStart(2, '0');
            let mins = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
            let secs = String(seconds % 60).padStart(2, '0');
            display.textContent = `${hrs}:${mins}:${secs}`;
        }, 1000);
    }

    // ============ UI =============

    const uiBox = document.createElement("div");
    uiBox.id = "lms-ui-pro";
    uiBox.innerHTML = `
        <div class="lms-box">
            <div class="header" id="drag-handle">
                <div class="logo">
                    <svg width="20" height="20" fill="#00FFC8" viewBox="0 0 24 24"><path d="M5 3a2 2 0 0 0-2 2v2h18V5a2 2 0 0 0-2-2H5zM3 9v10a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9H3zm8 3h2v5h-2v-5z"/></svg>
                    <span>Chặn thời gian</span>
                </div>
                <label class="switch">
                    <input type="checkbox" id="toggle-script" ${isEnabled ? "checked" : ""}>
                    <span class="slider"></span>
                </label>
            </div>
            <div class="status">
                <strong>Trạng thái:</strong> <span id="status">${isEnabled ? "Đang bật" : "Đã tắt"}</span>
            </div>
            <div class="timer">
                <svg width="16" height="16" fill="#00FFC8" viewBox="0 0 24 24"><path d="M12 8v5l4.28 2.54.72-1.21-3.5-2.08V8z"/><path d="M12 1C5.93 1 1 5.93 1 12s4.93 11 11 11 11-4.93 11-11S18.07 1 12 1zm0 20c-4.97 0-9-4.03-9-9s4.03-9 9-9 9 4.03 9 9-4.03 9-9 9z"/></svg>
                <span id="timer-display">00:00:00</span>
            </div>
        </div>

        <style>
#lms-ui-pro {
    position: fixed;
    top: 30px;
    left: 30px;
    z-index: 99999;
    animation: fadeSlideIn 0.5s ease-out;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    will-change: transform;
    max-width: 100vw;
    box-sizing: border-box;
}

.lms-box {
    background: #1f1f1f;
    border-radius: 14px;
    padding: 16px;
    box-shadow: 0 12px 25px rgba(0, 255, 200, 0.2);
    font-family: 'Segoe UI', sans-serif;
    color: #eee;
    width: 280px;
    transition: transform 0.4s ease, box-shadow 0.4s ease;
    user-select: none;
    box-sizing: border-box;
}

.lms-box:hover {
    transform: translateY(-3px);
    box-shadow: 0 14px 28px rgba(0, 255, 200, 0.3);
}

.lms-box.pressed {
    transform: scale(0.80);
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.logo {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: bold;
    color: #00FFC8;
    font-size: 16px;
}

.status,
.timer {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    font-size: 15px;
}

#timer-display {
    font-weight: bold;
    color: #00FFC8;
    font-size: 17px;
}

.switch {
    position: relative;
    display: inline-block;
    width: 52px;
    height: 28px;
}

.switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #555;
    transition: 0.4s;
    border-radius: 34px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
}

.slider:before {
    position: absolute;
    content: "";
    height: 22px;
    width: 22px;
    left: 3px;
    bottom: 3px;
    background-color: white;
    transition: 0.4s;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

input:checked + .slider {
    background-color: #00FFC8;
    box-shadow: 0 0 8px rgba(0, 255, 200, 0.6);
}

input:checked + .slider:before {
    transform: translateX(24px);
    background-color: #fff;
}

.switch:hover .slider {
    background-color: #00e6b2;
    box-shadow: 0 0 5px rgba(0, 255, 200, 0.22);
    transition: 0.3s ease;
}

@keyframes fadeSlideIn {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}


/* 📱 Responsive cho mobile portrait */
@media (max-width: 480px) {
    #lms-ui-pro {
        top: 10px !important;
        left: 10px !important;
        max-width: 90vw;
    }

    .lms-box {
        width: 260px !important;
        font-size: 13px;
        padding: 12px;
    }

    #timer-display {
        font-size: 15px;
    }

    .switch {
        transform: scale(0.85);
    }

    .logo svg {
        width: 16px;
        height: 16px;
    }
}

        </style>
    `;

    document.body.appendChild(uiBox);

    const timerDiv = document.querySelector("#lms-ui-pro .timer");
    if (timerDiv) {
        timerDiv.style.opacity = "0";
        timerDiv.style.transition = "opacity 0.8s ease, transform 0.8s ease";
        timerDiv.style.transform = "translateY(20px)";
        requestAnimationFrame(() => {
            timerDiv.style.opacity = "1";
            timerDiv.style.transform = "translateY(0)";
        });
    }

    if (isEnabled) blockTimers();
    startTimer();

document.getElementById("toggle-script").addEventListener("change", function () {
    isEnabled = this.checked;
    document.getElementById("status").innerText = isEnabled ? "Đang bật" : "Đã tắt";
    if (isEnabled) blockTimers(); else location.reload();
});


// ============ Drag & Interaction (PC + Mobile + mượt hơn) ============
const lmsBox = document.querySelector("#lms-ui-pro .lms-box");
const dragTarget = document.querySelector("#lms-ui-pro");
const dragHandle = document.querySelector("#lms-ui-pro"); // Toàn bộ khung kéo được

let isMouseDown = false;
let dragging = false;
let offsetX = 0, offsetY = 0;
let touchMoved = false;

// Tạo lớp chặn iframe
const iframeBlocker = document.createElement("div");
iframeBlocker.style.position = "fixed";
iframeBlocker.style.top = "0";
iframeBlocker.style.left = "0";
iframeBlocker.style.width = "100vw";
iframeBlocker.style.height = "100vh";
iframeBlocker.style.zIndex = "99998";
iframeBlocker.style.display = "none";
iframeBlocker.style.cursor = "grabbing";
document.body.appendChild(iframeBlocker);

function handlePressStart(e) {
    if (e.target.closest('.switch')) return;
    isMouseDown = true;
    lmsBox.classList.add("pressed");
}

function handlePressEnd() {
    if (isMouseDown) {
        lmsBox.classList.remove("pressed");
        isMouseDown = false;
    }
}

function startDrag(x, y) {
    dragging = true;
    iframeBlocker.style.display = "block"; // Chặn iframe
    const rect = dragTarget.getBoundingClientRect();
    offsetX = x - rect.left;
    offsetY = y - rect.top;
    document.body.style.userSelect = "none";
}

function duringDrag(x, y) {
    if (!dragging) return;
    dragTarget.style.left = `${x - offsetX}px`;
    dragTarget.style.top = `${y - offsetY}px`;
}

function stopDrag() {
    dragging = false;
    iframeBlocker.style.display = "none"; // Gỡ chặn iframe
    document.body.style.userSelect = "";
}

// PC events
dragHandle.addEventListener("mousedown", (e) => {
    if (e.target.closest('.switch')) return;
    handlePressStart(e);
    startDrag(e.clientX, e.clientY);
});

window.addEventListener("mouseup", () => {
    handlePressEnd();
    stopDrag();
});

window.addEventListener("mousemove", (e) => {
    if (dragging) duringDrag(e.clientX, e.clientY);
});

// Mobile touch events
dragHandle.addEventListener("touchstart", (e) => {
    if (e.target.closest('.switch')) return;
    handlePressStart(e);
    const touch = e.touches[0];
    startDrag(touch.clientX, touch.clientY);
    touchMoved = false;
}, { passive: false });

dragHandle.addEventListener("touchmove", (e) => {
    const touch = e.touches[0];
    duringDrag(touch.clientX, touch.clientY);
    touchMoved = true;
    e.preventDefault();
}, { passive: false });

dragHandle.addEventListener("touchend", () => {
    stopDrag();
    if (touchMoved) handlePressEnd();
    else setTimeout(() => handlePressEnd(), 100);
}, { passive: false });

// Ngăn chạm nền
dragTarget.addEventListener("touchstart", (e) => {
    if (!e.target.closest('.switch')) e.stopPropagation();
}, { passive: false });

dragTarget.addEventListener("touchend", (e) => {
    e.stopPropagation();
}, { passive: false });

dragTarget.addEventListener("touchmove", (e) => {
    e.preventDefault();
    e.stopPropagation();
}, { passive: false });

})();