MediaWiki:Postal map.js

Da Official Temtem Wiki.
Jump to navigation Jump to search

Nota: dopo aver pubblicato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.

  • Firefox / Safari: tieni premuto il tasto delle maiuscole Shift e fai clic su Ricarica, oppure premi Ctrl-F5 o Ctrl-R (⌘-R su Mac)
  • Google Chrome: premi Ctrl-Shift-R (⌘-Shift-R su un Mac)
  • Internet Explorer / Edge: tieni premuto il tasto Ctrl e fai clic su Aggiorna, oppure premi Ctrl-F5
  • Opera: premi Ctrl-F5.
// This was reverse-engineered from https://ark.gamepedia.com/Widget:SpawnMap
 
$( function () {

  if ( !document.getElementById("postal-map") ) return; // Early exit
  
  mw.loader.using('mediawiki.api').then(function() {
    var api = new mw.Api();

    var input = document.createElement("input");
    input.setAttribute("id", "postal-input");
    input.setAttribute("placeholder", "Delivery target");
  
    api.get({
        "action": "parse",
        "format": "json",
        "pageid": 252, // at time of writing, [[Postal_service/data.json]]
        "prop": "wikitext",
        "formatversion": "2"
      }).then(function(data){
      
      var targets = JSON.parse(data.parse.wikitext);

      var $select = $('<select id="postal-dropdown">')
        .append($('<option>').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);
      });
    
      // Create the list of names
      var names = []
      Object.keys(targets).forEach(function(target){
        names.push(String(target));
      });
      names.sort(function(a, b){return a.localeCompare(b);});
      // Add the list of names to the dropdown menu
      names.forEach(function(name) {
        $select.append($('<option>').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
      var urlHash = decodeURIComponent(window.location.hash);
      if (urlHash) {
          input.value = urlHash.substr(1);
          showLocation(input.value);
      }
      
      function showLocation(name) {
        var $mapContainer = $('#postal-map').find('#map-container');
      
        // clear notes
        var description = document.querySelector("#legend-container .description");
        var 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
      
        var $target = targets[name];
        var 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($('<div>').addClass('delivery-target')
          .css({'left': 'calc(' + $target.x + '%' + ' - ' + (pointSize / 2) + 'px)',
            'top': 'calc(' + $target.y + '%' + ' - ' + (pointSize / 2) + 'px)',
            'width': pointSize,
            'height': pointSize})
        );
    
        locationLabel.textContent = $target.map;
    
        if ($target.note != undefined){
          // send this through the parser so that we can allow valid wikitext while disallowing any other html
          api.get({
            "action": "parse",
            "format": "json",
            "text": $target.note,
            "prop": "text",
            "wrapoutputclass": "",
            "disablelimitreport": 1,
            "contentmodel": "wikitext",
            "formatversion": "2"
          }).then(function(data){
           description.innerHTML = data.parse.text;
          });
        }
    
        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:
    
        var currentFocus;
    
        // execute a function when someone writes in the text field:
        inp.addEventListener("input", function(e) {
            var a, b, i, val = this.value.toLowerCase();
    
            var maxResults = 10;
    
            // 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);
    
            // bottomStart is going to point to the bottom element of the half of the list that contains
            // the results that start with the input. We use this to sort this half of the list alphabetically
            var bottomStart = null
            // for each item in the array...
            for (i = 0; i < arr.length; i++) {
              var currentName = arr[i];
              if(targets[currentName].normalized){
                currentName = targets[currentName].normalized;
              }
              currentName = currentName.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:
                var index = currentName.indexOf(val);
                b.appendChild( document.createTextNode( arr[ i ].substr( 0, index ) ) );
                var strong = document.createElement( 'strong' );
                strong.textContent = arr[ i ].substr( index, val.length );
                b.appendChild( strong );
                b.appendChild( document.createTextNode( 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
                var input = document.createElement('input');
                input.type = 'hidden';
                input.value = arr[i];
                b.appendChild(input);
    
                // 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
                  if(!bottomStart){
                    a.prepend(b);
                    bottomStart = b;
                  }
                  else {
                    bottomStart.insertAdjacentElement('afterend', b);
                    bottomStart = b;
                  }
                }
                else if (a.children.length <= maxResults) {
                  // if our input is within the string, but not at the start, and we haven't reached results cap
                  a.append(b);
                }
    
                // show no more than 10 suggestions at once
                if(a.children.length > maxResults) {
                  a.lastChild.remove();
                }
              }
            }
        });
    
        // execute a function when a key is pressed:
        inp.addEventListener("keydown", function(e) {
            var 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 (var 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:
          var 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);
        });
      }
    });
  });
});