Waze Manage Bookmarks with Backup (API Version)

Displays a UI for managing bookmarks in the Waze editor using the Userscript API, with export/import features and paste buttons.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Waze Manage Bookmarks with Backup (API Version)
// @namespace    https://greatest.deepsurf.us/ja/users/735907-cauliflower-carrot
// @version      2.6
// @description  Displays a UI for managing bookmarks in the Waze editor using the Userscript API, with export/import features and paste buttons.
// @author       aoi
// @match        https://www.waze.com/*/editor*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const SCRIPT_ID = 'waze-bookmarks-manager';
    const defaultFontSize = '16px';
    let allowedUrls = JSON.parse(localStorage.getItem('allowedUrls')) || [];

    // Wait for WME to be fully ready
    function waitForWmeReady() {
        if (W?.userscripts?.state.isReady) {
            initializeScript();
        } else {
            document.addEventListener('wme-ready', initializeScript, { once: true });
        }
    }

    async function initializeScript() {
        // Register sidebar tab
        const { tabLabel, tabPane } = W.userscripts.registerSidebarTab(SCRIPT_ID);

        // Set tab label
        tabLabel.innerText = 'BM';
        tabLabel.title = 'Bookmark Manager';

        // Create tab content with paste buttons
        tabPane.innerHTML = `
            <div style="padding: 10px;">
                <h3 style="margin: 0 0 10px 0;">Bookmark Management</h3>
                <div style="display: flex; align-items: center; margin-bottom: 5px;">
                    <input type="text" id="urlInput" placeholder="Enter URL" style="flex: 1; padding: 5px; box-sizing: border-box;">
                    <button id="pasteUrlButton" style="margin-left: 5px; padding: 5px 10px; background-color: #9C27B0; color: white; border: none; border-radius: 3px;" title="Paste from clipboard">Paste</button>
                </div>
                <div style="display: flex; align-items: center; margin-bottom: 5px;">
                    <input type="text" id="nameInput" placeholder="Enter Bookmark Name" style="flex: 1; padding: 5px; box-sizing: border-box;">
                    <button id="pasteNameButton" style="margin-left: 5px; padding: 5px 10px; background-color: #9C27B0; color: white; border: none; border-radius: 3px;" title="Paste from clipboard">Paste</button>
                </div>
                <button id="addUrlButton" style="width: 100%; margin-top: 5px; padding: 5px; background-color: #4CAF50; color: white; border: none; border-radius: 5px;">Add Bookmark</button>
                <ul id="urlList" style="list-style: none; padding: 0; margin: 10px 0 0 0; max-height: 200px; overflow-y: auto;"></ul>
                <button id="clearCacheButton" style="width: 100%; margin-top: 15px; padding: 5px; background-color: #2196F3; color: white; border: none; border-radius: 5px;">Clear Cache</button>
                <button id="exportButton" style="width: 100%; margin-top: 10px; padding: 5px; background-color: #FF9800; color: white; border: none; border-radius: 5px;">Export Bookmarks</button>
                <input type="file" id="importButton" accept=".json" style="width: 100%; margin-top: 10px;" title="Import Bookmarks">
            </div>
        `;

        // Wait for tab to be connected to DOM
        await W.userscripts.waitForElementConnected(tabPane);

        // Update bookmark list
        updateUrlList();

        // Set up event listeners
        setupEventListeners();
    }

    // Function to update bookmark list
    function updateUrlList() {
        const urlList = document.getElementById('urlList');
        urlList.innerHTML = '';
        allowedUrls.forEach((item) => {
            const li = document.createElement('li');
            li.style.display = 'flex';
            li.style.justifyContent = 'space-between';
            li.style.alignItems = 'center';
            li.style.marginBottom = '5px';
            li.innerHTML = `<span style="flex: 1; font-size: ${defaultFontSize};"><a href="${item.url}" style="color: #2196F3;" class="bookmarkLink" data-url="${item.url}">${item.name || item.url}</a></span>`;
            const removeButton = document.createElement('button');
            removeButton.textContent = 'Remove';
            removeButton.style.marginLeft = '10px';
            removeButton.style.backgroundColor = '#F44336';
            removeButton.style.color = 'white';
            removeButton.style.border = 'none';
            removeButton.style.borderRadius = '3px';
            removeButton.style.padding = '2px 5px';
            removeButton.addEventListener('click', () => {
                allowedUrls = allowedUrls.filter(i => i.url !== item.url);
                localStorage.setItem('allowedUrls', JSON.stringify(allowedUrls));
                updateUrlList();
            });
            li.appendChild(removeButton);
            urlList.appendChild(li);
        });
    }

    // Function to clear cache and navigate
    function clearCacheAndNavigate(url) {
        caches.keys().then(names => {
            return Promise.all(names.map(name => caches.delete(name)));
        }).then(() => {
            window.location.href = url;
        });
    }

    // Function to paste from clipboard
    async function pasteFromClipboard(inputId) {
        try {
            const text = await navigator.clipboard.readText();
            document.getElementById(inputId).value = text;
        } catch (err) {
            console.error('Failed to paste from clipboard:', err);
            alert('Failed to paste from clipboard. Please ensure clipboard permissions are enabled.');
        }
    }

    // Set up event listeners
    function setupEventListeners() {
        document.getElementById('addUrlButton').addEventListener('click', () => {
            const urlInput = document.getElementById('urlInput');
            const nameInput = document.getElementById('nameInput');
            const newUrl = urlInput.value.trim();
            const newName = nameInput.value.trim();

            if (newUrl && !allowedUrls.some(item => item.url === newUrl)) {
                allowedUrls.push({ url: newUrl, name: newName });
                localStorage.setItem('allowedUrls', JSON.stringify(allowedUrls));
                urlInput.value = '';
                nameInput.value = '';
                updateUrlList();
            } else if (allowedUrls.some(item => item.url === newUrl)) {
                alert('This bookmark already exists.');
            } else {
                alert('Please enter a URL.');
            }
        });

        document.getElementById('clearCacheButton').addEventListener('click', () => {
            clearCacheAndNavigate(window.location.href);
        });

        document.getElementById('exportButton').addEventListener('click', () => {
            const dataStr = JSON.stringify(allowedUrls);
            const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
            const linkElement = document.createElement('a');
            linkElement.setAttribute('href', dataUri);
            linkElement.setAttribute('download', 'bookmarks.json');
            linkElement.click();
        });

        document.getElementById('importButton').addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    allowedUrls = JSON.parse(e.target.result);
                    localStorage.setItem('allowedUrls', JSON.stringify(allowedUrls));
                    updateUrlList();
                };
                reader.readAsText(file);
            }
        });

        document.getElementById('pasteUrlButton').addEventListener('click', () => {
            pasteFromClipboard('urlInput');
        });

        document.getElementById('pasteNameButton').addEventListener('click', () => {
            pasteFromClipboard('nameInput');
        });

        document.addEventListener('click', (e) => {
            if (e.target.classList.contains('bookmarkLink')) {
                e.preventDefault();
                const targetUrl = e.target.getAttribute('data-url');
                clearCacheAndNavigate(targetUrl);
            }
        });
    }

    // Start script initialization
    waitForWmeReady();
})();