Travian: Address book

By dbKiller Last update Jul 3, 2008 — Installed 10,166 times.
// ==UserScript==
// @name           Travian: Address book
// @version        0.2
// @description    (v0.2) Your address book available on every page! see when your buddies are online and send messages faster
// @author         dbKiller
// @email          user9999@gmail.com
// @date           2008-07-02
// @namespace      travian
// @source         http://userscripts.org/scripts/show/29168
// @identifier     http://userscripts.org/scripts/source/29168.user.js
// @include        http://*.travian*.*/*
// @exclude        http://board.travian*.*
// @exclude        http://forum.travian*.*
// @exclude        http://help.travian*.*/*
// @exclude        http://shop.travian*.*
// @exclude        http://www.travian*.*/*
// @exclude        http://*.travian*.*/activate.php*
// @exclude        http://*.travian*.*/ad/*
// @exclude        http://*.travian*.*/ajax.php*
// @exclude        http://*.travian*.*/anleitung.php*
// @exclude        http://*.travian*.*/anmelden.php*
// @exclude        http://*.travian*.*/chat/*
// @exclude        http://*.travian*.*/geschichte.php*
// @exclude        http://*.travian*.*/gutscheine.php*
// @exclude        http://*.travian*.*/hilfe.php*
// @exclude        http://*.travian*.*/impressum.php*
// @exclude        http://*.travian*.*/index.php*
// @exclude        http://*.travian*.*/links.php*
// @exclude        http://*.travian*.*/log*.php*
// @exclude        http://*.travian*.*/manual.php*
// @exclude        http://*.travian*.*/spielregeln.php*
// @exclude        http://*.travian*.*/support.php*
// @exclude        http://*.travian*.*/tutorial.php*
// ==/UserScript==
/* 
 * This script is licensed under the Attribution-Noncommercial-Share Alike 3.0 Unported License. 
 * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
 */


//set global variables
var SCRIPT = {
	url: 'http://userscripts.org/scripts/source/29168.user.js',
	version: '0.2'
};
var server = location.hostname;
var suffix;
var lang = new Array();
var image = new Array();
var listDefaultPosition = '4px_570px';  //top_left
var listWidth = 200;
var minListWidth = 200;
var dom = new DOMUtils();

//launch main function after doc is loaded
window.addEventListener('load', main, false);


//main function
function main()
{
	var html = document.body.innerHTML;
	if (html.indexOf(' <!-- ERROR ITEM CONTAINER') != -1) window.location.reload();
	
	//create unique suffix
	var ownerId = getOwnerId();
	if (ownerId) suffix = server+'_'+ownerId;
	else return;
	
	//load languages
	loadLanguage();
	
	//load images
	loadImage();
	
	//create list
	createAddressBook();
	
	//check for updates
	updateScript(SCRIPT);
}


//retrieve owner id
function getOwnerId()
{
	var user = dom.xs('//table[@id="navi_table"]//a[starts-with(@href, "spieler.php?uid=")]');
	var id = (user) ? getParamFromUrl(user.href, 'uid') : '';
	return id;
}


//load language
function loadLanguage()
{
	var ext = server.substring(server.lastIndexOf('.')+1);
	
	
	//English (default)
	lang['ADDRESSBOOK'] = 'Address book';
	lang['DRAG'] = 'Drag';
	lang['MINIMIZE'] = 'Minimize';
	lang['MAXIMIZE'] = 'Maximize';
	lang['NEW_VERSION'] = 'A new version of "Address book" is available';
	lang['UPDATE_NOW'] = 'Update now';
	lang['PLAYER_PROFILE'] = 'Player profile';
	lang['SEND'] = 'Send message';
	
	switch(ext) {
		case 'it': //Italian, translation by dbKiller
			lang['ADDRESSBOOK'] = 'Lista contatti';
			lang['DRAG'] = 'Trascina';
			lang['MINIMIZE'] = 'Riduci';
			lang['MAXIMIZE'] = 'Ingrandisci';
			lang['NEW_VERSION'] = 'E\' disponibile una nuova versione di "Address book"';
			lang['UPDATE_NOW'] = 'Aggiornare adesso';
			lang['PLAYER_PROFILE'] = 'Profilo giocatore';
			lang['SEND'] = 'Invia messaggio';
			break;
	}
}


//load images
function loadImage()
{
	image['minimize']='R0lGODlhDAAMAIAAAGBgYP///yH5BAEAAAEALAAAAAAMAAwAAAINjI+py+0PG5hU0RrzKwA7';
	image['maximize']='R0lGODlhDAAMAIAAAGBgYP///yH5BAEAAAEALAAAAAAMAAwAAAIVjI+pCe2N3osKUHZzsPhwLTnLSBoFADs%3D';
	image["letter"] = 'iVBORw0KGgoAAAANSUhEUgAAAAsAAAAICAYAAAAvOAWIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QsKFws6qttDxQAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAAAkUlEQVQY05XQTUpDQRAE4K8yz9BuPEduEH8C2Tw8haeT3CQbPZEiIeNmhLdIAvamqerqaqqDdxxwcr0mvAWv+MYHfi4I13hErXCuqmOSp9batFS11qYk26o64gzzmCXJPsl64DvskYHn1cKo995PvfdnPOBl5OjLa/PY3qEGtxm9Bh/MfwG/8Hkj4Bb3+c/rfgHKwRzhskmMfQAAAABJRU5ErkJggg==';
}


//create list
function createAddressBook()
{
	//create list-wrapper div
	var listDiv = dom.cn('div');
	listDiv.id = 'addressBook_'+suffix;
	listDiv.style.zIndex = 666;
	listDiv.style.clear = 'both';
	listDiv.style.position = 'relative';
	listDiv.style.width = listWidth+'px';
	//listDiv.style.height = '263px';
	listDiv.style.backgroundColor = '#FFFFFF';
	listDiv.style.border = '1px solid #C0C0C0';
	//add list to page
	document.body.appendChild(listDiv);
	
	//create title div
	var titleDiv = dom.cn('div');
	titleDiv.style.height = '18px';
	titleDiv.style.width = (listWidth-12)+'px'; //-12px minDiv width
	titleDiv.style.cssFloat = 'left';
	titleDiv.style.fontWeight = 'bold';
	titleDiv.style.fontSize = '10';
	titleDiv.style.textAlign = 'center';
	titleDiv.style.borderBottom = '1px solid #C0C0C0';
	titleDiv.style.backgroundColor = '#FFFFFF';
	titleDiv.style.backgroundImage = 'url(img/un/a/c2.gif)';
	titleDiv.title = lang['DRAG'];
	titleDiv.style.cursor = 'move';
	titleDiv.style.MozUserSelect = 'none';
	titleDiv.appendChild(dom.ct( lang['ADDRESSBOOK'] ));
	makeDraggable(listDiv, titleDiv);
	
	//create minimize/maximize list div
	var minDiv = dom.cn('div');
	minDiv.style.height = '18px';
	minDiv.style.width = '12px';
	minDiv.style.cssFloat = 'left';
	minDiv.style.borderBottom = '1px solid #C0C0C0';
	minDiv.style.backgroundColor = '#FFFFFF';
	minDiv.style.backgroundImage = 'url(img/un/a/c2.gif)';
	
	//append bar divs
	listDiv.appendChild(titleDiv);
	listDiv.appendChild(minDiv);
	
	//get list
	var listBody = dom.cn('div', '<a href="nachrichten.php?t=1"><img border="0" src="/img/un/a/friends.gif" style="width: 48px; height: 29px; margin:13px 75px 10px 75px;"/></a>');
	listBody.id = 'addressBookBody';
	listBody.style.width = '100%';
	listBody.style.cssFloat = 'left';
	listBody.style.clear = 'both';
	listBody.style.position = 'relative'; 
	listDiv.appendChild(listBody);
	
	//update list position
	var listCoords = GM_getValue('addressBook_'+suffix, '');
	if (!listCoords) {
		listCoords = listDefaultPosition; //default value
		GM_setValue('addressBook_'+suffix, listDefaultPosition);
	}
	listCoords = listCoords.split('_');
	listDiv.style.top = listCoords[0];
	listDiv.style.left = listCoords[1];
	listDiv.style.position = 'absolute';
	listDiv.style.zIndex = 666;
	
	//minimize/maximize list
	var listIsMinimized = GM_getValue('minimize_'+suffix);
	if (!listIsMinimized) {
		listIsMinimized = false; //default value
		GM_setValue('minimize_'+suffix, listIsMinimized);
	}
	if (listIsMinimized) {
		listBody.style.display = 'none';
		listDiv.style.height = '18px';
		listDiv.style.width = minListWidth+'px';
		titleDiv.style.width = (minListWidth-12)+'px'; //-12px minDiv width
		if (dom.id('adressbuch')) listBody.firstChild.style.display = 'none';
		var img = makeEventMaximize(titleDiv);
		minDiv.appendChild(img);
		//remove bar bottom border
		titleDiv.style.borderBottom = 'none';
		minDiv.style.borderBottom = 'none';
	} else {
		listBody.style.display = '';
		// listDiv.style.height = '263px';
		// listDiv.style.width = listWidth+'px';
		if (dom.id('adressbuch')) listBody.firstChild.style.display = '';
		var img = makeEventMinimize(titleDiv);
		minDiv.appendChild(img);
		//populate listBody
		getAddressBook();
	}
}


//get address book from nachrichten.php?t=1 page
function getAddressBook()
{
	var url = document.URL;
	url = url.substring(0, url.lastIndexOf('/')+1);
	url = url+'nachrichten.php?t=1';
	GM_xmlhttpRequest({
		method: 'GET',
		url: url,
		onload: function (responseDetails)
				{
					if (responseDetails.status != 200) return;
					var response = responseDetails.responseText;
					var div = dom.cn('div', response);
					var ansDoc = document.implementation.createDocument('', '', null);
					ansDoc.onload = ansDoc.appendChild(div);
					
					// get original adressbuch
					var addressBook = ansDoc.getElementById('adressbuch');
					
					//create contacts arrays
					var uidArray = new Array();
					var nameArray = new Array();
					var iconArray = new Array();
					
					//iterate over td elements of addressBook
					var tdArray = addressBook.getElementsByTagName('td');
					for (var i=0; i < tdArray.length; i++) {
						
						if (tdArray[i].className == 'addr1') {
							//get player's uid from "img" onclick attribute
							var imgEl = tdArray[i].getElementsByTagName('img')[0];
							if (imgEl) {
								var onclickTxt = imgEl.getAttribute('onclick');
								var uid = onclickTxt.substring(onclickTxt.lastIndexOf(',')+2, onclickTxt.lastIndexOf("'"));
								uidArray[uidArray.length] = uid;
							}
						} else if (tdArray[i].className == 'addr2') {
							//get player's name from "a" element
							var aEl = tdArray[i].getElementsByTagName('a')[0];
							if (aEl) {
								var name = aEl.firstChild.nodeValue;
								nameArray[nameArray.length] = name; 
							}
						} else if (tdArray[i].className == 'addr3') {
							//get player's status
							var imgEl = tdArray[i].getElementsByTagName('img')[0];
							if (imgEl) {
								iconArray[iconArray.length] = imgEl; 
							}
						}
					}
					
					//create contacts table
					var contactsTable = dom.cn('table');
					contactsTable.id = 'contactsTable';
					contactsTable.setAttribute('cellspacing', '1');
					contactsTable.setAttribute('cellpadding', '1');
					contactsTable.style.borderCollapse = 'collapse';
					contactsTable.style.width = '100%';
					contactsTable.style.cssFloat = 'left';
					contactsTable.style.clear = 'both';
					contactsTable.style.position = 'relative'; 
					//create tbody
					var tbody = dom.cn('tbody');
					//add contacts
					for (var i=0; i < uidArray.length; i++) {
						var tr = dom.cn('tr');
						if (i != uidArray.length-1) tr.style.borderBottom = '1px solid #C0C0C0';
						//player name
						var td = dom.cn('td');
							var a = dom.cn('a', nameArray[i]);
							a.href = 'spieler.php?uid=' + uidArray[i];
							a.title = lang['PLAYER_PROFILE'];
							td.appendChild(a);
						tr.appendChild(td);
						//send message
						var td = dom.cn('td');
						td.setAttribute('align', 'center');
						td.style.width = '20px';
							var igmlink = dom.cn('a', "<img src='data:image/gif;base64," + image["letter"] + "' style='margin:3px 0px 1px 3px; display: inline' title='" + lang['SEND'] + "' border=0>");
							igmlink.href = 'nachrichten.php?t=1&id=' + uidArray[i];
							td.appendChild(igmlink);
						tr.appendChild(td);
						//status
						var td = dom.cn('td');
						td.appendChild(iconArray[i]);
						td.setAttribute('align', 'center');
						td.style.width = '20px';
						tr.appendChild(td);
						//append row
						tbody.appendChild(tr);
					}
					//append tbody
					contactsTable.appendChild(tbody);
					
					//append list
					var addressBookBody = dom.id('addressBookBody');
					if (uidArray.length > 0) {
						addressBookBody.removeChild(addressBookBody.firstChild);
						addressBookBody.appendChild(contactsTable);
					}
				}
	});
}


//create minimize event
function makeEventMinimize(titleDiv)
{
	var img = dom.cn('img');
	img.title = lang['MINIMIZE'];
	img.style.width = '12px';
	img.style.height = '12px';
	img.style.paddingTop = '3px';
	img.style.cursor = 'pointer';
	img.src = 'data:image/png;base64,'+image['minimize'];
	img.addEventListener('click', foo=function(){minimizeList();}, false);
	titleDiv.addEventListener('dblclick', bar=function(){minimizeList();}, false);
	return img;
}


//create maximize event
function makeEventMaximize(titleDiv)
{
	var img = dom.cn('img');
	img.title = lang['MAXIMIZE'];
	img.style.width = '12px';
	img.style.height = '12px';
	img.style.paddingTop = '3px';
	img.style.cursor = 'pointer';
	img.src = 'data:image/png;base64,'+image['maximize'];
	img.addEventListener('click', foo=function(){maximizeList();}, false);
	titleDiv.addEventListener('dblclick', bar=function(){maximizeList();}, false);
	return img;
}


//minimize list
function minimizeList()
{
	GM_setValue('minimize_'+suffix, true);
	reloadAddressBook();
}


//maximize list
function maximizeList()
{
	GM_setValue('minimize_'+suffix, false);
	reloadAddressBook();
}


//reload list
function reloadAddressBook()
{
	var oldList = dom.id('addressBook_'+suffix);
	if (oldList) {
		oldList.parentNode.removeChild(oldList);
	}
	createAddressBook();
}


/************************ from Drag n drop******************************/
// by Risi http://userscripts.org/
var mouseOffset = null;
var iMouseDown  = false;
var lMouseState = false;
var dragObject  = null;
var curTarget   = null;
function mouseCoords(ev){
	return {x:ev.pageX, y:ev.pageY};
}
function getMouseOffset(target, ev){
	var docPos  = getPosition(target);
	var mousePos  = mouseCoords(ev);
	return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
function getPosition(e){
	var left = 0;
	var top = 0;
	while (e.offsetParent){
		left += e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
		top += e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);
		e   = e.offsetParent;
	}
	left += e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
	top  += e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);
	return {x:left, y:top};
}
function mouseMove(ev){
	var target = ev.target;
	var mousePos = mouseCoords(ev);
	if (dragObject){
		dragObject.style.position = 'absolute';
		dragObject.style.top  = (mousePos.y - mouseOffset.y) +'px';
		dragObject.style.left   = (mousePos.x - mouseOffset.x) +'px';
	}
	lMouseState = iMouseDown;
	return false;
}
function mouseUp(ev){
	if (dragObject) {
		setOption(dragObject.id, dragObject.style.top +'_'+ dragObject.style.left);
	}
	dragObject = null;
	iMouseDown = false;
}
function mouseDown(ev){
	var target = ev.target;
	iMouseDown = true;
	if (target.getAttribute('DragObj')){
		return false;
	}
}
function makeDraggable(parent, item){
	document.addEventListener('mousemove', mouseMove, false);
	document.addEventListener('mousedown', mouseDown, false);
	document.addEventListener('mouseup', mouseUp, false);
	if (!parent||!item) return;
	item.addEventListener('mousedown',function(ev){
		dragObject  = parent;
		mouseOffset = getMouseOffset(parent, ev);
		return false;
	}, false);
}
function setOption(key, value) {
	GM_setValue(key, value);
}
/************************ end Drag n drop*******************************/


/************************ from QP Targets*****************************/
// from QP of http://userscripts.org/
/**
* getParamFromUrl
* @param {String} url The string of the URL
* @param {String} urlParam The param being searched in the URL
*/
function getParamFromUrl(url, urlParam) {
	var res = "&" + url.substring(url.indexOf("?") + 1); //exclude "?" and before that
	var searchStr = "&" + urlParam + "=";
	var pos = res.indexOf(searchStr);
	if (pos != -1) {
		res = res.substring(res.indexOf(searchStr) + searchStr.length);
		var endPos = (res.indexOf("&") > res.indexOf("#")) ? res.indexOf("&") : res.indexOf("#");
		if (endPos != -1) {
			res = res.substring(0, endPos);
		}
		return res;
	} else {
		return;
	}
}
/************************ end QP Targets *****************************/


/************************* from FranMod *****************************/
function DOMUtils(doc, ctxt, html) {
	this.cn = function(tag, html) {
		var elem = this.document.createElement(tag);
		if (html) elem.innerHTML = html;
		return elem;
	}

	this.ct = function(text) {
		return this.document.createTextNode(text);
	}

	this.id = function(id) {
		return this.document.getElementById(id);
	}

	this.tag = function(tag) {
		return this.document.getElementsByTagName(tag);
	}

	this.xs = function(xpath) {
		var res = this.document.evaluate(xpath, this.context, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
		return res.singleNodeValue;
	}

	this.xa = function(xpath) {
		var arr = [];
		var xpr = this.document.evaluate(xpath, this.context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
		for (var i = 0; item = xpr.snapshotItem(i); i++)
			arr.push(item);
		return arr.length == 0? null: arr;
	}

	this.xo = function(xpath) {
		var ret = this.document.evaluate(xpath, this.context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		return ret; //no snapshot
	}

	if (!doc) doc = document;
	if (!ctxt) ctxt = doc;
	if (html) {
		this.document = doc.implementation.createDocument('', '', null);
		this.context = doc.createElement('div');
		this.context.innerHTML = html;
	        ansDoc.appendChild(this.context);
	}
	else {
		this.document = doc;
		this.context = ctxt;
	}
}
/************************** end FranMod *****************************/


//update the script
function updateScript(SCRIPT) {

	var d = new Date();
	var t = d.getTime();
	var lastUpdate = parseInt(GM_getValue('lastUpdate',0));
	if (t-lastUpdate >= 1000*60*60*24) {
		
		GM_xmlhttpRequest({
			method: 'GET',
			url: SCRIPT.url + '?source', // don't increase the 'installed' count just for checking
			onload: function(result) {
				if (result.status != 200) return;
				if (!result.responseText.match(/@version\s+([\d.]+)/)) return;
				var theOtherVersion = parseFloat(RegExp.$1);
				if (theOtherVersion <= parseFloat(SCRIPT.version)) {
					return;
				} else {
					if (window.confirm(lang['NEW_VERSION']+' (v'+theOtherVersion+')!\n\n'+lang['UPDATE_NOW']+'?\n')) {
						GM_openInTab(SCRIPT.url);
					}
				}
			}
		});
		
		GM_setValue('lastUpdate',t+'');
	}
}