您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adjust the tabs in the Waze Map Editor to your liking by adjusting their size, hiding tabs or even renaming tabs completely.
当前为
// ==UserScript== // @name WME Tab Preferences // @namespace http://www.tomputtemans.com/ // @description Adjust the tabs in the Waze Map Editor to your liking by adjusting their size, hiding tabs or even renaming tabs completely. // @include https://www.waze.com/*/editor/* // @include https://www.waze.com/editor/* // @include https://editor-beta.waze.com/* // @exclude https://www.waze.com/user/*editor/* // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADcAAAA3CAYAAACo29JGAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wwCEzYBoD6dGgAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAACfUlEQVRo3u3aTUgUYRjA8b/bjKyziyyTH2VpKYoHDxLkaTFvRSJCeBHxpFBHCULoWgcpqL3VqZaQIIKULlKSBoqIGJjQQTE2T8YqbpCzrwuz63Zwxy5+pLTtzvY8txle5n1+PO/XDFP0c8tKU6DhoYBDcIITnOAE99/jtKMa2LaNUnGSts3Ozk5+VMTjQdN1jBIDvbj4wHZFh51QtpXCsrbyujo+nx/D5zte5Wzb3oOZponf70fTtLwAJZNJLMsiFosRj1vour5vBQ+cc0rF92CBQCBvYACaphEIBDBNczfXbXW8BSWVSgFgGEbeDkknNyfXP8clkwAUHzJhcx1Obk6uss8JTnCCy93x6+/FJgvvp1hVBhevXOPS6UKo3NoUI++WSDDHyMMQodBTJpbAmn/D6EIiq10feLbcWI8CUFdXd/KnJxZ4cusOr76BYZxCqQzGa2CkFIpaeh+/4GbzybuIRCIAlFdU/uPKeSs5X1UC2L9hAAmFsoGzLbQ0unJYWnz5MMemx7t7WRrk9vA4U2PPGQiWZpDf+Twxw1fLdbhJXt4LEZ5eB6CmvZsbF7zgr6eru50agPVpwg/u8mzSdbgKquvLMA19d63ciOIMzLXIKpsAuoFZdo7yUjcuKMBKuJ/+8AqgYzZeptmMsfhpmZgNtAww9qgLP25cUJhh9O2K8/pLbHmWj7MZGMD8ME9mXLvPBenta+NM7XUGh3poyNxt6Bli8Go15W199AZdfEKp6rzP606ARaJN4/yIVtHaGqSjKUhHlvvO+pzLduRwzslbgeAEJzjBCS6331CczdrtsZ+joCtXlE6n5Q8iwQlOcIITnOAEJzjBCe6I+AVAjNynsKm5WAAAAABJRU5ErkJggg== // @version 1.0.1 // @grant none // ==/UserScript== "use strict"; (function() { var tabReopened = false, // have we reopened the tab from last time? timesRan = 0, // variable for sanity check tabsSecured = -1, // Up until which index have we fully rearranged the tabs? versions = ['0.1', '0.2', '1.0', '1.0.1'], Storage = (function() { var hashes = (localStorage.tabprefs_hidden ? localStorage.tabprefs_hidden.split(',') : []), tabConfigs = (localStorage.tabprefs_configs ? JSON.parse(localStorage.tabprefs_configs) : {}); return { setTabVisibility: function(hash, visible) { var hashIndex = hashes.indexOf(hash); if (hashIndex !== -1 && visible) { hashes.splice(hashIndex, 1); localStorage.tabprefs_hidden = hashes.join(); } else if (hashIndex === -1 && !visible) { hashes.push(hash); localStorage.tabprefs_hidden = hashes.join(); } }, isTabVisible: function(hash) { return hashes.indexOf(hash) === -1; }, setTabConfig: function(hash, config) { tabConfigs[hash] = config; localStorage.tabprefs_configs = JSON.stringify(tabConfigs); }, removeTabConfig: function(hash) { delete tabConfigs[hash]; localStorage.tabprefs_configs = JSON.stringify(tabConfigs); }, getTabConfig: function(hash) { return tabConfigs[hash] || {}; } }; })(); function init() { if (typeof I18n === 'undefined') { log('No internationalisation object found yet, snoozing'); setTimeout(init, 300); return; } var om_strings = { en: { prefs: { title: 'Tab Preferences', tab_width: 'Tab width', tab_height: 'Tab height', reset: 'reset', preserve_tab: 'Preserve opened tab over sessions', preserve_order: 'Preserve tab order and change names', remove_tab: 'Tab no longer found. Remove entry?', hide_tab: 'Change tab visibility', edit_tab_name: 'Replace tab name', change_icon: 'Change icon', set_icon: 'Set icon', reset_tab: 'Reset tab', icon: 'Icon', icon_none: 'None set', close: 'Close' }, update: { first_run: 'Thanks for using Tab Preferences!\nThe settings tab on the left contains additional options now.\nThis message will only appear one time.', message: 'New version installed! Changelog:', v0_1: '- Initial version with tab memory and order preservation', v0_2: '- Improvements to order preservation algorithm\n- Addition of version change messages', v1_0: '- Ability to hide a tab added\n- Ability to replace tab with symbol added\n- Ability to resize tabs added\n- Metadata icon added to userscript', v1_0_1: '- Fixed the script for Google Chrome' } }, nl: { prefs: { title: 'Tabvoorkeuren', preserve_tab: 'Geopende tab bijhouden tussen sessies', preserve_order: 'Volgorde van tabs bijhouden en namen veranderen', remove_tab: 'Tab niet langer gevonden. Verwijderen?' } } }; om_strings['en_GB'] = om_strings.en; for(var i = 0; i < I18n.availableLocales.length; i++) { var locale = I18n.availableLocales[i]; if (I18n.translations[locale]) { I18n.translations[locale].tabpreferences = om_strings[locale]; } } checkVersion(); // Always add scrollbar to sidepanel to keep the width constant document.getElementById('sidebar').style.overflowY = 'scroll'; initTabListener(); initSettings(); } function initTabListener() { var tabs = document.querySelector('#user-tabs .nav-tabs'); if (!tabs) { log('No tabs found yet, snoozing'); setTimeout(initTabListener, 400); return; } log('Tabs found, enabling observers'); var selectionObserver = new MutationObserver(function(mutationRecords) { mutationRecords.forEach(function(mutationRecord) { // Store last opened tab when one of the tabs receives focus if (localStorage.tabprefs_reopenTab && mutationRecord.target.className === 'active') { localStorage.tabprefs_reopenTab = mutationRecord.target.querySelector('a').hash; } }); }); for (var i = 0; i < tabs.children.length; i++) { selectionObserver.observe(tabs.children[i], { attributes: true, attributeFilter: ['class'] }); if (!Storage.isTabVisible(tabs.children[i].querySelector('a').hash)) { tabs.children[i].style.display = 'none'; } } var tabObserver = new MutationObserver(function(mutationRecords) { if (!tabReopened) { reopenTab(); } mutationRecords.forEach(function(mutationRecord) { // Reorder tabs when new ones get added if (mutationRecord.addedNodes.length > 0) { for (var i = 0; i < mutationRecord.addedNodes.length; i++) { var node = mutationRecord.addedNodes[i], hash = node.querySelector('a').hash; // Also start observing here for changes to tab selection selectionObserver.observe(node, { attributes: true, attributeFilter: ['class'] }); // Tab visibility if (!Storage.isTabVisible(hash)) { node.style.display = 'none'; } } renameTabs(); resizeTabs(); reorderTabs(); } }); }); tabObserver.observe(tabs, { childList: true }); reopenTab(); renameTabs(); resizeTabs(); reorderTabs(); } function initSettings() { var prefsTab = document.querySelector('#sidepanel-prefs'); if (!prefsTab) { log('No settings tab found yet, snoozing'); setTimeout(initSettings, 400); return; } var section = prefsTab.querySelector('.side-panel-section'), heading = document.createElement('h4'), tabOrderPanel = document.createElement('ul'), formGroup = document.createElement('div'); heading.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.title'))); formGroup.className = 'form-group'; formGroup.style.marginBottom = '15px'; formGroup.appendChild(createSlider('tabWidth', I18n.t('tabpreferences.prefs.tab_width'), localStorage.tabprefs_tabwidth, 15, function() { localStorage.tabprefs_tabwidth = this.value; resizeTabs(); })); formGroup.appendChild(createSlider('tabHeight', I18n.t('tabpreferences.prefs.tab_height'), localStorage.tabprefs_tabheight, 5, function() { localStorage.tabprefs_tabheight = this.value; resizeTabs(); })); formGroup.appendChild(createOption('reopenTab', I18n.t('tabpreferences.prefs.preserve_tab'), (localStorage.tabprefs_reopenTab ? true : false), function() { if (this.checked) { localStorage.tabprefs_reopenTab = document.querySelector('#user-tabs .nav-tabs li.active a').hash; } else { localStorage.removeItem('tabprefs_reopenTab'); } })); formGroup.appendChild(createOption('preserveOrder', I18n.t('tabpreferences.prefs.preserve_order'), (localStorage.tabprefs_preserveOrder ? true : false), function() { if (this.checked) { var tabs = document.querySelectorAll('#user-tabs .nav-tabs li a'), hashes = []; for (var i = 0; i < tabs.length; i++) { hashes.push(tabs[i].hash); } localStorage.tabprefs_preserveOrder = hashes.join(); refreshTabPanel(); document.getElementById('tabPreferencesOrder').style.display = 'block'; } else { localStorage.removeItem('tabprefs_preserveOrder'); document.getElementById('tabPreferencesOrder').style.display = 'none'; } })); tabOrderPanel.className = 'result-list'; tabOrderPanel.id = 'tabPreferencesOrder'; tabOrderPanel.style.display = (localStorage.tabprefs_preserveOrder ? '' : 'none'); formGroup.appendChild(tabOrderPanel); // Obsolete option, remove from localStorage if (localStorage.tabprefs_hidePermissions) { localStorage.removeItem('tabprefs_hidePermissions'); } section.appendChild(heading); section.appendChild(formGroup); refreshTabPanel(); } // Add options to the preferences tab function createOption(name, description, checked, eventHandler) { var input = document.createElement('input'); input.type = 'checkbox'; input.name = name; input.id = name + '-on'; input.checked = checked; input.addEventListener('click', eventHandler); var label = document.createElement('label'); label.htmlFor = name + '-on'; label.appendChild(document.createTextNode(description)); var container = document.createElement('div'); container.className = 'controls-container'; container.appendChild(input); container.appendChild(label); return container; } // Add sliders to the preferences tab function createSlider(name, description, initialValue, defaultValue, eventHandler) { var input = document.createElement('input'); input.type = 'range'; input.name = name; input.id = name + '-on'; input.min = 0; input.max = 30; input.value = (initialValue ? initialValue : defaultValue); input.addEventListener('input', eventHandler); input.style.verticalAlign = 'middle'; var label = document.createElement('label'); label.htmlFor = name + '-on'; label.appendChild(document.createTextNode(description)); label.style.marginRight = '4px'; var reset = document.createElement('button'); reset.className = 'btn-link'; reset.addEventListener('click', function() { input.value = defaultValue; var inputEvent = new InputEvent('input', { bubbles: true, cancelable: true }); input.dispatchEvent(inputEvent); }); reset.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.reset'))); var container = document.createElement('div'); container.className = 'controls-container'; container.appendChild(label); container.appendChild(input); container.appendChild(reset); return container; } // Attempt to reopen the tab opened during the previous session function reopenTab() { if (!localStorage.tabprefs_reopenTab) { return; } var tab = document.querySelector('#user-tabs .nav-tabs li a[href$="'+localStorage.tabprefs_reopenTab+'"]'); if (!tabReopened && tab) { log("Tab to reopen found, reopening now"); var clickEvent = new MouseEvent("click", { bubbles: true, cancelable: true, view: window }); tab.dispatchEvent(clickEvent); tabReopened = true; } } // If necessary, start reordering the tags as they were saved function reorderTabs(force) { if (force) { tabsSecured = -1; } // Protection against possible infinite loop if certain scripts don't follow the standards if (timesRan > 1000) { return; } if (timesRan === 1000) { log('Sanity limit reached! Tab Preferences is most likely conflicting with another script. Backing off from now on.'); // run one last time to increase counter } timesRan++; if (localStorage.tabprefs_preserveOrder) { var hashes = localStorage.tabprefs_preserveOrder.split(','), navTabs = document.querySelector('#user-tabs ul.nav-tabs'), navAnchors = navTabs.querySelectorAll('li a'); // First we check whether we know all tabs we currently have for (var i = 0; i < navAnchors.length; i++) { if (hashes.indexOf(navAnchors[i].hash) === -1) { // Add unknown tags to the end of the list hashes.push(navAnchors[i].hash); } } localStorage.tabprefs_preserveOrder = hashes.join(); refreshTabPanel(); // Then we put them in the order we have stored var tabsMissing = 0; for (var i = tabsSecured+1; i < hashes.length; i++) { var tabAnchor = navTabs.querySelector('a[href$="'+hashes[i]+'"]'); if (!tabAnchor) { tabsMissing++; continue; } var tabIndex = Array.prototype.indexOf.call(navTabs.children, tabAnchor.parentNode); if (tabIndex === i && tabsSecured === tabIndex-1) { tabsSecured++; } if (tabAnchor && tabIndex !== i - tabsMissing && i < navTabs.children.length) { navTabs.insertBefore(tabAnchor.parentNode, navTabs.children[i - tabsMissing]); if (tabsSecured === i-1) { tabsSecured++; } } } } } function resizeTabs() { var width = (localStorage.tabprefs_tabwidth ? localStorage.tabprefs_tabwidth : 15), height = (localStorage.tabprefs_tabheight ? localStorage.tabprefs_tabheight : 5), tabAnchors = document.querySelectorAll('#user-tabs .nav-tabs li a'); for (var i = 0; i < tabAnchors.length; i++) { tabAnchors[i].style.padding = height + 'px ' + width + 'px'; } } function renameTabs(force) { var tabs = document.querySelectorAll('#user-tabs .nav-tabs li a'); for (var i = 0; i < tabs.length; i++) { var anchor = tabs[i], config = Storage.getTabConfig(anchor.hash); if (config && config.icon && (!anchor.originalChildren || force)) { if (!anchor.originalChildren) { var children = []; for (var j = 0; j < anchor.childNodes.length; j++) { // Bleh, nodelist doesn't support for each children.push(anchor.childNodes[j]); } anchor.originalChildren = children; } if (config.icon) { var span = document.createElement('span'); span.style.fontFamily = config.icon.fontFamily; span.appendChild(document.createTextNode(String.fromCharCode(config.icon.charCode))); span.style.fontWeight = 'normal'; while (anchor.firstChild) { anchor.removeChild(anchor.firstChild); } anchor.appendChild(span); } } if (!config.icon && anchor.originalChildren) { while (anchor.firstChild) { anchor.removeChild(anchor.firstChild); } anchor.originalChildren.forEach(function(node) { anchor.appendChild(node); }); delete anchor.originalChildren; } } } function refreshTabPanel() { var tabPanel = document.getElementById('tabPreferencesOrder'), eyeSlashIcon = String.fromCharCode(61552), eyeIcon = String.fromCharCode(61550); if (!localStorage.tabprefs_preserveOrder || !tabPanel) { return; } var order = localStorage.tabprefs_preserveOrder.split(','); while (tabPanel.firstChild) { // clear out tabPanel's children tabPanel.removeChild(tabPanel.firstChild); } order.forEach(function(hash, index, obj) { var item = document.createElement('li'), name = document.createElement('span'), buttons = document.createElement('div'), moveUp = document.createElement('span'), moveDown = document.createElement('span'), remove = document.createElement('span'), hide = document.createElement('span'), edit = document.createElement('span'), anchor = document.querySelector('#user-tabs .nav-tabs li a[href$="'+hash+'"]'), tabConfig = {}; if (anchor) { tabConfig = Storage.getTabConfig(hash); } // Add action buttons if (!anchor) { remove.className = 'icon-remove fa fa-remove'; remove.style.cursor = 'pointer'; remove.title = I18n.t('tabpreferences.prefs.remove_tab'); remove.addEventListener('click', function() { obj.splice(index, 1); localStorage.tabprefs_preserveOrder = obj.join(); refreshTabPanel(); }); buttons.appendChild(remove); } if (hash !== '#sidepanel-prefs') { // Prevent the preferences tab from being hidden and getting locked out hide.className = 'icon- fa'; hide.innerHTML = (Storage.isTabVisible(hash) ? eyeSlashIcon : eyeIcon); hide.style.cursor = 'pointer'; hide.style.marginLeft = '3px'; hide.title = I18n.t('tabpreferences.prefs.hide_tab'); hide.addEventListener('click', function() { if (this.innerHTML === eyeSlashIcon) { this.innerHTML = eyeIcon; anchor.parentNode.style.display = 'none'; Storage.setTabVisibility(hash, false); } else { this.innerHTML = eyeSlashIcon; anchor.parentNode.style.display = 'block'; Storage.setTabVisibility(hash, true); } refreshTabPanel(); }); buttons.appendChild(hide); } edit.className = 'icon-pencil fa fa-pencil'; edit.style.cursor = 'pointer'; edit.style.marginLeft = '3px'; edit.title = I18n.t('tabpreferences.prefs.edit_tab_name'); edit.addEventListener('click', function() { if (!item.details) { createTabConfigPane(item, hash); } else { item.removeChild(item.details); item.details = false; } }); buttons.appendChild(edit); moveDown.className = 'icon-chevron-down fa fa-chevron-down'; moveDown.style.marginLeft = '3px'; if (index === order.length - 1) { moveDown.style.cursor = 'default'; moveDown.style.color = '#aaa'; } else { moveDown.style.cursor = 'pointer'; moveDown.addEventListener('click', function() { obj.splice(index+1, 0, obj.splice(index, 1)[0]); localStorage.tabprefs_preserveOrder = obj.join(); reorderTabs(true); refreshTabPanel(); }); } buttons.appendChild(moveDown); moveUp.className = 'icon-chevron-up fa fa-chevron-up'; moveUp.style.marginLeft = '3px'; if (index === 0) { moveUp.style.color = '#aaa'; moveUp.style.cursor = 'default'; } else { moveUp.style.cursor = 'pointer'; moveUp.addEventListener('click', function() { obj.splice(index-1, 0, obj.splice(index, 1)[0]); localStorage.tabprefs_preserveOrder = obj.join(); reorderTabs(true); refreshTabPanel(); }); } buttons.appendChild(moveUp); buttons.style.float = 'right'; item.className = 'result'; item.appendChild(buttons); // Add name and replacement if (anchor) { var title = anchor.title; if (!title) { title = anchor.parentNode.title; } if (anchor.originalChildren) { var arrow = document.createElement('span'); arrow.style.fontFamily = 'FontAwesome'; arrow.style.color = '#888'; arrow.style.margin = '0 6px'; arrow.appendChild(document.createTextNode(String.fromCharCode(61537))); anchor.originalChildren.forEach(function(node) { name.appendChild(node.cloneNode(true)); }); name.appendChild(arrow); for (var i = 0; i < anchor.childNodes.length; i++) { name.appendChild(anchor.childNodes[i].cloneNode(true)); } } else { name.innerHTML = anchor.innerHTML; } if (title) { name.appendChild(document.createTextNode(' (' + title + ')')); } if (!Storage.isTabVisible(hash)) { name.style.color = '#888'; } } else { name.style.color = '#888'; name.style.fontStyle = 'italic'; name.appendChild(document.createTextNode(hash)); } item.appendChild(name); tabPanel.appendChild(item); }); } function checkVersion() { var version = localStorage.tabprefs_version, scriptVersion = GM_info.script.version; if (!version) { showMessage(I18n.t('tabpreferences.update.first_run')); localStorage.tabprefs_version = scriptVersion; } else if (version !== scriptVersion) { if (versions.indexOf(version) === -1) { // There's tampering happening if we arrive here, just set to current version and ignore issue localStorage.tabprefs_version = scriptVersion; return; } var message = I18n.t('tabpreferences.update.message'); for (var i = versions.indexOf(version)+1; i < versions.length; i++) { message += '\nv' + versions[i] + ':\n' + I18n.t('tabpreferences.update.v' + versions[i].replace(/\./g, '_')); } showMessage(message); localStorage.tabprefs_version = scriptVersion; } } function createTabConfigPane(container, hash) { var tabConfig = Storage.getTabConfig(hash), details = document.createElement('div'), iconDiv = document.createElement('div'), iconBtn = document.createElement('button'), icon = document.createElement('span'), nameDiv = document.createElement('div'), nameBtn = document.createElement('button'), titleDiv = document.createElement('div'), titleBtn = document.createElement('button'), reset = document.createElement('button'), close = document.createElement('button'); iconBtn.appendChild(document.createTextNode((tabConfig.icon ? I18n.t('tabpreferences.prefs.change_icon') : I18n.t('tabpreferences.prefs.set_icon')))); iconBtn.style.margin = '0 10px'; iconBtn.className = 'btn-link'; iconBtn.addEventListener('click', function() { if (!iconBtn.icons) { var icons = document.createElement('div'); icons.style.height = '10em'; icons.style.overflow = 'auto'; icons.style.letterSpacing = '5px'; icons.style.fontSize = '12px'; icons.style.wordWrap = 'break-word'; // FontAwesome: symbols start at 'F000' (= 61440) and end at 'F295' in version 4.5 of FontAwesome (Waze uses 4.4) for (let i = 61440; i <= 62101; i++) { var icon = document.createElement('span'); icon.style.fontFamily = 'FontAwesome'; icon.appendChild(document.createTextNode(String.fromCharCode(i))); icon.style.cursor = 'pointer'; icon.addEventListener('click', function() { tabConfig.icon = { fontFamily: 'FontAwesome', charCode: i }; Storage.setTabConfig(hash, tabConfig); container.removeChild(details); renameTabs(true); refreshTabPanel(); }); icons.appendChild(icon); } details.insertBefore(icons, reset); iconBtn.icons = icons; } else { details.removeChild(iconBtn.icons); iconBtn.icons = false; } }); iconDiv.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.icon') + ': ')); if (tabConfig.icon) { icon.style.fontFamily = tabConfig.icon.fontFamily; icon.appendChild(document.createTextNode(String.fromCharCode(tabConfig.icon.charCode))); } else { icon.style.fontStyle = 'italic'; icon.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.icon_none'))); } iconDiv.appendChild(icon); iconDiv.appendChild(document.createElement('br')); iconDiv.appendChild(iconBtn); details.appendChild(iconDiv); reset.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.reset_tab'))); reset.style.margin = '0 5px'; reset.className = 'btn btn-danger'; reset.addEventListener('click', function() { Storage.removeTabConfig(hash); container.removeChild(details); container.details = false; renameTabs(); refreshTabPanel(); }); details.appendChild(reset); close.appendChild(document.createTextNode(I18n.t('tabpreferences.prefs.close'))); close.style.margin = '0 5px'; close.className = 'btn btn-default'; close.addEventListener('click', function() { container.removeChild(details); container.details = false; }); details.appendChild(close); container.details = details; container.appendChild(details); } function showMessage(message) { alert('Tab Preferences\n=============\n' + message); } function log(message) { if (console.log) { console.log('%cWME Tab Preferences: %c' + message, 'color:black', 'color:#d97e00'); } } log('version - ' + GM_info.script.version); init(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址