map-making.app formula selector

in map edition page, adds a formula button at the bottom right

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         map-making.app formula selector
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  in map edition page, adds a formula button at the bottom right
// @author       JanosGeo
// @license      MIT
// @match        https://map-making.app/maps/*
// @run-at       document-idle
// @icon         https://www.google.com/s2/favicons?sz=64&domain=map-making.app
// @grant        none
// ==/UserScript==

// JanosGeo comments:
// Original code developed by .flamby. I've modified the code to
// 1. Use the order and same color for the tags
// 2. Customize the styling
// 3. Add the option to right-click to make an intersection instead of a union.

function addStyle() {
  let style = document.createElement("style");
  style.type = "text/css";
  let css = ".buttonFormula {";
  css += "padding: 5px; ";
  css += "margin: 4px; ";
  css += "color: #C8A675; ";
  css += "background-color: #1A1C1D; ";
  css += "border-radius: 10px; ";
  css += "border-color: #C8A675; ";
  css += "}";
  css += ".buttonFormula:hover{";
  css += "color: #F3DCBB; ";
  css += "border-color: #F3DCBB; ";
  css += "}";
  css += "#buttonExec{";
  css += "margin-right: 16px; ";
  css += "}";

  style.innerHTML = css;
  document.head.appendChild(style);
}

function createDivButton() {
  let divButton = document.createElement("button");
  divButton.textContent = "Selections";
  divButton.id = "divButton";
  divButton.style.position = "fixed";
  divButton.style.right = "110px";
  divButton.style.bottom = "15px";
  divButton.style.borderRadius = "18px";
  divButton.style.fontSize = "15px";
  divButton.style.padding = "5px 10px";
  divButton.style.border = "none";
  divButton.style.color = "white";
  divButton.style.cursor = "pointer";
  divButton.style.backgroundColor = "#4CAF50";

  document.body.appendChild(divButton);
  divButton.addEventListener("click", function () {
    updateTagList();
    document.getElementById("divFormula").style.display = "flex";
  });
}

function unionTag(tag) {
  let original = document.getElementById("inputFormula").value;
  if (original !== "") {
    original += " || ";
  }
  document.getElementById("inputFormula").value = original + "{" + tag + "}";
}

function intersectTag(tag) {
  let original = document.getElementById("inputFormula").value;
  if (original !== "") {
    original = "(" + original + ") && ";
  }
  document.getElementById("inputFormula").value = original + "{" + tag + "}";
}

function handleClick(event, tag) {
  if (event.button == 0) {
    // Left click
    unionTag(tag);
  } else if (event.button == 1) {
    // Wheel click, do nothing for now
  } else if (event.button == 2) {
    // right click
    event.preventDefault();
    intersectTag(tag);
  }
}

function componentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

function rgbToHex(arr) {
  return (
    "#" +
    componentToHex(arr[0]) +
    componentToHex(arr[1]) +
    componentToHex(arr[2])
  );
}

function textColor(arr) {
  let r = arr[0];
  let g = arr[1];
  let b = arr[2];
  return r * 0.299 + g * 0.587 + b * 0.114 >= 125 ? "black" : "white";
}

function updateTagList() {
  // Read tags in the proper order
  let tags = [];
  for (const tag in window.editor.tags) {
    tags.push(window.editor.tags[tag]);
  }
  tags.sort((a, b) => a.order - b.order);

  let strHTML = "";
  for (const tag in tags) {
    const name = tags[tag].tag;
    strHTML +=
      "<button id='buttonTag_" +
      name +
      "' class='buttonFormula'>" +
      name +
      "</button>";
  }
  document.getElementById("divTagList").innerHTML = strHTML;

  for (const tag in tags) {
    const name = tags[tag].tag;
    let button = document.getElementById("buttonTag_" + name);
    button.style.backgroundColor = rgbToHex(tags[tag].color);
    button.style.color = textColor(tags[tag].color);
    button.addEventListener("contextmenu", (event) => event.preventDefault());
    button.addEventListener("mousedown", (event) => {
      handleClick(event, name);
    });
  }
}

function createDivFormula() {
  let divFormula = document.createElement("div");
  divFormula.id = "divFormula";
  divFormula.style.display = "none";
  divFormula.style.position = "fixed";
  divFormula.style.top = "50%";
  divFormula.style.left = "50%";
  divFormula.style.transform = "translate(-50%, -50%)";
  divFormula.style.flexDirection = "column";
  divFormula.style.zIndex = 1000;
  divFormula.style.margin = "15px";
  divFormula.style.backgroundColor = "#1A1C1D";
  divFormula.style.borderRadius = "10px";
  divFormula.style.padding = "10px";

  let strHTML =
    "<div id='divTagList' style='display:flex;flex-direction:row;max-width:50vw;flex-wrap:wrap;'>";
  strHTML += "</div>";

  strHTML += "<div style='display:flex;flex-direction:row;margin:15px;'>";
  strHTML +=
    "<span style='margin:5px;'>Formula</span><input id='inputFormula' type='text' style='width:50vw;margin:5px;font-size:16px;' title='Example: ({black_car}||{white_car}) && !{antenna}'/>";
  strHTML +=
    "<button id='buttonExec' class='buttonFormula'>select</button><button id='buttonClear' class='buttonFormula'>clear</button><button id='buttonCancel' class='buttonFormula'>cancel</button>";
  strHTML += "</div>";

  divFormula.innerHTML = strHTML;
  document.body.appendChild(divFormula);

  document
    .getElementById("buttonCancel")
    .addEventListener("click", function () {
      document.getElementById("divFormula").style.display = "none";
    });

  document.getElementById("buttonClear").addEventListener("click", function () {
    document.getElementById("inputFormula").value = "";
  });

  document.getElementById("buttonExec").addEventListener("click", function () {
    let strFormula = document.getElementById("inputFormula").value;
    while (strFormula.includes("{")) {
      let intStart = strFormula.indexOf("{");
      let intEnd = strFormula.indexOf("}");
      if (intStart + 1 >= intEnd) {
        return 0;
      }
      let tagName = strFormula.substring(intStart + 1, intEnd);

      strFormula =
        strFormula.substring(0, intStart) +
        "window.locations[i].tags.includes('" +
        tagName +
        "')" +
        strFormula.substring(intEnd + 1, strFormula.length);
    }

    let locationList = [];
    for (let i = 0; i < window.locations.length; i++) {
      if (eval(strFormula)) {
        locationList.push(window.locations[i]);
      }
    }
    window.editor.selectLocations(locationList);
    document.getElementById("divFormula").style.display = "none";
  });
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// main
(async () => {
  // wait for page load
  while (window.editor == undefined) {
    await sleep(250);
  }
  await sleep(250);

  // add buttons and styles
  addStyle();
  createDivButton();
  createDivFormula();
})();