Greasy Fork

Greasy Fork is available in English.

Popmundo Scheduler ( In Development )

Adiciona um calendário com eventos salvos usando GM_setValue e GM_getValue

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Popmundo Scheduler ( In Development )
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Adiciona um calendário com eventos salvos usando GM_setValue e GM_getValue
// @author       Você
// @match        *://*.popmundo.com/World/Popmundo.aspx/Character*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_listValues
// @license      MIT
// @require      https://code.jquery.com/jquery-3.7.1.min.js
// @require      https://cdn.jsdelivr.net/npm/sweetalert2@11
// ==/UserScript==

(function() {
    'use strict';
 // Função para verificar eventos do dia atual e adicionar notificações
    function checkTodayEvents() {
        let today = new Date();
        let todayKey = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`; // Formata a chave da data

        let events = getEventsForDay(todayKey);

        if (events.length > 0) {
            events.forEach(event => {
                let notification = `<div class="notification-real notification-normal">Atenção! Evento de hoje : ${event.description}</div>`;
                $('#notifications').append(notification); // Adiciona a notificação à div de ID "notifications"
            });
        }
    }
  // Função para gerar um UID único
function generateUID() {
    return Math.random().toString(36).substr(2, 9); // Gera um UID aleatório com 9 caracteres
}

  checkTodayEvents();
    // Salvar ou recuperar eventos do localStorage (via GM_setValue e GM_getValue)
    function getEventsForDay(dateKey) {
        let events = GM_getValue(dateKey, []);
        return Array.isArray(events) ? events : [];  // Garante que 'events' seja sempre um array
    }

    function saveEventForDay(dateKey, eventDescription, uid) {
        let events = getEventsForDay(dateKey);
        if (events.length < 4) {
            events.push({ description: eventDescription, uid: uid });
            GM_setValue(dateKey, events);
        }
    }

    function deleteEventForDay(dateKey, eventIndex) {
        let events = getEventsForDay(dateKey);
        events.splice(eventIndex, 1);
        GM_setValue(dateKey, events);
    }

    function deleteSeries(uid) {
        let allKeys = GM_listValues();
        allKeys.forEach(key => {
            let events = getEventsForDay(key);
            if (Array.isArray(events)) {
                events = events.filter(event => event.uid !== uid); // Filtra apenas eventos com UIDs diferentes
                GM_setValue(key, events);
            }
        });
    }

    // Função para gerar o HTML do calendário com divs e grid
    function generateCalendar(year, month) {
        let daysInMonth = new Date(year, month + 1, 0).getDate();
        let firstDay = new Date(year, month, 1).getDay();
        let $calendar = $('<div class="calendar-grid"></div>');

        // Adicionar os dias da semana
        let daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
        daysOfWeek.forEach(day => {
            $calendar.append(`<div class="calendar-header">${day}</div>`);
        });

        // Adicionar dias em branco até o primeiro dia da semana
        for (let i = 0; i < firstDay; i++) {
            $calendar.append('<div class="calendar-day empty"></div>');
        }

        // Adicionar os dias do mês
        for (let day = 1; day <= daysInMonth; day++) {
            let dateKey = `${year}-${month + 1}-${day}`;
            let events = getEventsForDay(dateKey);
            let eventsHtml = events.map((e, index) => `
                <div class="event-tag">
                    ${e.description}
                    <button class="delete-event" data-date="${dateKey}" data-index="${index}" data-uid="${e.uid}" title="Remover evento">🗑️</button>
                </div>`).join('');
            let $dayDiv = $(`<div class="calendar-day" data-date="${dateKey}">${day}<div class="events">${eventsHtml}</div></div>`);

            $calendar.append($dayDiv);
        }

        return $calendar.prop('outerHTML');
    }

    // Função para abrir o popup para adicionar evento
    function openEventPopup(dateKey, $dayDiv) {
        Swal.fire({
            title: 'Adicionar Evento',
            html: `
                <input type="text" id="eventDescription" class="swal2-input" placeholder="Descrição do evento">
                <label>Recorrente?</label>
                <input type="checkbox" id="isRecurring" class="swal2-checkbox">
                <div id="recurringOptions" style="display:none;">
                    <label>A cada quantos dias?</label>
                    <input type="number" id="recurringInterval" class="swal2-input" min="1">
                    <label>Data de término</label>
                    <input type="date" id="endDate" class="swal2-input">
                </div>
            `,
            showCancelButton: true,
            confirmButtonText: 'Agendar',
            cancelButtonText: 'Cancelar',
            preConfirm: () => {
                let eventDescription = $('#eventDescription').val();
                let isRecurring = $('#isRecurring').is(':checked');
                let recurringInterval = $('#recurringInterval').val();
                let endDate = $('#endDate').val();
                if (eventDescription) {
                    return { eventDescription, isRecurring, recurringInterval, endDate };
                } else {
                    Swal.showValidationMessage('Por favor, insira uma descrição para o evento.');
                    return false;
                }
            }
        }).then(result => {
            if (result.isConfirmed) {
                let { eventDescription, isRecurring, recurringInterval, endDate } = result.value;
                let uid = generateUID();

                if (isRecurring && recurringInterval > 0 && endDate) {
                    scheduleRecurringEvents(dateKey, eventDescription, recurringInterval, endDate, uid);
                } else {
                    saveEventForDay(dateKey, eventDescription, uid);
                }

                updateDayWithEvent(dateKey, $dayDiv); // Atualizar o dia com o evento
            }
        });

        $('#isRecurring').on('change', function() {
            if ($(this).is(':checked')) {
                $('#recurringOptions').show();
            } else {
                $('#recurringOptions').hide();
            }
        });
    }

    // Função para agendar eventos recorrentes até a data de término
    function scheduleRecurringEvents(startDateKey, eventDescription, interval, endDate, uid) {
        let [year, month, day] = startDateKey.split('-').map(Number);
        let currentDate = new Date(year, month - 1, day);
        let endRecurringDate = new Date(endDate);

        while (currentDate <= endRecurringDate) {
            let dateKey = `${currentDate.getFullYear()}-${currentDate.getMonth() + 1}-${currentDate.getDate()}`;
            saveEventForDay(dateKey, eventDescription, uid);

            // Adicionar o intervalo de dias
            currentDate.setDate(currentDate.getDate() + parseInt(interval));
        }
    }

    // Função para atualizar o dia com novos eventos
    function updateDayWithEvent(dateKey, $dayDiv) {
        let events = getEventsForDay(dateKey);
        let eventsHtml = events.map((e, index) => `
            <div class="event-tag">
                ${e.description}
                <button class="delete-event" data-date="${dateKey}" data-index="${index}" data-uid="${e.uid}" title="Remover evento">🗑️</button>
            </div>`).join('');
        $dayDiv.find('.events').html(eventsHtml); // Atualizar a lista de eventos no dia
        attachDeleteEventHandlers(); // Reanexar os eventos de clique da lixeira
    }

    // Função para remover eventos com confirmação
    function attachDeleteEventHandlers() {
        $('.delete-event').on('click', function() {
            let dateKey = $(this).data('date');
            let eventIndex = $(this).data('index');
            let uid = $(this).data('uid');

            Swal.fire({
                title: 'Remover Evento?',
                text: "Você quer remover apenas este evento ou a série inteira?",
                icon: 'warning',
                showCancelButton: true,
                showDenyButton: true,
                confirmButtonText: 'Remover único',
                denyButtonText: 'Remover série inteira',
                cancelButtonText: 'Cancelar'
            }).then((result) => {
                if (result.isConfirmed) {
                    deleteEventForDay(dateKey, eventIndex);
                    updateDayWithEvent(dateKey, $(`.calendar-day[data-date="${dateKey}"]`)); // Atualizar o dia após remoção
                } else if (result.isDenied) {
                    deleteSeries(uid); // Remover toda a série de eventos
                    showCalendar(); // Recarregar o calendário
                }
            });
        });
    }

    // Função para abrir o SweetAlert com o calendário
    function showCalendar() {
        let date = new Date();
        let year = date.getFullYear();
        let month = date.getMonth();

        function updateCalendar(newYear, newMonth) {
            $('#calendarTitle').text(new Date(newYear, newMonth).toLocaleString('default', { month: 'long', year: 'numeric' }));
            $('#calendarContainer').html(generateCalendar(newYear, newMonth));
            attachEventHandlers(newYear, newMonth); // Reanexar os eventos de clique após renderizar
            attachDeleteEventHandlers(); // Reanexar os eventos de deletar
        }

        Swal.fire({
            title: 'Scheduler',
            html: `
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <button id="prevMonth">&lt;</button>
                    <span id="calendarTitle">${date.toLocaleString('default', { month: 'long' })} ${year}</span>
                    <button id="nextMonth">&gt;</button>
                </div>
                <div id="calendarContainer">${generateCalendar(year, month)}</div>
            `,
            heightAuto: true,
            customClass: {
                popup: 'custom-height-popup'
            },
            showConfirmButton: false,
            didOpen: function() {
                attachEventHandlers(year, month); // Inicializa os eventos ao abrir o calendário
                attachDeleteEventHandlers(); // Inicializar os eventos de deletar

                // Navegação entre meses
                $('#prevMonth').on('click', function() {
                    month = (month === 0) ? 11 : month - 1;
                    year = (month === 11) ? year - 1 : year;
                    updateCalendar(year, month);
                });

                $('#nextMonth').on('click', function() {
                    month = (month === 11) ? 0 : month + 1;
                    year = (month === 0) ? year + 1 : year;
                    updateCalendar(year, month);
                });
            }
        });
    }

    // Função para reanexar os eventos de clique após o calendário ser renderizado
    function attachEventHandlers(year, month) {
        $('.calendar-day').on('dblclick', function() {
            let dateKey = $(this).data('date');
            openEventPopup(dateKey, $(this));
        });
    }

    // Adicionar o botão "Scheduler" ao menu
    let careerMenu = $('div.menu ul').eq(1);
    if (careerMenu.length) {
        let newMenuItem = $('<li><a href="#">Scheduler</a></li>');
        careerMenu.prepend(newMenuItem);

        newMenuItem.on('click', function(e) {
            e.preventDefault();
            showCalendar();
        });
    }

    // Estilos para o calendário e a janela SweetAlert
    let calendarStyle = `
        <style>
            .calendar-grid {
                display: grid;
                grid-template-columns: repeat(7, 1fr);
                gap: 5px;
                margin-top: 10px;
            }
            .calendar-header, .calendar-day {
                padding: 15px;
                text-align: center;
                border: 1px solid #ddd;
                min-height: 60px; /* Aumenta o tamanho das células para caberem 4 eventos */
                position: relative;
            }
            .calendar-header {
                background-color: #f2f2f2;
                font-weight: bold;
            }
            .calendar-day {
                background-color: #fff;
                cursor: pointer;
            }
            .calendar-day:hover {
                background-color: #007bff;
                color: white;
            }
            .calendar-day.empty {
                background-color: transparent;
                border: none;
            }
            .events {
                display: flex;
                flex-direction: column;
                gap: 3px;
                margin-top: 5px;
            }
            .event-tag {
                background-color: #28a745;
                color: white;
                padding: 3px;
                border-radius: 3px;
                font-size: 12px;
                text-align: center;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .delete-event {
                background: none;
                border: none;
                color: white;
                cursor: pointer;
                margin-left: 10px;
            }
            #prevMonth, #nextMonth {
                background-color: #007bff;
                color: white;
                border: none;
                padding: 5px 10px;
                cursor: pointer;
            }
            #prevMonth:hover, #nextMonth:hover {
                background-color: #0056b3;
            }
            .custom-height-popup {
                height: 800px;
                width:850px;
            }
        </style>
    `;
    $('head').append(calendarStyle); // Injetar o CSS no documento
})();