Lex_The_Great / InkMods

// ==UserScript==
// @name         InkMods
// @license      MIT
// @copyright    2017, Lex_The_Great (https://openuserjs.org/users/Lex_The_Great)
// @namespace    https://www.reddit.com/r/inkarnate/
// @updateURL    https://openuserjs.org/meta/Lex_The_Great/InkMods.meta.js
// @version      1.5.4
// @description  Inkarnate Mods!
// @author       Lex_The_Great
// @include      http*://*/maps*
// @require      http://code.jquery.com/jquery-latest.js
// @require      https://openuserjs.org/src/libs/sizzle/GM_config.js
// @require      https://gist.githubusercontent.com/PizzaBrandon/5709010/raw/e539a6f16c10465eb948b9ef6b0fe1d4c17a7c3e/jquery.waituntilexists.js
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_webRequest
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==
// Some reason /^(.*)\/maps\#\/(.*)$/ doesn't work so we will use *....

function isFireFox() {
  //Check if browser is Firefox or not
  if (navigator.userAgent.search("Firefox") >= 0)
    return true;
  return false;
}

function injectScript(text) {
  var newScript = document.createElement('script');
  newScript.type = "text/javascript";
  newScript.textContent = text;
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(newScript);
}

function injectMods(text) {
  // Inject MapSize Editor
  text = text.replace(/!function\(t,e\){/g, 'var xsize=1024;var ysize=768;if(localStorage.getItem("mapX")!==undefined&&localStorage.getItem("mapY")!==undefined){console.log("Debug:Settingsize:"+xsize+":"+ysize);xsize=localStorage.getItem("mapX");ysize=localStorage.getItem("mapY");}window.constX=xsize;window.constY=ysize;!function(t,e){');
  text = text.replace(/width:e,height:i,/g, 'width:constX,height:constY,');
  //text = text.replace(/this\.w=1024\*this\.s\.map\.scale,this\.h=1024\*this\.s\.map\.scale,/g, 'this.w=constX*this.s.map.scale,this.h=constY*this.s.map.scale,');
  //text = text.replace(/width:t\.map\.width\*t\.map\.scale,height:t\.map\.height\*t\.map\.scale/g, 'width:constX*t.map.scale,height:constY*t.map.scale');
  //text = text.replace(/e.attr\(\{width:1024\*t\.map\.scale,height:1024\*t\.map\.scale}\),/g, 'e.attr({width:constX*t.map.scale,height:constY*t.map.scale}),');
  text = text.replace(/"fantasy-world",1024,768/g, '"fantasy-world",constX,constY');
  // Comercial Support
  text = text.replace(/"fantasy-world-2x",1024,768/g, '"fantasy-world-2x",constX,constY');
  // ImageHijack
  text = text.replace(/r\.src=i,/g, 'r.hijack(i),');

  /* Debug
  text = text.replace(/console\.log\("loaded",e\)/g, 'console.log("loaded",e,i)');
  text = text.replace(/console\.log\("loading",e\)/g, 'console.log("loading",e,i)');
  text = text.replace(/console\.log\("texture load",n\)/g, 'console.log("texture load",n,s)');
  text = text.replace(/console\.log\("texture loaded",n\)/g, 'console.log("texture loaded",n,s)');
  */
  // Todo something else usefull..

  injectScript(text);
}

Image.prototype.hijack = function (newval) {
  if (newval.search("ocean-01") > 0) {
    if (localStorage.getItem("BackgroundImage") !== null && localStorage.getItem("BackgroundImage") !== '') {
      newval = localStorage.getItem("BackgroundImage");
      console.log("Hijacked Background: " + newval);
    }
  }
  this.src = newval;
};

var InkMods = {
  Config: false,
  ConfigOpen: false,
  Button: $('<div id="InkModsMenu">Settings</div>'),

  init: function () {
    this.Config = GM_config.init({
      'id': 'Inkarnate',
      'fields': {
        'Init': {
          'label': 'Init (Hidden)',
          'type': 'checkbox',
          'default': false
        },
        'LargeMode': {
          'label': 'Move around UI to work with Large Maps. (Will break Map Selection Menu!)<br>',
          'type': 'checkbox',
          'default': false
        },
        'MapX': {
          'label': 'Map Width (When creating new map.)<br>',
          'type': 'int',
          'min': 1024,
          'default': 1024
        },
        'MapY': {
          'label': 'Map Height (When creating new map.)<br>',
          'type': 'int',
          'min': 768,
          'default': 768
        },
        'BackgroundImage': {
          'label': 'Background Image, Blank for defualt. (When creating new map.)<br>',
          'type': 'text',
          'default': ''
        }
      },
      'events': {
        'init': function () {
          window.InkMods.onInit(this);
        },
        'open': function () {
          console.log('onOpen()');
        },
        'save': function () {
          window.InkMods.onSave(this);
        },
        'close': function () {
          window.InkMods.onClose(this);
        },
        'reset': function () {
          window.InkMods.setupStorage(this, true);
          console.log('onReset()');
        }
      },
      'css': '#Inkarnate_Init_var { display: none !important; }'
    });
  },
  setupStorage: function (cfg, reset) {
    console.log("InkMods: Init Storage.");
    if (!cfg.get("Init") || reset === true || GM_info.script.version !== localStorage.getItem("Version")) {
      console.log("InkMods: New Storage.");
      cfg.set("Init", true);
      cfg.save();

      localStorage.setItem("Version", GM_info.script.version);
      localStorage.setItem("LargeMode", false);
      localStorage.setItem("mapX", 1024);
      localStorage.setItem("mapY", 768);
      localStorage.setItem("BackgroundImage", '');
    }
  },

  onInit: function (cfg) {
    this.setupStorage(cfg);

    console.log('onInit()');
    this.Button.css({
      "position": "fixed",
      "right": "100px",
      "bottom": "10px",
      "border": "1px solid #6b5326",
      "padding": "5px 10px",
      "color": "orange",
      "cursor": "pointer",
      "z-index": "99999"
    });
    this.Button.insertAfter("#fb-root");

    var p = this;
    this.Button.click(function () {
      if (p.ConfigOpen)
        return;

      p.ConfigOpen = true;
      cfg.open();
    });
  },

  onClose: function (cfg) {
    console.log('onClose()');
    this.ConfigOpen = false;
  },

  onSave: function (cfg) {
    console.log('onSave()');
    this.Options.MapSize(cfg.get("MapX"), cfg.get("MapY"));
    this.Options.BackgroundImage(cfg.get("BackgroundImage"));
    this.Options.LargeMode(cfg.get("LargeMode"));
  },

  Options: {
    MapSize: function (x, y) {
      if (typeof x === 'number' && isFinite(x) && typeof y === 'number' && isFinite(y)) {
        localStorage.setItem("mapX", x);
        localStorage.setItem("mapY", y);
        constX = x;
        constY = y;
      }
    },
    BackgroundImage: function (url) {
      localStorage.setItem("BackgroundImage", url);
    },
    LargeMode: function (flag) {
      localStorage.setItem("LargeMode", flag);

      if (flag && this.style === undefined) {
        console.log("Injected Styles.");
        this.style = GM_addStyle('#map-builder-view { position: absolute; }' +
          '.map-builder-container { position: absolute; width: auto; left: 80px;}' +
          '#left-sidebar, #tool-options, #logo-menu, #selected-tool { position: fixed; z-index: 999;}' +
          '#tool-options, #selected-tool { left: 22%;}' +
          '#logo-menu { left: 1px; top: 20px;}' +
          '#left-sidebar { left: 10px; top: 15%;}');
      }
      else if (!flag && this.style !== undefined) {
        this.style.remove();
        this.style = undefined;
      }
    }
  }
};

function doMenu() {
  $(window).load(function (e) {
    if (typeof (Storage) !== "undefined") {
      console.log("InkMods: Init");
      window.InkMods = InkMods;
      window.InkMods.init();
      window.InkMods.Options.LargeMode((localStorage.getItem("LargeMode") == 'true'));
    }
    else {
      console.log("InkMods: Error, Storage is undefined.");
    }

    if (!$("#logo-menu").length) {
      console.log("InkMods: Debug: Can't find #logo-menu. (Page loaded to fast?) " + $("#logo-menu").length);
      return;
    }

    $("#ui").waitUntilExists(function (e) {
      $("#map-container > canvas").css({
        width: constX + 'px',
        height: constY + 'px'
      });
    });

      $("#objects > ul").waitUntilExists(function (e) {
          $("#objects > ul").css({
              overflow: 'scroll'
          });
      });
      $("#textures > ul").waitUntilExists(function (e) {
          $("#textures > ul").css({
              overflow: 'scroll'
          });
      });
  });
}
window.doMenu = doMenu;

if (isFireFox()) {
  console.log("Mozzila!");

  window.addEventListener('beforescriptexecute', function (e) {
    src = e.target.src;
    if (src.search(/map-builder-app(.*)\.js/) != -1) {
      e.preventDefault();
      e.stopPropagation();
      console.log("Block: " + e.target.src);
      window.mapjs = e.target.src;

      GM_xmlhttpRequest({
        method: "GET",
        url: window.mapjs,
        synchronous: true,
        onload: function (response) {
          console.log("Hijacked: " + window.mapjs);
          injectMods(response.responseText);
          GM_xmlhttpRequest({
            method: "GET",
            url: "https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-route.js",
            onload: function (response) {
              console.log("Hijacked: " + e.target.src);
              injectScript(response.responseText);
              window.doMenu();
            }
          });
        }
      });
    }

    if (src.search(/angular-route(.*)\.js/) != -1) {
      e.preventDefault();
      e.stopPropagation();
    }
  });
}
else {
  console.log("Something else?");
  alert("You're not using firefox. Chrome doesn't have beforescriptexecute.");
  // Going to need to edit this file your self if you have crhome. Chrome doesn't have a working interceptor :( basicly replaces are above. Host on your own local server. Do not redistrubute inkarnate!
  // Also, put in userscript above for chrome!
  // @webRequest   [{"selector":"*/assets/map-builder-app*.js","action":{"redirect":"https://localhost/map-builder-app.js"}}]
  GM_webRequest([{
    selector: '*/assets/map-builder-app*.js',
    action: {
      redirect: 'https://localhost/map-builder-app.js'
    }
  }, ], function (info, message, details) {
    console.log(info, message, details);
  });
}