Widget:Postal map

display:inline-block; color:#000; background:#faeed9; border:2px solid #875A7F; border-radius:10px; z-index:1; }   float:left; width:15em; text-align:center; padding:0.5em; }   margin:4px; background-color:#002343; border-radius:10px; overflow:clip; }
 * 1) postal-map {
 * 1) postal-map #legend-container {
 * 1) postal-map #map-container {

background: #4E3351; border: 3px solid #B2738D; border-radius: 10px; text-align: center; color: #FCC56B; font-weight:bold; padding: 3px; margin:10px 0 15px; min-height:calc(1em + 6px); }   display:inline-block; position:relative; } .delivery-target { position:absolute; background-color:red; border-radius:50%; z-index:2; }   display:none; }
 * 1) postal-map .location {
 * 1) map-container {
 * 1) map-container .map:not(.selected){

position: relative; display: inline-block; width:calc(100% - 17px); height:1.5rem; box-sizing:unset; /* mobile */ }
 * 1) postal-autocomplete {

position: absolute; border: 1px solid #d4d4d4; border-bottom: none; border-top: none; z-index: 99; /*position the autocomplete items to be the same width as the container:*/ top: 100%; left: 0; right: 0; }
 * 1) postal-autocomplete-list {

padding: 10px; cursor: pointer; background-color: #fff; border-bottom: 1px solid #d4d4d4; text-align:left; }
 * 1) postal-autocomplete-list div {

/*when hovering an item:*/ background-color: #e9e9e9; }
 * 1) postal-autocomplete-list div:hover {

/*when navigating through the items using the arrow keys:*/ background-color: DodgerBlue; color: #ffffff; }
 * 1) postal-autocomplete-list .postal-autocomplete-active {

height:1.5rem; width:17px; border-style:none; float:right; direction:rtl; }
 * 1) postal-dropdown {

direction:ltr; }
 * 1) postal-dropdown option {

padding:2px; border:1px solid #555; width:calc(100% - 5px); height:calc(100% - 6px); }
 * 1) postal-input {

// This was reverse-engineered from https://ark.gamepedia.com/Widget:SpawnMap RLQ.push(['jquery', function {  const input = document.createElement("input");  input.setAttribute("id", "postal-input");  input.setAttribute("placeholder", "Delivery target");

const $select = $('') .append($(' ').val('').text('Select a delivery target')) .change(function {          // when the dropdown updates, update the map and the input          showLocation($(this).val);          input.value = $(this).val;      });

// When the input updates, update the map and the dropdown input.addEventListener("input", function (e) {   showLocation(this.value);    $select.val(this.value);  });

// sort the target list by name targets.sort((a,b) => (a.name > b.name) ? 1 : -1);

// Create the list of names names = [] targets.forEach(function (target) {   names.push(target.name);  }); // Add the list of names to the dropdown menu names.forEach(function (name) {   $select.append($(' ').text(name));  });

// Add the input and dropdown menu to the legend $('#legend-container').prepend($select); $('#postal-autocomplete').prepend(input);

// start the autocomplete script postalAutocomplete(input, names); //Allows for use of # anchors in the url to start the map with that item selected const urlHash = decodeURIComponent(window.location.hash); if (urlHash) { input.value = urlHash.substr(1); showLocation(input.value); } function showLocation(name) { const $mapContainer = $('#postal-map').find('#map-container');

// clear notes const description = document.querySelector("#legend-container .description"); const locationLabel = document.querySelector("#legend-container .location"); description.innerHTML = ""; locationLabel.innerHTML = "";

// clear the map $mapContainer.children('.delivery-target').remove; if (!name || !(names.includes(name))){ // clear the # in the URL, but also keep the page from jumping back to the top lastPos = $(window).scrollTop; window.location.hash = ''; $(window).scrollTop(lastPos); return; }   else { $mapContainer.children('.selected').removeClass('selected'); }   // draw point to the map const $target = targets.find(t => t.name === name); const pointSize = 10; // Remove all spaces and question marks (for The Highbelow?) in the target's location so we can get a valid HTML id	// then find the map with that id and mark it as selected $mapContainer.children('#' + $target.map.replace(/ |\?/g, '')).addClass('selected'); $mapContainer.prepend($(' ').addClass('delivery-target')     .css({'left': 'calc(' + $target.x + '%' + ' - ' + (pointSize / 2) + 'px)', 'top': 'calc(' + $target.y + '%' + ' - ' + (pointSize / 2) + 'px)', 'width': pointSize, 'height': pointSize})   );

locationLabel.innerHTML = $target.map;

if ($target.note != undefined){ description.innerHTML=$target.note; }

window.location.hash = name; }; // autcomplete functionality was copied with modification from https://www.w3schools.com/howto/howto_js_autocomplete.asp function postalAutocomplete(inp, arr) { // the autocomplete function takes two arguments, the text field element and an array of possible autocompleted values:

let currentFocus;

// execute a function when someone writes in the text field: inp.addEventListener("input", function(e) {       var a, b, i, val = this.value.toLowerCase;

// close any already open lists of autocompleted values closeAllLists; if (!val) { return false;} currentFocus = -1;

// create a div element that will contain the items (values): a = document.createElement("div"); a.setAttribute("id", "postal-autocomplete-list"); a.setAttribute("class", "postal-autocomplete-items");

// append the div element as a child of the autocomplete container: this.parentNode.appendChild(a);

let results = 0 // for each item in the array... for (i = 0; i < arr.length; i++) { let currentName = arr[i].toLowerCase; if(targets[i].normalized){ currentName = targets[i].normalized.toLowerCase; }         // check if the item starts with or contains the same letters as the text field value: if (currentName.substr(0, val.length) == val || currentName.includes(val)) { // create a div element for each matching element: b = document.createElement("div");

// make the matching letters bold: const index = currentName.indexOf(val); b.innerHTML = arr[i].substr(0, index) + " " + arr[i].substr(index, val.length) + " " + arr[i].substr(index + val.length);

// insert an input field that will hold the current array item's value: // Replace apostrophes with their html entity so they don't end the string b.innerHTML += "";

// execute a function when someone clicks on the item value (DIV element): b.addEventListener("click", function(e) {             // insert the value for the autocomplete text field:              inp.value = this.getElementsByTagName("input")[0].value;

showLocation(document.getElementById("postal-input").value);

// close the list of autocompleted values closeAllLists; });

// Add the suggestion to the list, prioritizing starting with over containing if(index == 0) { // if our input is at the start of the string a.prepend(b); }           else if (results < 10) { // if our input is within the string, but not at the start, and we haven't reached results cap a.append(b); }

results++;

// show no more than 10 suggestions at once if(results >= 10) { a.lastChild.remove; results--; }         }        }    });

// execute a function when a key is pressed: inp.addEventListener("keydown", function(e) {       let x = document.getElementById("postal-autocomplete-list");        if (x) x = x.getElementsByTagName("div");        if (e.keyCode == 40) {          // If the arrow DOWN key is pressed, increase the currentFocus variable:          currentFocus++;          // and make the current item more visible:          addActive(x);        } else if (e.keyCode == 38) {          //If the arrow UP key is pressed, decrease the currentFocus variable:          currentFocus--;          // and make the current item more visible:          addActive(x);        } else if (e.keyCode == 13) {          // If the ENTER key is pressed, prevent the form from being submitted,          e.preventDefault;          if (currentFocus > -1) {            // and simulate a click on the "active" item:            if (x) x[currentFocus].click;          }        }    });

function addActive(x) { // classify an item as "active": if (!x) return false;

//start by removing the "active" class on all items: removeActive(x); if (currentFocus >= x.length) currentFocus = 0; if (currentFocus < 0) currentFocus = (x.length - 1);

// add class "postal-autocomplete-active": x[currentFocus].classList.add("postal-autocomplete-active"); }

function removeActive(x) { // remove the "active" class from all autocomplete items: for (let i = 0; i < x.length; i++) { x[i].classList.remove("postal-autocomplete-active"); }   }

function closeAllLists(elmnt) { // close all autocomplete lists in the document, except the one passed as an argument: let x = document.getElementsByClassName("postal-autocomplete-items"); for (var i = 0; i < x.length; i++) { if (elmnt != x[i] && elmnt != inp) { x[i].parentNode.removeChild(x[i]); }   }  }

// close the autocomplete when someone clicks in the document: document.addEventListener("click", function (e) {     closeAllLists(e.target);  }); } }]);