WME Layer Saver

Save the state of different combinations of layer display settings.settings

目前為 2019-06-13 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name               WME Layer Saver
// @author             HBiede
// @namespace          hbiede.com
// @description        Save the state of different combinations of layer display settings.settings
// @include            /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/
// @require            https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @version            2019.06.12.001
// @grant              none
// @copyright          2019 HBiede
// ==/UserScript==

/* global GM_info */
/* global W */
/* global WazeWrap */
/* global require */
/* global $ */
/* global localStorage */
/* global document */
/* global alert */
/* global prompt */
/* global window */

const DEBUG = true;
const UPDATE_DESCRIPTION = "<h4 style='margin-bottom: 5px;'>Changes:</h4><ul><li>Server Saving via WazeWrap</li><li>Export Individual Groups</li></ul>";
const DEFAULT_SETTINGS = { settings: [] };
const SCRIPT_STRING = 'LSaver';
const settings = DEFAULT_SETTINGS;


// clear the alert text
function setAlertParagraph(message) {
    if (typeof message === 'string') document.getElementById('LSaverAlertText').innerText = message;
}

// load the settings.settings from the local and server sources
async function loadSettings() {
    let local;
    try {
        local = JSON.parse(localStorage.getItem(SCRIPT_STRING));
    } catch (e) {
        local = DEFAULT_SETTINGS;
    }
    try {
        const returnValue = $.extend(DEFAULT_SETTINGS, local);

        const serverSettings = await WazeWrap.Remote.RetrieveSettings(SCRIPT_STRING);
        if (serverSettings && serverSettings.time > returnValue.time) {
            $.extend(returnValue, serverSettings);
        }
        return returnValue;
    } catch (e) {
        if (DEBUG) console.log(`${e.message}`);
        return DEFAULT_SETTINGS;
    }
}

// save settings.settings locally/to the server
function saveSettings() {
    settings.time = Date.now();
    WazeWrap.Remote.SaveSettings(SCRIPT_STRING, settings);
    localStorage.setItem(SCRIPT_STRING, JSON.stringify(settings));
}

// load all the settings.settings groups
async function loadLayerSaverSettings() {
    const returnValue = await loadSettings(SCRIPT_STRING);
    if (DEBUG) console.log(returnValue);
    settings.settings = returnValue.settings;
    saveSettings(SCRIPT_STRING);
    console.log(await WazeWrap.Remote.RetrieveSettings(SCRIPT_STRING));
}

// save all the settings groups
function saveLayerSaverSettings() {
    let arrayBuilder = [];
    const currentSettings = document.getElementById('LSaverSelector').children;
    for (let i = 1; i < currentSettings.length; i++) {
        arrayBuilder = arrayBuilder.concat([`${currentSettings[i].textContent}::${currentSettings[i].settingsString}`]);
    }
    arrayBuilder.sort();
    settings.settings = arrayBuilder;
    console.log(settings.settings);
    saveSettings(SCRIPT_STRING);
}

// load the selected settings.settings group
function loadLayerSettings() {
    if (document.getElementById('LSaverSelector').selectedIndex !== 0) {
        const settingsString = document.getElementById('LSaverSelector').selectedOptions[0].settings.settingsString;
        if (DEBUG) console.log(`Loading according to: ${settingsString}`);
        const toggles = document.getElementById('layer-switcher-group_display').parentNode.parentNode.parentNode.querySelectorAll('input');
        for (let i = 0; i < toggles.length; i++) {
            // if the input is in the group and not checked, or not in the group and checked, click the input
            if (((toggles[i].id && settingsString.includes(toggles[i].id)) || (toggles[i].labels[0].textContent && settingsString.includes(toggles[i].labels[0].textContent))) !== toggles[i].checked) {
                if (DEBUG) console.log(`Toggling ${toggles[i].labels[0].textContent} ${(settingsString[0].includes(toggles[i].id))}`);
                toggles[i].click();
            }
        }
        console.log(`Loaded Group: ${document.getElementById('LSaverSelector').selectedOptions[0].textContent}`);
    }
}

// delete the selected settings.settings group
function deleteLayerSettings() {
    if (document.getElementById('LSaverSelector').selectedIndex !== 0) {
        const name = document.getElementById('LSaverSelector').children[document.getElementById('LSaverSelector').selectedIndex].textContent;
        document.getElementById('LSaverSelector').children[document.getElementById('LSaverSelector').selectedIndex].remove();
        saveLayerSaverSettings();
        console.log(`Deleted Group: ${name}`);
    }
}

// turn the currently selected inputs into a usable string
function getCurrentLayerSettingsString() {
    const toggles = document.getElementById('layer-switcher-group_display').parentNode.parentNode.parentNode.querySelectorAll('input');
    let stringBuilder = '';
    for (let i = 0; i < toggles.length; i++) {
        if (toggles[i].checked) {
            stringBuilder += (toggles[i].id
                ? toggles[i].id
                : (toggles[i].labels[0].textContent ? toggles[i].labels[0].textContent : ''));
        }
    }
    if (DEBUG) console.log(stringBuilder);
    return stringBuilder;
}

// save the selected settings.settings group
function saveLayerSettings() {
    const layerSettingSelector = document.createElement('option');
    layerSettingSelector.textContent = prompt('Name Your New Layer Settings Group', '');
    if (layerSettingSelector.textContent != null) {
        layerSettingSelector.settingsString = getCurrentLayerSettingsString();
        document.getElementById('LSaverSelector').appendChild(layerSettingSelector);
        saveLayerSaverSettings();
        console.log(`Created Group: ${layerSettingSelector.textContent}`);
        return;
    }
    console.log('Save Aborted');
}

function populateSelector() {
    const firstOption = document.createElement('option');
    firstOption.hidden = true;
    document.getElementById('LSaverSelector').appendChild(firstOption);

    // build the selector options
    if (settings.settings.length > 0) {
        for (let i = 0; i < settings.settings.length; i++) {
            const setting = settings.settings[i].split('::');
            const layerSettingSelector = document.createElement('option');
            [layerSettingSelector.textContent] = setting;
            [layerSettingSelector.value] = setting;
            console.log(setting[1]);
            layerSettingSelector.settingsString = setting[1] ? setting[1] : '';
            document.getElementById('LSaverSelector').appendChild(layerSettingSelector);
        }
    }
}

// build the selector on the script tab
function selectorInit() {
    console.log('Loading Layer Settings');
    populateSelector();

    // add button listeners
    document.getElementById('LSaverLoadBtn').addEventListener('click', () => { loadLayerSettings(); });
    document.getElementById('LSaverDeleteBtn').addEventListener('click', () => { deleteLayerSettings(); });
    document.getElementById('LSaverSaveBtn').addEventListener('click', () => { saveLayerSettings(); });
    document.getElementById('LSaverImportBtn').addEventListener('click', () => { importSettingsString(); });
    document.getElementById('LSaverExportBtn').addEventListener('click', () => { exportSettingsString(); });
    document.getElementById('LSaverExportAllBtn').addEventListener('click', () => { exportAllSettingsString(); });
    console.log('Layer Settings Loaded');
}

// import a settings array in the from of a base64 encoded stringified version of the settings array
function importSettingsString() {
    try {
        const importedArray = JSON.parse(window.atob(prompt('Import settings text:', '')));
        if (!Array.isArray(importedArray)) {
            setAlertParagraph('Invalid Input String');
            return;
        }
        settings.settings = settings.settings.concat(importedArray);
        saveSettings('LSaver');

        const selector = document.getElementById('LSaverSelector');
        while (selector.firstChild) {
            selector.removeChild(selector.firstChild);
        }
        populateSelector();

        setAlertParagraph('Loaded');
    } catch (e) {
        setAlertParagraph(e.message);
    }
}

function copyToClipboard(text) {
    if (text === '') {
        setAlertParagraph('Cannot export no settings.');
        return;
    }

    const ta = document.createElement('textarea');
    ta.value = text;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand('copy');
    document.body.removeChild(ta);
    setAlertParagraph("Copied all groups' settings text to clipboard");
}

// export the selected settings string
function exportSettingsString() {
    const selectedSetting = document.getElementById('LSaverSelector').selectedOptions[0];
    if (selectedSetting) {
        copyToClipboard(window.btoa(JSON.stringify([`${selectedSetting.textContent}::${selectedSetting.settings.settingsString}`])));
    } else {
        setAlertParagraph('Select a group');
    }
}

// export a settings array in the from of a base64 encoded stringified version of the settings array
function exportAllSettingsString() {
    copyToClipboard(window.btoa(JSON.stringify(settings.settings)));
}

// Create the tab in the sidebar via WazeWrap
function createTab() {
    const tabDisplay = $('<div>', { id: 'WMELayerSaver' });
    tabDisplay.html([
        '<h3><b>WME Layer Saver</b></h3>',
        `<p><i>${GM_info.script.version} by ${GM_info.script.author}</i></p>`,
        '<div id="LSaverSelectorDiv"><label>Groups</label><br><select id="LSaverSelector" style="width:90%; margin-bottom: 8px;"></select></div>',
        '<div id="LSaverInteractionDiv"></div>',
        '<button class="btn btn-primary" id="LSaverLoadBtn" title="Load" style="margin: 8px 8px auto auto;">Load</button>',
        '<button class="btn btn-primary" id="LSaverDeleteBtn" title="Delete Selected" style="margin: 8px 8px auto auto;">Delete Selected</button><br>',
        '<button class="btn btn-primary" id="LSaverSaveBtn" title="Save New Group" style="margin: 8px 8px auto auto;">Save New Group</button><br>',
        '<button class="btn btn-primary" id="LSaverImportBtn" title="Import" style="margin: 8px 8px auto auto;">Import</button>',
        '<button class="btn btn-primary" id="LSaverExportBtn" title="Export" style="margin: 8px 8px auto auto;">Export</button>',
        '<button class="btn btn-primary" id="LSaverExportAllBtn" title="Export All" style="margin: 8px 8px auto auto;">Export All</button>',
        '<p style="padding-top: 10px; font-weight: bold;" id="LSaverAlertText"></p>',
        '</div>'
    ].join(''));

    new WazeWrap.Interface.Tab('LSaver', tabDisplay.html(), selectorInit);
    if (DEBUG) console.log(tabDisplay);
}

// main function
async function initLayerSaver(attempts = 1) {
    if (attempts <= 1000) {
        if (!WazeWrap.Ready || typeof W === 'undefined' || typeof W.map === 'undefined' || typeof W.loginManager === 'undefined' || !document.querySelector('#topbar-container > div > div > div.location-info-region > div') || !document.getElementById('layer-switcher-group_display')) {
            if (DEBUG) console.log('retry');
            setTimeout(() => {
                initLayerSaver(attempts++);
            }, 800);
        } else {
            console.log('Starting Layer Saver');
            await loadLayerSaverSettings();
            createTab();
            WazeWrap.Interface.ShowScriptUpdate(GM_info.script.name, GM_info.script.version, UPDATE_DESCRIPTION, 'https://greasyfork.org/en/scripts/383384-wme-layer-saver', 'https://www.waze.com/forum/viewtopic.php?f=819&t=283513');
        }
    }
}

// start
setTimeout(initLayerSaver, 1000);