There are 14 previous versions of this script.
var scriptMetadata = parseMetadata(<><![CDATA[
// ==UserScript==
// @name Ikariam City Select Reorder-er
// @author overkill
// @namespace overkill_gm
// @version 3.7
// @description Lets you reorder your cities in the drop down
// @homepage http://userscripts.org/scripts/show/27630
// @include http://s*.ikariam.*/index.php*// ==/UserScript==
]]></>.toString());
function parseMetadata(a){var b=a.split(/[\r\n]+/).filter(/\/\/ @/);var c={include:[],exclude:[]};for each(var d in b){[d,name,value]=d.match(/\/\/ @(\S+)\s*(.*)/);if(c[name]instanceof Array)c[name].push(value);else c[name]=value}return c}
function debug() { var msg = []; for (var i = 0, n = arguments.length; i<n; ++i) msg.push(arguments[i]); setTimeout(function() { throw new Error("[debug] " + msg.join(' ')); }, 0);}
function stripHTML(s){ return s.replace(/<[^>]*>/g, ""); }
function onClick(node, fn, capture, e) { node.addEventListener((e||"") + "click", fn, !!capture); }
function node(type, className, styles, content) {
var n = document.createElement(type||"div");
if (className) n.className = className;
if (styles) for (var prop in styles) n.style[prop] = styles[prop];
if (content) n.innerHTML = "string" == typeof content ? content : content.toXMLString();
return n;
}
function $(id) { return document.getElementById(id); }
function $x( xpath, root ) {
var doc = root ? root.evaluate ? root : root.ownerDocument : document, next;
var got = doc.evaluate( xpath, root||doc, null, 0, null ), result = [];
switch (got.resultType) {
case got.STRING_TYPE:
return got.stringValue;
case got.NUMBER_TYPE:
return got.numberValue;
case got.BOOLEAN_TYPE:
return got.booleanValue;
default:
while (next = got.iterateNext())
result.push( next );
return result;
}
}
function $X( xpath, root ) { var got = $x( xpath, root ); return got instanceof Array ? got[0] : got; }
function trim(str) {
str = str.replace(/^\s\s*/, '');
var ws = /\s/;
var i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
}
function in_array(needle, haystack) { for (var key in haystack) if (haystack[key] == needle) return true; return false; }
function durationHMS(seconds,depth){
var temp = unsafeWindow.LocalizationStrings['timeunits']['short'], ret = [], prefix = '';
if (seconds == 0) { return '0'; }
else if (seconds < 0) { seconds = -seconds; prefix = '-'; }
var x = [ Math.floor(seconds / 86400) , Math.floor(seconds/3600) % 24 , Math.floor(seconds/60) % 60 , Math.ceil(seconds % 60) ];
var y = [ temp.day , temp.hour , temp.minute, temp.second ];
for (var i = 0; i < x.length; ++i){ if (x[i] != 0) { ret.push(x[i].toString() + y[i]); } }
if (depth && depth<ret.length) return prefix + ret.slice(0,depth).join(' ');
else return prefix + ret.join(' ');
}
function distance(r1,r2){
if (r1 && r2 && (typeof r1 == "string") && (typeof r2 == "string")) { // uhm, has to be a better way of doing this
r1=r1.split(':');
r2=r2.split(':');
if (r1.length && r2.length) return Math.round(Math.sqrt(Math.pow(r1[0]-r2[0],2) + Math.pow(r1[1]-r2[1],2))*100)/100;
}
return false;
}
function generateSelfCache(){
var cache = {};
for each (var town in $x('./option',$('citySelect'))){
if (town.innerHTML.charAt(0) == '[') { //todo: move this if statement outside the loop
// COORDS in town navigation
cache[town.value] = {
'name' : town.innerHTML.replace(' ',' ').replace(/\[[0-9:\s]+\]\s+/,''),
'position' : town.innerHTML.match(/\[([0-9:\s]+)\]/,'')[1].replace(/00/g,'100'),
'tradegood': town.title.substring(12)
};
} else {
// TRADE GOOD in town navigation
var coords = town.title;
coords = coords.substr(1,coords.length-2);
cache[town.value] = {
'name':town.innerHTML,
'position':coords,
'tradegood':unsafeWindow.LocalizationStrings['resources'][town.className.charAt(town.className.indexOf('tradegood')+9)]
};
}
}
return cache;
}
function writeCitySelectHTML(){
var optionParent = $('citySelect');
var optionElems = $x('./option',optionParent);
var liParent = optionParent.previousSibling.childNodes[1];
var liElems = liParent.getElementsByTagName('li');
var oldOptions = {};
var oldLis = {};
var n_cities = optionElems.length;
var id, newLi;
for (var i = n_cities-1; i >= 0; --i) {
oldOptions[optionElems[i].value] = optionElems[i].cloneNode(true);
newLi = liElems[i].cloneNode(true);
newLi.className = newLi.className.replace(/( first)|( last)|( active)/g,'');
oldLis[optionElems[i].value] = newLi;
optionParent.removeChild(optionElems[i]);
liParent.removeChild(liElems[i]);
}
for (i = 0; i < n_cities; ++i) {
id = myCityList[i];
optionParent.appendChild(oldOptions[id]);
newLi = oldLis[id];
if (id == currentCityId) { newLi.className += ' active'; }
if (i == 0) { newLi.className += ' first'; }
if (i == n_cities-1) { newLi.className += ' last'; }
onClick(newLi, selectCity, false);
liParent.appendChild(newLi);
}
}
// called when a new city is chosen. rewrites the citySelect form and submits it
function selectCity(event){
var optionParent = $('citySelect');
var optionElems = $x('./option',optionParent);
var liParent = optionParent.previousSibling.childNodes[1];
var liElems = liParent.getElementsByTagName('li');
var n_cities = optionElems.length;
var x = 0;
while ((x < n_cities) && (this != liElems[x])) { ++x; }
if (x >= n_cities) {
alert("An error has occured. Please Disable this script and contact the author.");
return;
}
//debug(this.parentNode.parentNode.parentNode.parentNode.parentNode);
for (var i = n_cities-1; i >= 0 ; --i) {
optionElems[i].selected = i == x;
}
//debug(active.className);
var active = optionParent.previousSibling.childNodes[0];
var newClass = liElems[x].className.match(/tradegood./);
if (newClass) { active.className = "avatarCities "+newClass[0]+" dropbutton"; }
active.innerHTML = liElems[x].innerHTML;
// don't bother changing title
var form = this.parentNode.parentNode.parentNode.parentNode.parentNode; // errr... this is silly =P
form.submit();
}
///////////////////////////////////////// START OPTIONS
function moveUp(){
var clicked = this.parentNode;
clicked.parentNode.insertBefore(clicked,clicked.previousSibling);
saveListFromOption();
}
function moveDown(){
var clicked = this.parentNode;
clicked.parentNode.insertBefore(clicked,clicked.nextSibling.nextSibling);
saveListFromOption();
}
// will add content to the OPTIONS page in place-th place (optional) and encapsulate it in a div. returns the DIV element of the options
function addOptionsToPage(content,place){
place = place || 5; // place must be > 0 and a number
var parentElem = $('options_changePass').parentNode; // an arbitrary element with an id was chosen
return parentElem.insertBefore(node("div", "", { textAlign: "center" },content),$X('./div['+place+']',parentElem));
}
function showOptions(){
var element, id;
var opts = '<h3>Reorder Towns v'+scriptMetadata['version']+' (by <a href="http://userscripts.org/users/53907">Overkill</a>)</h3><i>(will automatically save, no need to hit the "Save settings!" button)</i><br /><ul id="city_reorder" style="width:300px; margin:3px auto;">';
for (var i = 0; i < myCityList.length ; ++i) {
id = myCityList[i];
opts += '<li id="reorder'+ myCityList[i] +'"><span>' + selfCache[id].name + '</span><span class="ok_up">▲</span><span class="ok_down">▼</span></li>';
}
opts += '</ul>Put Transport Helper<select>';
opts += '<option' + ((transporterContainer == '') ? ' selected' : '') + ' value="">disabled</option>';
opts += '<option' + ((transporterContainer == 'globalResources') ? ' selected' : '') + ' value="globalResources">top</option>';
opts += '<option' + ((transporterContainer == 'mainview') ? ' selected' : '') + ' value="mainview">bottom</option>';
opts += '<option' + ((transporterContainer == 'Overkill Bar') ? ' selected' : '') + '>Overkill Bar</option>';
opts += '</select>';
var newDiv = addOptionsToPage(opts,3);
for each (element in $x('.//span[@class="ok_up"]' ,newDiv)){ onClick(element,moveUp); }
for each (element in $x('.//span[@class="ok_down"]',newDiv)){ onClick(element,moveDown); }
//onClick($X('.//select',newDiv),saveListFromOption);
$X('.//select',newDiv).addEventListener("change", saveListFromOption, false);
GM_addStyle('#city_reorder span:first-child { display:inline-block; width: 200px; }');
GM_addStyle('#city_reorder span + span { cursor: pointer; }');
}
function saveListFromOption(){
//debug("saving list");
myCityList = [];
var li = $x("./li",$('city_reorder'));
for (var i = 0; i < li.length; i++)
myCityList.push(parseInt(li[i].id.replace(/^reorder/,''),10));
//debug('saving ' + uneval(myCityList));
//debug('saving use_bar ' + $X('..//select',$('city_reorder')).value);
GM_setValue('cities_'+server,uneval(myCityList));
GM_setValue('use_bar',$X('..//select',$('city_reorder')).value);
}
///////////////////////////////////////// END OPTIONS
//rearrange Balances page
function reorderBalances(){
var cities = $x(".//tr",$('balance'));
var n = cities.length;
var row, rows = {};
var cityName, id, p;
if ((n > 3) && (n == myCityList.length+3)) {
var resultRow = cities[n-2];
p = cities[0].parentNode;
for (var i = n-3; i > 0; --i) {
cityName = trim(cities[i].getElementsByTagName('td')[0].innerHTML);
if (!rows[cityName]) rows[cityName] = p.removeChild(cities[i]); // if multiple cities have the same name, ignore after the 1st city
}
for (i = 0; i < myCityList.length; ++i) {
if (row = rows[selfCache[myCityList[i]].name]){
row.className = (i % 2)? "alt" : "";
p.insertBefore(row,resultRow);
}
}
}
}
function writeTransportBoxHTML(){
var output = '', id, d, selected, dOutput;
for (var i = 0,n = myCityList.length; i < n; ++i) {
id = myCityList[i];
selected = (id == currentCityId) ? ' selected ' : '';
dOutput = ((d = distance(selfCache[currentCityId].position,selfCache[id].position)) !== false) ? ' (' + durationHMS(Math.max(1200*d,600)) + ')' : '';
output += '<option value="'+id+'"' + selected + '>' + selfCache[id].name + dOutput + '</option>';
}
var html = "<form method='get' action='index.php' style='float:right;'><select id='overkillTransport' name='destinationCityId' onchange='this.parentNode.submit()'>"+output+"</select><input type=\"hidden\" name=\"view\" value=\"transport\" /></form>";
switch (transporterContainer) {
case 'mainview' :
GM_addStyle("#overkillTransport { background:wheat; font-size:8pt; border: 0 none; margin:0; padding:0; height:15px; }");
GM_addStyle("#overkillTransport option { padding: 0; }");
$(transporterContainer).appendChild(node('div','',{position:'absolute'},html));
break;
case 'globalResources' :
GM_addStyle("#overkillTransport { background:wheat; font-size:8pt; border: 0 none; margin:0; padding:0; height:15px; }");
GM_addStyle("#overkillTransport option { padding: 0; }");
$(transporterContainer).appendChild(node('div','',{position:'absolute',top:'-11px'},html));
break;
case 'Overkill Bar' :
GM_addStyle("#overkillTransport { font-size:8pt; border: 0 none; margin: 0 0 0 4px; padding:0; height:15px; }");
GM_addStyle("#overkillTransport option { padding: 0; }");
var barTab = overkillBar(html+'Transport');
overkillBar_add(barTab,'<a href="'+scriptMetadata['homepage']+'">Version: '+scriptMetadata['version']+'</a>');
overkillBar_add(barTab,'<a href="/index.php?view=options#city_reorder">Change Options</a>');
break;
}
}
if ($('servertime') && unsafeWindow.IKARIAM){
// global variabless
var server = document.domain;
var currentCityId = parseInt($X('//select[@id="citySelect"]/option[@selected]').value,10);
var selfCache = generateSelfCache();
var myCityList = eval(GM_getValue('cities_'+server,[])); // load saved order
var transporterContainer = GM_getValue('use_bar','globalResources');
// reconcile saved list of cities with current list of cities
var change = false;
for (var i = myCityList.length-1; i>=0; --i)
if (!selfCache[myCityList[i]]) { myCityList.splice(i,1); change = true; }
for (var id in selfCache) {
id = parseInt(id,10);
if (!in_array(id,myCityList)) { myCityList.push(id); change = true; }
}
if (change) GM_setValue('cities_'+server,uneval(myCityList));
writeCitySelectHTML();
if (document.body.id == 'finances') reorderBalances();
else if (document.body.id == 'options') showOptions();
if (transporterContainer) writeTransportBoxHTML();
}
/*
OVERKILL BAR -- add everything below this to script to enable the overkill bar. Add a new tab and initialize the bar with
var tab = overkillBar('tab title');
*/
function overkillBar(title){
if (!$('overkillBar')){
var div = node('div','','','<ul></ul>');
div.id = "overkillBar";
document.body.appendChild(node('div','',{"height":"3em;"},' '));
document.body.appendChild(div);
var ul = $X('./ul',div);
ul.appendChild(node('li','','','<h2 style="font-weight:bold;">OVERKILL</h2><ul><li><a href="http://userscripts.org/users/53907/scripts">Homepage</a></li></ul>'));
//test
//styleBar();
//production
GM_addStyle('#overkillBar ul{margin:0;padding:0;border:0;list-style-type:none;display:block}#overkillBar ul li{margin:0;padding:0;border:0;display:block;float:left;position:relative;z-index:5}#overkillBar ul li:hover{z-index:10000}#overkillBar ul li li{float:none}#overkillBar ul ul{visibility:hidden;position:absolute;z-index:10;left:0;bottom:0}#overkillBar ul li:hover>ul{visibility:visible;bottom:100%}#overkillBar ul li li:hover>ul{bottom:0;left:100%}#overkillBar ul:after,#overkillBar ul ul:after{content:".";height:0;display:block;visibility:hidden;overflow:hidden;clear:both}#overkillBar ul ul{ background:none;padding:30px 30px 10px 30px;margin:0 0 -10px -30px}#overkillBar ul ul ul{padding:30px 30px 30px 10px;margin:0 0 -30px -10px}#overkillBar{ position:fixed; bottom:0px; width:100%; z-Index:10}#overkillBar h2{ font-size:14px}#overkillBar ul{color:#eee;background:#234}#overkillBar ul ul li{color:#eee;background:#234; font-size:smaller}#overkillBar ul ul{width:15em}#overkillBar ul a{text-decoration:none;color:#eee;padding:.4em 1em;display:block;position:relative}#overkillBar ul a:hover,#overkillBar ul li:hover>a{color:#fc3}#overkillBar ul li{ padding:3px; white-space:nowrap}#overkillBar ul li{border:1px solid #ccc}#overkillBar ul>li+li{border-left:0}#overkillBar ul ul>li+li{border-left:1px solid}#overkillBar ul ul>li+li{border-top:0}#overkillBar ul li li:hover>ul{bottom:5px;left:90%}#overkillBar em{ font-style:italic}');
}
var ul = $X('./ul',$('overkillBar'));
var tab = ul.appendChild(node('li','','','<h2>'+title+'</h2>'));
return tab.appendChild(node('ul','','',''));
}
function overkillBar_add(barTab,content){
return barTab.appendChild(node('li','','',"string" == typeof content ? content : content.toXMLString()));
}
function overkillBarOptions(barTab){
var gameServer = document.domain.replace(/ikariam\./,'');
this.save = function(){
var copy = {};
for (thing in this)
if ((typeof this[thing] !== 'function') && (typeof this[thing] !== 'object'))
copy[thing] = this[thing];
//debug("save : "+uneval(copy));
GM_setValue('_okbarOptions_'+gameServer,uneval(copy));
}
this.setTab = function(barTab){
this.barTab = barTab;
}
this.addInput = function(label,defaultValue){
var options = this;
var labelName = stripHTML(label);
//debug(label + ' ' + labelName);
if (!options[labelName]) { options[labelName] = defaultValue || ''; }
var ctrl = options.barTab.appendChild(node('li','',{cursor:'pointer'},label+': '+(options[labelName]?options[labelName]:'not set')));
onClick(ctrl,function(){
var newValue = prompt('New '+labelName,options[labelName]);
if (newValue !== null) options[labelName] = newValue;
this.innerHTML = label+': '+(options[labelName]?options[labelName]:'not set');
options.save();
});
}
this.addCB = function(label,defaultValue){
var options = this;
var labelName = trim(stripHTML(label));
//debug(label + ' ' + labelName);
if (typeof options[labelName] != 'boolean') { options[labelName] = !!defaultValue; }
var ctrl = options.barTab.appendChild(node('li','',{cursor:'pointer'},label+' '+(options[labelName]?'✓':'')));
onClick(ctrl,function(){
options[labelName] = !options[labelName];
this.innerHTML = label+' '+(options[labelName]?'✓':'');
options.save();
});
}
this.barTab = barTab;
var options = eval(GM_getValue('_okbarOptions_'+gameServer),{});
for (thing in options) this[thing] = options[thing];
}
