There are 5 previous versions of this script.
// ==UserScript==
// @name Ikariam City Select Reorder-er
// @author overkill
// @namespace overkill_gm
// @version 0.11
// @description Lets you reorder your cities in the drop down
// @include http://*.ikariam.*/*
// @exclude http://board.ikariam.*
// ==/UserScript==
/*
Homepage: http://userscripts.org/scripts/show/27630
*/
function debug(aMsg) { setTimeout(function() { throw new Error("[debug] " + aMsg); }, 0);}
function getListOfCities(){
var city;
var cities = $x("./option",$('citySelect'));
if (cities.length == 1) { return false; }
for (var i = 0; i < cities.length; ++i) {
idToCity[cities[i].value] = trim(cities[i].innerHTML);
if (cities[i].selected) {
currentCityId = parseInt(cities[i].value,10);
currentCityName = trim(cities[i].innerHTML);
}
city = cities[i].value.toString();
currentCityList.push(city);
}
return true;
}
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].replace(/\D+/g,'');
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);
}
}
// this doesn't quite work the way i want to, but it works, so i'm leaving it alone
function syncListOfCities(){
//debug("syncListOfCities : old " + myCityList);
var n = myCityList.length;
var n2 = currentCityList.length;
//debug("syncing " + n + " to " + n2);
var id, saved_id;
if ((n > 0) && (n == n2)) {
for (var x = 0; x < n2; ++x){
id = currentCityList[x].replace(/\D+/,'');
}
} else {
//debug("syncListOfCities : replaced " + myCityList);
myCityList = currentCityList;
return false;
}
//debug("syncListOfCities : new " + myCityList);
return true;
}
function saveListFromOption(){
//debug("saving list");
var li = $x("./li",$('city_reorder'));
myCityList = [];
for (var i = 0; i < li.length; i++) {
myCityList.push(li[i].id.replace(/^reorder/,''));
}
//debug('saving ' + uneval(myCityList));
GM_setValue('cities_'+server,uneval(myCityList));
}
function moveUp(row){
var clicked = this.parentNode;
var cloned = clicked.cloneNode(true);
var ul = this.parentNode.parentNode;
var li = ul.getElementsByTagName('li');
for (var i = 1; i < li.length; ++i){
if (li[i] == clicked) {
cloned = ul.insertBefore(cloned,li[i-1]);
ul.removeChild(clicked);
spanUp = cloned.childNodes[1];
spanDown = cloned.childNodes[2];
onClick(spanUp, moveUp, false);
onClick(spanDown, moveDown, false);
saveListFromOption();
}
}
return true;
}
function moveDown(row){
var clicked = this.parentNode;
var cloned = clicked.cloneNode(true);
var ul = this.parentNode.parentNode;
var li = ul.getElementsByTagName('li');
for (var i = 0; i < li.length-1; ++i){
if (li[i] == clicked) {
cloned = ul.insertBefore(cloned,li[i+1].nextSibling);
ul.removeChild(clicked);
spanUp = cloned.childNodes[1];
spanDown = cloned.childNodes[2];
onClick(spanUp, moveUp, false);
onClick(spanDown, moveDown, false);
saveListFromOption();
}
}
return true;
}
function stripHTML(s){
return s.replace(/<[^>]*>/g, "");
}
// 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();
}
function getCoordOfCity(){
// check if breadcrumbs correspond to currentCityName
var city = $x(".//*[@class='city']",$('breadcrumbs'));
if (city.length == 1) {
if (city[0].firstChild.nodeValue == currentCityName) {
var x = $('breadcrumbs');
var match = x.innerHTML.match(/\[(.+)\]/); // can't narrow this down any further since it's so inconsistent
//debug(match[1]);
if (match) { cityCoords[currentCityId] = match[1]; }
}
}
}
//rearrange Balances page
function reorderBalances(){
var cities = $x(".//tr",$('balance'));
var n = cities.length;
var 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);
rows[cityName] = cities[i].cloneNode(true);
p.removeChild(cities[i]);
}
for (i = 0; i < n-3; ++i) {
id = myCityList[i].replace(/\D+/g,'');
rows[idToCity[id]].className = (i % 2)? "alt" : "";
p.insertBefore(rows[idToCity[id]],resultRow);
}
}
}
// show options
function showOptions(){
// from score linker
//debug("showing options");
var mybox = node("div", "", { textAlign: "center" });
var opts = '<h3>Reorder</h3>(will automatically save, no need to hit the "Save settings!" button)<br /><ul id="city_reorder" style=\"width:300px; margin-left:auto; margin-right:auto\">';
var id;
//debug("myCityList.length " + myCityList.length);
for (var i = 0; i < myCityList.length ; ++i) {
id = myCityList[i].match(/\d+/);
opts += '<li id="reorder'+ myCityList[i] +'"><span style="padding-left: 10px; padding-right:15px; width:200px">' + idToCity[id] + '</span><span id="up'+id+'">▲</span><span id="down'+id+'" cl>▼</span></li>'+"\n";
}
opts += '</ul>';
mybox.innerHTML = opts;
var pwd = $('options_changePass');
pwd.appendChild(mybox);
//var up = $x('//li[@type="checkbox" and contains(@id,"Score")]');
var ul = $('city_reorder');
var up = ul.getElementsByTagName("span");
//debug("up " + up.length);
for (i = 0; i < up.length; i++) {
if (up[i].id.search(/^up/) != -1) { onClick(up[i], moveUp, false); }
else if (up[i].id.search(/^down/) != -1) { onClick(up[i], moveDown, false); }
//up.onclick = "moveUp('this');";
}
}
/**************************************** HELPER FUNCTIONS *********************************************/
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 duration(seconds){
var x = [Math.floor(seconds / 86400) , Math.floor(seconds/3600) % 24 , Math.floor(seconds/60) % 60 , Math.round(seconds % 60) ];
var y = ['d' , 'h' , 'm' , 's'];
var r = [];
for (var i = 0; i < x.length; ++i){ if (x[i] > 0) { r.push(x[i].toString() + y[i]); } }
return r.join(' ');
}
function distance(r1,r2){
if ((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){
var x1 = r1[0];
var x2 = r2[0];
var y1 = r1[1];
var y2 = r2[1];
return Math.round(Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2))*100)/100;
}
}
return false;
}
function writeTransportBoxHTML(){
var ikNewElement = document.createElement('div');
ikNewElement.id = 'transportBox';
$('container2').appendChild(ikNewElement);
//$('mainview').insertBefore(ikNewElement,$('mainview').firstChild);
var list = $('citySelect');
list = list.previousSibling.childNodes[1];
var optionElems = list.getElementsByTagName('li');
var n_cities = optionElems.length;
var output = '';
var id, coords, d, selected, dOutput;
var curCoords = cityCoords[currentCityId];
for (var i = 0; i < n_cities; ++i) {
id = myCityList[i].replace(/\D+/g,'');
selected = (id == currentCityId) ? ' selected ' : '';
if ((d = distance(curCoords,cityCoords[id])) !== false) { dOutput = ' (' + duration(60*20*(d+1)) + ')'; }
else { dOutput = ''; }
output += '<option value="'+id+'" ' + selected + '>' + idToCity[id] + dOutput + '</option>';
}
$("transportBox").innerHTML = "<form method=\"GET\" action=\"index.php\"><select name=\"destinationCityId\" onchange=\"this.parentNode.submit()\">"+output+"</select><input type=\"hidden\" name=\"view\" value=\"transport\" /></form>";
}
// global variabless
var currentCityName;
var currentCityId;
var currentCityList = []; // pre-re-ordrered list of cities
var idToCity = {};
var server = document.location.toString().split('/')[2];
var myCityList = eval(GM_getValue('cities_'+server,'[]')); // load saved order
var cityCoords = eval(GM_getValue('coords_'+server,'({})')); // load saved coordinates
if (getListOfCities()) {
getCoordOfCity();
syncListOfCities();
writeCitySelectHTML();
// save list
GM_setValue('cities_'+server,myCityList.toSource());
GM_setValue('coords_'+server,cityCoords.toSource());
// special pages
switch(document.body.id) {
case 'options' : showOptions(); break;
case 'finances' : reorderBalances(); break;
}
// transporter code, based on darkyndy's Ikariam: Ikariam Transporter
GM_addStyle(
"" + <><![CDATA[
#cityNav .dropbutton img { position:relative; top:2px; background:none; padding-right:4px; }
#cityNav .optionList img { position:relative; top:2px; background:none; padding-right:4px; }
#transportBox {
position:absolute; left:24px; top:155px;
margin: 0px;
padding: 0px;
}
#transportBox select {
font-size:8pt;
background-color:#fff7e2;
border: 0px none;
margin: 0px;
padding: 0px;
width:44px;
}
#transportBox select:focus { width:auto; }
]]></>);
writeTransportBoxHTML();
}
