MH - Map Re-inviter

Repeat invites for RR

// ==UserScript==
// @name         MH - Map Re-inviter
// @description  Repeat invites for RR
// @author       Maidenless
// @version      1.0.6
// @match        https://www.mousehuntgame.com/*
// @match        https://apps.facebook.com/mousehunt/*
// @icon         https://www.google.com/s2/favicons?domain=mousehuntgame.com
// @resource     https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
// @require      https://code.jquery.com/ui/1.12.1/jquery-ui.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
// @grant        none
// @namespace https://greasyfork.org/users/748165
// ==/UserScript==

//Inject touchpoint
//universal mapIdl
var mapId;

//Shows button 
$(document).ajaxComplete(async(event,xhr,options) => {
    if (options.url == "https://www.mousehuntgame.com/managers/ajax/board/board.php"){
        $(".mi-invite-repeat")[0] ? null : addRepeater();
    }
})


function addRepeater(){
    var injectNode = $(".mousehuntActionButton.tiny.lightBlue.treasureMapView-previewRewardsButton")[0]
    //Somtimes the script fails to cloneNode when switching maps, but does not matter since it was cloned before;
    if (injectNode){
        var inviteNode = injectNode.cloneNode()
    };
    //bunch of CSS
    inviteNode.className = "mi-invite-repeat";
    inviteNode.style.color = "black";
    inviteNode.style.background = "pink";
    inviteNode.style.boxShadow = "1px 1px 1px #eee";
    inviteNode.style.border = "1px solid #000";
    inviteNode.style.borderColor = "#50549c";
    inviteNode.style.borderRadius = "5px"
    inviteNode.style.padding = "3px 5px";
    inviteNode.style.position = "relative";
    inviteNode.style.verticalAlign = "top";
    inviteNode.style.textAlign = "center";
    inviteNode.style.color = "#000!important";
    inviteNode.style.textDecoration = "none";
    inviteNode.style.fontSize = "10px";
    inviteNode.style.fontWeight = "100";
    inviteNode.style.lineHeight = "normal";
    //Mouse over and mouse out function
    inviteNode.onmouseover = function(){
        inviteNode.style.color = "white";
    }
    inviteNode.onmouseout = function(){
        inviteNode.style.color = "black";
    }
    var span = document.createElement("span");
    span.innerText = "Invite +";
    inviteNode.appendChild(span);
    //onclick function
    inviteNode.onclick = async()=>{
        var mapCurrentlyOpened;
        var maps = user.quests.QuestRelicHunter.maps;
        if(maps.length >1){
            mapCurrentlyOpened = $(".treasureMapRootView-tab.active.map")[0].children[1].innerText;
        } else {
            mapCurrentlyOpened = user.quests.QuestRelicHunter.maps[0].name;
        }
        console.log("Map currently opened is " + mapCurrentlyOpened);
        console.log(maps);
        var index = maps.findIndex(item => item.name == mapCurrentlyOpened);
        mapId = maps[index].map_id;
        await getCurrentHunters(mapId)
        .then(res=>{
            render(res);
        })
    }
    //disable if not maptain   
    /*var maptain = $(".treasureMapView-hunter.captain")[0].children[0].children[0].title;
    var username = user.firstname ? user.firstname : user.lastname;
    if (maptain.indexOf(username)<0){
        inviteNode.onclick = function(){
            return;
        }
        inviteNode.style.background = "grey";
    }*/
    injectNode.insertAdjacentElement("afterend",inviteNode);
    //https://stackoverflow.com/questions/46868091/css-trouble-with-displaynone-not-being-recognized
    var displayValue = window.getComputedStyle($(".mi-invite-repeat")[0]).display
    $(".mi-invite-repeat")[0].style.display = "block";
}

async function render(res){
    document
    .querySelectorAll("#mi-repeater-box")
    .forEach(el=>el.remove())

    //Render Box
    var div = document.createElement("div");
    div.id = "mi-repeater-box"
    div.style.backgroundColor = "#F5F5F5";
    div.style.position = "fixed";
    div.style.zIndex = "9999";
    div.style.left = "35vw";
    div.style.top = "20vh";
    div.style.border = "solid 3px #696969";
    div.style.borderRadius = "20px";
    div.style.padding = "10px";
    div.style.textAlign = "center";
    div.style.fontSize = "12px"
    
    //Close button
    const btnDiv = document.createElement("div");
    const closeButton = document.createElement("button", {
        id: "close-button"
    });
    closeButton.textContent = "x";
    closeButton.style.marginLeft = "5px";
    closeButton.style.cursor = "pointer";
    closeButton.style.float = "right";
    closeButton.style.position = "relative";
    closeButton.onclick = function () {
        document.body.removeChild(div); 
    }
    btnDiv.appendChild(closeButton);
    div.appendChild(btnDiv);
        
    //Header
    const toolHeader = document.createElement("div");
    toolHeader.className = "repeater-tool-header";
    toolHeader.textContent = "Map Invite Repeater"
    toolHeader.style.marginTop = "5px";
    toolHeader.style.height = "21px";
    toolHeader.style.textAlign = "Left";
    toolHeader.style.marginLeft = "17px";
    toolHeader.style.fontWeight = "bold";
    toolHeader.style.cursor = "Map Invite Repeater"
    div.appendChild(toolHeader);
    
    //Body
    const toolBody = document.createElement("div");
    toolBody.id = "mi-repeater-tool-body"

    //Current hunters
    var currentHunters = res;

    //Checks for record
    console.log("Getting Saved Hunters info from local storage")
    var savedHunters = localStorage.getItem("mi-repeater");
    if (savedHunters){
        console.log("Saved Hunters info obtained");
        savedHunters = JSON.parse(savedHunters);
        console.log(savedHunters);
        var table = document.createElement("table");
        table.style.margin = "auto";
        for(let i=0; i<savedHunters.length;i++){
            //Check whether the invited hunter is already in the map
            let index = currentHunters.findIndex(item => item.name === savedHunters[i].name);
            //If not, create a table row dedicated to invite the hunter
            if (index <0){
                const row = document.createElement("tr");
                row.style.textAlign = "left";

                const checkBoxTD = document.createElement("td");
                const checkBoxInput = document.createElement("input");
                checkBoxInput.type = "checkbox";
                checkBoxInput.className = "mi-checkbox";
                checkBoxInput.checked = true;
                checkBoxTD.appendChild(checkBoxInput);
                row.appendChild(checkBoxTD);

                const nameTd = document.createElement("td");
                const nameLabel = document.createElement("label");
                nameLabel.innerHTML = savedHunters[i].name;
                nameLabel.htmlFor = "mi-checkbox" + i;
                nameTd.appendChild(nameLabel);
                row.appendChild(nameLabel);
                table.appendChild(row);
            } else {
                console.log("Hunter " + i + " is already on the map");
            }
        }
        toolBody.appendChild(table);
    } else {
        //If no saved hunters
        console.log("No hunters saved in local storage")
    }

    //Save Button & Send Invite Button
    const action = document.createElement("div");
    div.style.width = "200px";
    //Save
    const saveBtn = document.createElement("button");
    saveBtn.textContent = "Save Current Hunters";
    saveBtn.style.cursor = "pointer";
    saveBtn.style.marginTop = "10px";
    saveBtn.onclick = async()=>{
        var stringCurrentHunters = JSON.stringify(currentHunters);
        localStorage.setItem("mi-repeater",stringCurrentHunters);
        alert ("Saved current Hunters in Map");
    }
    action.appendChild(saveBtn);
    
    const inviteBtn = document.createElement("button");
    inviteBtn.textContent = "Invite Hunters";
    inviteBtn.style.cursor = "pointer";
    inviteBtn.style.marginTop = "5px";
    action.appendChild(saveBtn);
    inviteBtn.onclick = async() =>{
        var nameChecked = $(".mi-checkbox");
        var combinedId = []
        for (let i=0;i<nameChecked.length;i++){
            if (nameChecked[i].checked == true){
                console.log(nameChecked[i] + "is checked");
                var nameInvite = $(".mi-checkbox")[i].parentNode.parentNode.children[1].innerHTML
                console.log("Inviting " + nameInvite)
                //Get the snuid from the name
                var index = savedHunters.findIndex(item => item.name == nameInvite);
                var snuid = savedHunters[index].sn_user_id;
                combinedId.push(snuid);
            }
        }
        //only send if there is something to send;
        if(combinedId != ""){
            await sendInvite(combinedId,mapId)
            .then(res=>{
                alert("Sent all map invites");
            })
        }
    }
    action.appendChild(inviteBtn);

    toolBody.appendChild(action);
    div.appendChild(toolBody);
    document.body.appendChild(div);
    dragElement(div,toolHeader)
}

function getCurrentHunters(mapId){
    console.log("Getting current hunters in the map")
    return new Promise (async (resolve,reject)=>{
        await postReq("https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php",
        `sn=Hitgrab&hg_is_ajax=1&action=map_info&map_id=${mapId}&uh=${user.unique_hash}&last_read_journal_entry_id=${lastReadJournalEntryId}`
        ).then(res=>{
            if (!res){
                return;
            } else {
                try{
                    var response = JSON.parse(res.responseText)
                    const mapHunters = response.treasure_map.hunters;
                    if (mapHunters){
                        console.log("Current Hunters info obtained")
                        //check whether hunter is active, if they left their names will still be in the list but their
                        //is_active will be false
                        for(var i=0;i<mapHunters.length;i++){
                            if (mapHunters[i].is_active == false){
                                mapHunters.splice(i,1);
                                i--;
                            }
                        }
                        console.log(mapHunters);
                        resolve(mapHunters);
                    } else {
                        console.log("No hunters on map")
                    }
                        //const stringMapHunters = JSON.stringify(mapHunters);
                        //localStorage.setItem("mi-repeater",stringMapHunters);
                } catch (error){
                    console.log(error)
                }
            }
        })
    })
}

function sendInvite(snuid,mapId){
    console.log("Inviting hunters")
    var combinedId = [];
    for(let i=0;i<snuid.length;i++){
        console.log("Sending to snuid " + snuid[i])
        combinedId = combinedId + "&snuids%5B%5D=" + snuid[i]
    }
    return new Promise ((resolve,reject)=>{
        postReq("https://www.mousehuntgame.com/managers/ajax/users/treasuremap.php",
        `sn=Hitgrab&hg_is_ajax=1&action=send_invites&map_id=${mapId}` + combinedId + 
        `&uh=${user.unique_hash}&last_read_journal_entry_id=${lastReadJournalEntryId}`
       ).then(res=>{
            try{
                var data = JSON.parse(res.responseText);
                if(data.success == "1"){
                    console.log("Sent map invite to hunter")
                } else {
                    alert("Invite failed:\nYou are not the maptain or\nInvite has been sent before or\nMap is full!")
                }
                resolve();
            } catch(error){
                console.log(error)
            }
        })
    })
}

    

function postReq(url, form) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open("POST", url, true);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.onreadystatechange = function () {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
          resolve(this);
        }
      };
      xhr.onerror = function () {
        reject(this);
      };
      xhr.send(form);
    });
  }

  function dragElement(elmnt,dragEl) {
    var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    /*if (elmnt.firstElementChild) {
      // if present, the header is where you move the DIV from:
     elmnt.firstElementChild.onmousedown = dragMouseDown;
    } else {*/
      // otherwise, move the DIV from anywhere inside the DIV:
      dragEl.onmousedown = dragMouseDown;
    //}
  
    function dragMouseDown(e) {
      e = e || window.event;
      e.preventDefault();
      // get the mouse cursor position at startup:
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      // call a function whenever the cursor moves:
      document.onmousemove = elementDrag;
    }
  
    function elementDrag(e) {
      e = e || window.event;
      e.preventDefault();
      // calculate the new cursor position:
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      // set the element's new position:
      elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
      elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }
  
    function closeDragElement() {
      // stop moving when mouse button is released:
      document.onmouseup = null;
      document.onmousemove = null;
    }
}