//
// ==UserScript==
//
// @name IkaTweaks
// @description Improvements for Ikariam
// @version 2.1
// @author Yvonne P.
// @license MIT; https://opensource.org/licenses/MIT
// @icon http://de.ikariam.gameforge.com/favicon.ico
// @namespace YveOne
// @include /^https?:\/\/s\d+-\w+\.ikariam\.gameforge\.com.*?$/
// @run-at document-start
//
// @downloadURL none
// ==/UserScript==
//
/* jshint esversion: 6 */
/* global $ */
/* global ikariam */
/* global ajax */
/* global GM_info */
/* global dataSetForView */
/* global LocalizationStrings */
(function(window){
"use strict";
var jshintUnused;
//--------------------------------------------------------------------------------------------------
// CONSTANTS
const _LINKS_ = {
OnePiece : 'http://www.iconarchive.com/show/one-piece-character-icons-by-crountch.html',
GreasyFork : 'https://greasyfork.org/de/scripts/401313-ikatweaks',
OpenUserJS : 'https://openuserjs.org/scripts/YveOne/IkaTweaks',
GitHubRepo : 'https://github.com/YveOne/Userscript-IkaTweaks',
};
// CONSTANTS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// SYSTEM FUNCTIONS
function forEach(obj, func) {for(var k in obj){if(obj.hasOwnProperty(k)){func(obj[k],k,obj);}}}
function jsonDecode(str, dflt) {var obj=null;try{obj=JSON.parse(str);}catch(e){}return((obj!==null)?obj:dflt);}
function injectCSS(cssText) {var el=document.createElement('style');el.setAttribute('type','text/css');if(el.styleSheet){el.styleSheet.cssText=cssText;}else{el.appendChild(document.createTextNode(cssText));}document.querySelector('head').appendChild(el);return el;}
function hookFunction(obj, fn, cb) {(function(of){obj[fn]=function(){var ret=of.apply(this,arguments);cb.apply(this,[ret,of,arguments]);return ret;};}(obj[fn]));}
function waitFor(cond, func, tOut, sleep) {sleep=sleep||33;var tEnd=tOut?(new Date()).getTime()+tOut:null;var ret,w4=function(){ret=cond();if(ret){return func(ret);}if(tEnd && tEnd<(new Date()).getTime()){return func(false);}setTimeout(w4,sleep);};w4();}
function removeElement(el) {try{return el.parentNode.removeChild(el);}catch(e){}return null;}
// v3 (c) Yvonne P.
function LocalStorageHandler(tag) {
var data = JSON.parse(localStorage.getItem(tag)) || {
storedKeys : {},
};
function dataUnset(k1) {
if(data) {
var s = {};
forEach(data.storedKeys, (_, k2) => {
if (k1 !== k2) {
s[k2] = data.storedKeys[k2];
}
});
data.storedKeys = s;
localStorage.setItem(tag, JSON.stringify(data));
}
}
function dataSet(k) {
if (data) {
data.storedKeys[tag] = (new Date()).getTime();
data.storedKeys[k] = (new Date()).getTime();
localStorage.setItem(tag, JSON.stringify(data));
}
}
this.drop = function(key) {
key = tag+key;
localStorage.removeItem(key);
dataUnset(key);
return (typeof localStorage.getItem(key) == 'undefined');
};
this.save = function(key, val) {
key = tag+key;
localStorage.setItem(key, val);
dataSet(key);
return (localStorage.getItem(key) == val);
};
this.load = function(key, dflt) {
key = tag+key;
var v = localStorage.getItem(key);
return (v!==null ) ? v : dflt;
};
this.data = function() {
return JSON.parse(JSON.stringify(data));
};
this.clear = function(t) {
var b = true;
if (typeof t == 'string') {
var s = [t];
forEach(data.storedKeys, (_, k) => {
s.push(' "'+k+'"');
});
b = confirm(s.join("\n"));
}
if (b) {
forEach(data.storedKeys, (_, k) => {
localStorage.removeItem(k);
});
data = null;
return true;
}
return false;
};
}
// v2 (c) Yvonne P.
function EasyTemplates() {
var that = this;
var tplList = {};
var regExpParseHtml = new RegExp('\\{[a-zA-Z0-9_]+\\}', 'gi');
this.set = function(id, html) {
tplList[id] = html;
};
this.get = function(id, data) {
id = id || '';
return (tplList[id]) ? that.parse(tplList[id], data) : 'Template "'+id+'" not found';
};
this.getEach = function(arr, func) {
var ret = [];
var keys = Object.keys(arr);
while(keys.length)
{
var k = keys.shift();
var a = func(k, arr[k]);
if(a) ret.push(that.get.apply(null, a));
}
return ret.join('');
};
this.parse = function(html, data) {
html = html || '';
data = data || {};
return html.replace(regExpParseHtml, function(x){
var y = data[x.substr(1, x.length-2)];
return (y!==null && typeof y!='undefined') ? y : x;
});
};
}
// v3 (c) Yvonne P.
function LanguageHandler(useLocal, baseLocal)
{
var str = {};
var ctr = {};
var als = {};
function get(k) {
return (typeof str[k]=='string') ? str[k] : k;
}
function set(c, l, n) {
if (c instanceof Array) {
while(c.length)
{
set(c.shift(), n);
}
return;
}
if (als[c] == useLocal) {
c = als[c];
}
ctr[c] = l;
if (c == baseLocal) {
forEach(n, (v, k) => {
if (v !== null) {
str[k] = (typeof str[k]=='string') ? str[k] : v.toString();
}
});
} else {
if (c == useLocal) {
forEach(n, (v, k) => {
if (v !== null) {
str[k] = v.toString();
}
});
}
}
}
var ret = function() {
if(arguments.length==1) return get.apply(null, arguments);
if(arguments.length==3) return set.apply(null, arguments);
return str;
};
ret.codes = function() {
return JSON.parse(JSON.stringify(ctr));
};
ret.alias = function(a, b) {
als[a] = b;
};
ret.local = function() {
return useLocal;
};
return ret;
}
const TPL = new EasyTemplates();
const LS = new LocalStorageHandler('IkaTweaks_');
const LANG = LanguageHandler(LS.load('LANG', location.hostname.match(/s\d+\-(\w+)\.ikariam\.gameforge\.com/i)[1]), 'en');
// SYSTEM FUNCTIONS
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// HTML: Select DropDown
TPL.set('SelectContainer', `
`);
TPL.set('SelectOption', `
`);
function SelectDropDown(selectId, size, options, selected) {
this.val = function() {
return $(`#js_${selectId}Options`).val();
};
this.tpl = function() {
return TPL.get('SelectContainer', {
selectSize : size,
selectId : selectId,
selectOptions : TPL.getEach(options, function(c, n){
return ['SelectOption', {
value : c,
text : n,
selected: (selected == c) ? 'selected="selected"' : '',
}];
}),
});
};
}
// HTML: Select DropDown
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// IkaTweaks CORE
const IkaTweaks = {};
(function(IkaTweaks){
var enabledModules = jsonDecode(LS.load('modules'), {});
var definedModules = {};
var sidebarButtons = [];
function loadModule(modId) {
var modData = jsonDecode(LS.load(modId), {});
definedModules[modId].func(modData, function() {
LS.save(modId, JSON.stringify(modData));
});
}
IkaTweaks.injectCSS = function(css, cb, sl) {
sl = sl || 33;
waitFor(function(){
return document.querySelector('head');
}, function(){
(cb||function(){})(injectCSS(css));
}, 2000, sl);
};
const mainViewIcon = 'https://raw.githubusercontent.com/YveOne/Userscript-IkaTweaks/master/images/mainViewIcon.png';
IkaTweaks.injectCSS(`
#IkaTweaks_sidebar1 .centerButton .button {width:200px;margin:2px 0px;}
#IkaTweaks_sidebar2 .centerButton .button {width:200px;margin:2px 0px;}
#IkaTweaks_c:before,
#UpdateChecker_c:before {
content: url('${mainViewIcon}');
}
/** extend h3 header **/
.contentBox01h .header.hidden {
overflow: hidden;
height: 0px;
padding-top: 7px;
}
/** fix research window list **/
ol.research_type {
width: 220px !important;
}
/** fix city select **/
.dropdownContainer.city_select li.last-child {
background-position: left -142px !important;
padding-bottom: 3px;
}
.dropdownContainer.city_select li.last-child:hover{
background-position: left -196px !important;
}
/** increase view top padding from 10 to 20, looks better **/
#container .mainContentBox .mainContent {
padding-top: 20px !important;
}
/** fix h4 width, margin on right side **/
#container .satisfaction_overview .sub_header, #container .notices h4 {
margin: 0 3.5px 0 3px;
}
/** fix townhall view div right margin **/
#townHall .population_graph {
margin: 0 3.5px 0 3px;
}
/** fix scrollbar x position **/
#container .scroller {
background-position-x: -1px !important;
}
/** fix scroll window margin top **/
#container .mainContentBox .mainContentScroll {
margin-top: -0.5px;
}
/** fix scroll area margin right to parent view window **/
#container .scroll_area {
margin-right: 3px;
}
#container .scroll_area.scroll_disabled {
margin-right: 0px;
}
`);
IkaTweaks.setModule = function(modId, modFunc) {
if(typeof enabledModules[modId] == 'undefined') enabledModules[modId] = false;
definedModules[modId] = {
name: `{str_${modId}_name}`,
info: `{str_${modId}_info}`,
func: modFunc,
};
if(enabledModules[modId]) {
loadModule(modId);
}
IkaTweaks.injectCSS(`
#${modId}_c:before {
content: url('${mainViewIcon}');
}
`);
};
IkaTweaks.addSidebarButton = function(btnText, btnFunc, useTop) {
sidebarButtons.push({text:btnText,func:btnFunc,useTop:useTop});
};
IkaTweaks.changeHTML = function(id, html, cb) {
waitFor(function(){
try{return ikariam.controller;}catch(e){}
return false;
}, function(n){
if(!n || n===null) return;
if(n.ajaxResponder===null){n.ajaxResponder=ikariam.getClass(ajax.Responder);}
html = TPL.get('IkaTweaksFrame', {
version : GM_info.script.version,
mainview: html,
buttons1: TPL.getEach(sidebarButtons, function(i, btn){
if(!btn.useTop) return null;
return ['IkaTweaksSidebar_button', {
btnId: 'IkaTweaksSidebar_button'+i,
btnText: btn.text
}];
}),
buttons2: TPL.getEach(sidebarButtons, function(i, btn){
if(btn.useTop) return null;
return ['IkaTweaksSidebar_button', {
btnId: 'IkaTweaksSidebar_button'+i,
btnText: btn.text
}];
}),
});
html = TPL.parse(html, LANG());
n.ajaxResponder.changeHTML([id,html], true);
setTimeout(ikariam.controller.adjustSizes, 1000);
var sidebarButtonsLength = sidebarButtons.length;
for(var i=0; i