avoid leaving page without saving changes, enable preview button, and scroll current location (in both map and script view) into view to avoid excessive scrolling and searching. Also adds a setting "Publishing Mode", which, when disabled, prevents you from accidentally publishing a script instead of saving it. Load at least 100 locations in bulk editing mode, add a button to generate computer voice for all locations
// ==UserScript== // @name VoiceMap Tour Editor Additions // @namespace http://tampermonkey.net/ // @version 0.7 // @description avoid leaving page without saving changes, enable preview button, and scroll current location (in both map and script view) into view to avoid excessive scrolling and searching. Also adds a setting "Publishing Mode", which, when disabled, prevents you from accidentally publishing a script instead of saving it. Load at least 100 locations in bulk editing mode, add a button to generate computer voice for all locations // @author Kiki // @license MIT // @match https://voicemap.me/mapmaker/* // @icon https://www.google.com/s2/favicons?sz=64&domain=voicemap.me // @grant none // ==/UserScript== /* globals jQuery, $ */ (function() { 'use strict'; //window.onload = doItAll; window.setTimeout(doItAll, 2000); })(); function doItAll() { if (window.location.href.indexOf("/scripts") > -1) { enablePreview(); showHidePublishButton(); createPublishingModeSetting(); highlightCurrentScript(); } if (window.location.href.indexOf("/map-locations") > -1) { watchForNewSelection(); } if(window.location.href.indexOf("overview") > -1) { if(applyBulkEditingLimit()) { addBulkGenerateVoiceButton(); } } } function enablePreview() { var x = document.querySelector('span.isDisabled.text-gray-600:has(> a g[id="preview-icon"])'); if(x != null) { x.classList.remove("isDisabled"); x.classList.remove("text-gray-600"); } } function protectMyChanges() { $('textarea.sound_bite_text').bind('input propertychange', function() { $(window).on("beforeunload", function() { return true; }); }); $('input.btn.btn-save-location').on("click", function() { $(window).off("beforeunload"); }); $('input.btn.btn-danger.save_submit').on("click", function() { $(window).off("beforeunload"); }); } function highlightCurrentScript() { // show the list console.log('show sidebar'); $('#map-location').find('.sidebar').toggleClass("collapsed"); $('#map-location').find('.form-sound-bite').toggleClass("extend"); console.log('show sidebar - done'); //move to the current one var card = $('#map-location .card-location.active .mask'); if(card != null && card instanceof jQuery && card.length > 0) { card[0].scrollIntoView({ behavior: "instant", block: "nearest", inline: "nearest" }); } else { console.log("no highlight"); } } function watchForNewSelection() { var observer = new MutationObserver(function(mutations) { for (let mutation of mutations) { var elem = $(mutation.target); if (elem.hasClass('active')) { elem[0].scrollIntoView({ behavior: "instant", block: "nearest", inline: "nearest" }); break; } } }); observer.observe($('#map-location')[0], { subtree: true, attributes: true, attributeFilter: ['class'] }); console.log("observing"); } ////////////////////////////// // Publishing Mode function createPublishingModeSetting() { const newDiv = document.createElement("div"); // use predefined class for better layout newDiv.classList.add("btn"); newDiv.innerHTML = ` <div style="display:inline-block;">Publishing Mode: </div> <div style="display:inline-block;"> <label class="switch"> <input id="cbPublishingMode" type="checkbox" ${ (getCookie('PublishingMode') === 'true') ? 'checked' : '' } > <span class="slider round"></span> </label> </div> `; const parent = document.querySelector('div.btn-group'); parent.appendChild(newDiv); // add handler const cb = document.querySelector('input#cbPublishingMode'); cb.addEventListener("change", publishingModeChanged); } function publishingModeChanged(event) { setCookie('PublishingMode', event.currentTarget.checked); showHidePublishButton(); } function showHidePublishButton() { const btn = document.querySelector('.btn-danger.save_submit'); if(btn != null) { if(getCookie('PublishingMode') === "true") { btn.classList.remove('d-none'); } else { btn.classList.add('d-none'); } } } function setCookie(name, value, expireInDays = 30) { var expiry = new Date(); expiry.setDate(expiry.getDate() + expireInDays); document.cookie = `${name}=${value}; expires=${expiry.toUTCString()}; path=/`; } function deleteCookie(name) { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; } function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) { return parts.pop().split(';').shift(); } } ///////////////////////////////////////// // bulk editing page function applyBulkEditingLimit() { if(document.querySelector("a#dropdown-limit-locations span").innerText < 100) { document.location.href = document.location.href.split('?')[0] + "?limit=100"; return false; } return true; } function addBulkGenerateVoiceButton() { if(document.querySelector("button#btnVoice") == null) { const newDiv = document.createElement("div"); newDiv.innerHTML = ` <button id="btnVoice" class="btn" type="button" style="margin-left: 10px;">Generate ALL Speech</button> `; const parent = document.querySelector('div.card div.d-flex'); parent.appendChild(newDiv); // add handler const btn = document.querySelector('button#btnVoice'); btn.addEventListener("click", generateVoice); } } function generateVoice() { if(!confirm('Do you really want to create speech for ALL locations?\nThis will take a while.')) { return; } var soundBiteInputs = document.querySelectorAll("input.checkbox-select-sound-bite"); var soundBites = []; soundBiteInputs.forEach((a) => { soundBites.push(a.value);}); var authenticity_token = document.querySelector('input[name="authenticity_token"]').value; var data = { "utf8": "✓", "authenticity_token": authenticity_token, "action_type": "text_to_speech", "sound_bite_ids": soundBites.join(',') }; $.post(document.location.href, data, (data, status) => { console.log("generateVoice status: " + status); }); alert('Speech is being generated, please be patient.'); }