Return to Snippet

Revision: 10341
at February 21, 2009 13:10 by preasha


Updated Code
// ==UserScript==
// @name           WKW-ElemGrabber
// @namespace      http://dev.3muskeeters.com
// @description    Grabs birthday dates of all your buddies
// @include		   http://www.wer-kennt-wen.de/events/calendar/year/*
// ==/UserScript==

/*
	- Grabs birthday dates, saves them in an Array ( key: BDAY00000 -> value: SURNAME NAME--X--DD-MM )
*/

//--------------------------------------------------------------------------------------
//	Some obvious prototyping
//--------------------------------------------------------------------------------------
//
//
//	@method	Checks wether a key already exists (using the double equal as log. op.)
//
Array.prototype.contains = 	function(strKey)
							{
								for (key in this)
								{
									if (key == strKey)
									{
										return true;
									}
								}
								return false;
							}
//
//	@method	Counts all contained (associative) keys
//
Array.prototype.getLength =	function()
							{
								var i = 0;
								for each (k in this)
								{
									if (typeof(k) != "function")
									{
										i++;
									}
								}
								return i;
							}
//							
//--------------------------------------------------------------------------------------						
//--------------------------------------------------------------------------------------
//
//	@name 		CElementGrabber()
//	@class		Baseclass for the whole grabbing thing.
//
function CElementGrabber()
{
	var aTempNodes = new Array(); // holds all requested resources
	var addElement, getElement, dumpElements;	// Dummy declaration, used by following closure
	
	(	// BEGIN GETTER/SETTER CLOSURE

		function()
		{
			var grabbedElements = new Array();
			
			//
			// @name	addElement(key, value)
			// @method	Setter for array of grabbed elements
			// @params	nothing to explain; only key has to be != null/undefined
			//
			addElement = 	function(key, value)
					{
						try 
						{
							if (key) 
							{
								//GM_log("addElement( " + key + " ,  " + value + " );");
								grabbedElements[key] = value;
							}
							else 
							{
								throw new TypeError("Invalid element was returned from XPath query");
							}
						}
						catch (error)
						{
							alert(error.name + ": " + error.message);
						}
					};
			//
			// @name	getElement(index)
			// @method	Getter for array of grabbed elements
			// @params	key:	the key that should be returned; if key is omitted,
			//					a whole "copy" of grabbedElements is being returned
			//		
			getElement = 	function(key)
							{	
								// no index passed => return complete "copy" of array
								if (key == undefined)
								{
									return	(
												function(tmp)
												{
													//GM_log("     getElement(undefined):  WHOLE ARRAY");
													return tmp;
												}
									
											)(grabbedElements);
								}
								// valid index passed 
								else if ((typeof(key) == "string") && key)
								{
									//GM_log("getElement( " + key + " ):  " + grabbedElements[key]);
									return grabbedElements[key];
								}
								// invalid parameter
								else
								{
									return null;
								}
								
							};
							
			dumpElements = 	function()
							{
								//GM_log("Listing the content of grabbedElements:\n\n");
								for (key in grabbedElements)
								{
									GM_log("grabbedElements[ " + key + "] = " + grabbedElements[key])
								}
							};
		}
	)()	// END GETTER/SETTER CLOSURE
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	dump()
	// @method	Privileged method, lists all grabbed Elements in error console
	//
	this.dump = function()
				{
					dumpElements();
				}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------			
	//
	// @name	grab(strRule, strURL)
	// @method	privileged method; Executes a XPath query to the current document, if nodes are found
	//			the given callback function is called with argsCallback as argument
	// @params	strRule: string, xpath query to execute
	//			aUrlList: array, contains all urls that should be filtered
	// 
	this.grab = function(strXPathExpr, aUrlList)
	{
		//GM_log("ENTER grab");
		try 
		{
			if (!!aUrlList)	// when a url list is passed
			{
				for (var i = 0; i < aUrlList.length; i++) 
				{
					if (!load(aUrlList[i], filterElements, [strXPathExpr]))	// when load() wasn't successfull
					{
						throw new Error("Error occured while loading url: " + aUrlList[i]);
					}
				}
				//alert("All urls in aUrlList loaded");
			}
			else	// only the current document should be filtered
			{
				filterElements(strXPathExpr);
			}
		} 
		catch (error) 
		{
			alert("grab()->try-statement:   " + error.name + ": " + error.message);
			return false;
		}
		//GM_log("LEAVE grab");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------	
	//
	// @name	filterElements(strURL, strExpression)
	// @method	callback function; Gets called through load(), applies a passed xpath to the 
	//			current document and passes each matched node to getBDayDetails()
	// @params	strURL:	string, the current url
	//			strExpression:	string, xpath to apply
	//
	function filterElements(strURL, aArgs)
	{
		//GM_log("ENTER filterElements");
		var result = document.evaluate(	aArgs[0],
										aTempNodes[aArgs[1]],
										null,
										XPathResult.ORDERED_NODE_ITERATOR_TYPE,
										null
										);
		var currentNode =  
		{
			count: 1,
			node: result.iterateNext()		
		};
		
		while (currentNode.node)
		{
 			// there are nodes in result to iterate through
			try
			{
 				getBDayDetails(currentNode.node, currentNode.count, strURL);
				currentNode.count++;
				currentNode.node = result.iterateNext();
			}
			catch (error)
			{
				alert("filterElements()->try-statement:   " + error.name + ": " + error.message);
				return false;
			}
		}
		if (aArgs[1] == 11)
		{
			startInjecting();
		}
		return true;
		//GM_log("LEAVE filterElements");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	getBDayDetails(nodeCapture, numIndex, strURL)
	// @method	Callback function; Gets captured node, index of that node and some optionally passed
	//			in arguments in a string.
	// @params	nodeCapture: 	dom-node, the captured node
	//			numIndex:		number, the index of the node inside the whole captured collection
	//			aPassedArgs:	array, the optionally passed in arguments
	//	
	function getBDayDetails(nodeCapture, numIndex, strURL)
	{
 
		var aBirthday = new Array();
		var nodecollSpans = nodeCapture.parentNode.parentNode.parentNode.getElementsByTagName("span");
		for (var i = 0; i < nodecollSpans.length; i++)
		{
			if (nodecollSpans[i].getAttribute("class") == "day")
			{
				aBirthday["day"] = nodecollSpans[i].childNodes[0].nodeValue;
 				i = nodecollSpans.length;
			}
			
		}
 
		var aREReturn = /^http:\/\/www\.wer-kennt-wen\.de\/events\/calendar\/year\/(\d{4,4})\/month\/(\d{1,2})/.exec(strURL);
		
		// month
		aBirthday["month"] = aREReturn[2];
 		// year
		aBirthday["year"] = aREReturn[1];
 		// name of birthday child
		if (nodeCapture.hasAttribute("title"))	// birthday of a buddy
		{
			if (nodeCapture.getAttribute("title").length) 
			{
				// using unicode-ranges cause some dumbasses are using "funny" symbols
				// i am wondering why the wkw-team permitted those characters
				aBirthday["who"] = /([\u0000-\uFFFF]+)\swird\s\d{2,3}/.exec(nodeCapture.getAttribute("title"))[1];
			}
		}
		else	// thats my own birthday, returning
		{
			return false;
		}
 
		//GM_log("     Capture #" + numIndex + "/" + getElement("BDAY-COUNTER") + ":   " + aBirthday["who"] + " -> " + aBirthday["day"] + "-" +	aBirthday["month"] + "-" + aBirthday["year"]);
		
		if (parseInt(getElement("BDAY-COUNTER")) >= 0) 
		{
			// bday counter already exists, so we increment him by one
			addElement("BDAY-COUNTER", parseInt(getElement("BDAY-COUNTER")) +  1);
		}
		else
		{
			// bday coutner doesnt exist, so we create him
			addElement("BDAY-COUNTER", 1);
		}
		//GM_log("     Current BDay-Counter: " + getElement("BDAY-COUNTER"));
		
		addElement(("BDAY" + decorateNumber(getElement("BDAY-COUNTER"), 5)), (aBirthday["who"] + "--X--" + aBirthday["month"] + "-" + aBirthday["day"]));
 
 
		return true;
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	decorateNumber(numInput, templength)
	// @method	private method, takes a string and "fills" him up with zeros up to a legth
	//			specified by numLength. If the passed in string is already longer than numLength
	//			it will be returned without any modification.
	// @params	numInput: 	string, number that should be decorated
	//			numLength:	number, the length numInput should be filled up to
	//	
	function decorateNumber(numInput, numLength)
	{
		if (numInput.toString().length < numLength) {
			
			var strTemp = new String();
			for (var i =0; i < numLength - String(numInput).length; i++)
			{
				strTemp += "0";
			}
			return strTemp + numInput.toString(); 
		} 
		else
		{
			return numInput;
		}

	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	loadURL(strURL, cbFunc, aCbArgs)
	// @method	private method; Requests the resource at the given url
	// @params	strURL:	str, url to request
	//			cbFunc: function ref; callback function thats gonna be passed through
	//			aCbArgs: array; arguments that are gonna be passed through
	//
	function load(strURL, cbFunc, aCbArgs)
	{
		//GM_log("ENTER load");
		if (new RegExp(/http\:\/\/[\w0-9-_\.@\/\+\?]+/).test(strURL)) 
		{
			var objReqDetails = {
				method: "GET",
				url: strURL,
				headers: {
					"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4)",
					"Accept": "application/atom+xml,application/xml,text/xml",
					"Referer": "http://www.wer-kennt-wen.de/events/calendar",
					"Cookie": document.cookie.split(/__utma=.*;\s(?=__utma=)/)[1],
					"Accept-Language": "de-de,en-us;q=0.7,en;q=0.3",
					"Accept-Encoding": "gzip,deflate",
					"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
					"Keep-Alive": "300",
					"Connection": "keep-alive"
				},
				onerror: handleReqError,
				onreadystatechange: function(respDetails)
									{
										if (respDetails.readyState == 4) 
										{
											interpretRespData(respDetails, strURL, cbFunc, aCbArgs);
										}
									}
			};
			GM_xmlhttpRequest(objReqDetails);
			//GM_log("LEAVE grab");
			return true;
		}
		else
		{
			alert("load: You gave me an invalid url");
			//GM_log("LEAVE grab");
			return false;
		}
	}



	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	interpretRespData(responseDetails, strURL, cbFunc, aCbArgs)
	// @method	Joins the properties contained in responseDetails, and alerts the result
	// @params	responseDetails: object, details about the request process
	//			strURL: string; url of requested resource -> passed through
	//			cbFunc: callback function; passed through
	//			aCbArgs: array; arguments for callback function -> passed through
	//
	function interpretRespData(responseDetails, strURL, cbFunc, aCbArgs)
	{
		/*
		GM_log("ENTERED interpretRespData");
		GM_log("     interpretRespData-> complete. The request is completed and all response data is available in other fields");
		GM_log("     interpretRespData-> HTTP-Status: " + responseDetails.statusText);
		GM_log("     interpretRespData-> Response headers: " + responseDetails.responseHeaders);
		GM_log("     interpretRespData-> Status: " + responseDetails.status);
		*/
		
		var currIndex = changeDocElement(responseDetails.responseText);
		aCbArgs.push(currIndex)
		cbFunc(strURL, aCbArgs);
		
		//GM_log("LEAVING interpretRespData");
	}


	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	function handleReqError(responseDetails)
	{
		//GM_log("ENTERED handleReqError");

		var strMsg = 	"handleReqError-> During the request/response an error occured.\n" + 
						"handleReqError-> Status text: " + responseDetails.statusText;
		alert(strMsg);
		
		//GM_log("LEAVING handleReqError");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	changeDocElement(strInnerHTML)
	// @method	private method; replaces the current body with the one in strInnerHTML
	// @params	strInnerHTML:	string; contains the new html code
	//	
	function changeDocElement(strInnerHTML)
	{
		var currIndex = aTempNodes.push(document.createElement("div")) - 1;
		aTempNodes[currIndex].innerHTML = /(\x3Cbody[\s\u0000-\uFFFF]*?\x3E)([\s\u0000-\uFFFF]*)(\x3C\/body\x3E)/.exec(strInnerHTML)[2];
		return currIndex;
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------	
	this.save = function()
	{

		// checking for bday counter inside the greasemonkey space
		if (getData("BDAY-COUNTER") == null) 
		{
			// bday coutner doesnt exist, so we create him
			saveData("BDAY-COUNTER", 0);
		}
		
		var numGrabbedElements = parseInt(getElement("BDAY-COUNTER"));
		
		if (numGrabbedElements != NaN)
		{
			alert("     grabbedElements.length = " + getElement().getLength());	
			alert("     numGrabbedElements = " + numGrabbedElements);
			
			//dumpElements();
			
			for (var i=1; i <= numGrabbedElements; i++)
			{
				alert("i: " + i + "  /  " + decorateNumber(i, 5));
				var strTmpKey = "BDAY" + decorateNumber(i, 5);
				alert(strTmpKey);
				var tmpValues = {	key: strTmpKey,
									value: getElement(strTmpKey)
									};
				GM_log("     Saving: " + tmpValues.key + " -> " + tmpValues.value);
				saveData(tmpValues.key, tmpValues.value);
				saveData("BDAY-COUNTER", parseInt(getData("BDAY-COUNTER")) + 1);
			}
			alert("Everything saved!");
			
		}
		else
		{
			return false;
		}
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	saveData(key, value)
	// @method	Saving a key-value pair into the gm persistent memory
	// @params	key: string, property name
	//			value: string, value
	//
	function saveData(key, value)
	{
		if (!!key)
		{
			GM_setValue(key, value);
		}		
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	getData(searchKey)
	// @method	Looks for a key with searchKey as name and returns his value
	// @params	searchKey: string, property name to search for
	//
	function getData(searchKey)
	{
		var value = GM_getValue(searchKey);
		if (value == undefined)
		{
			value = null;
			alert("No key \"" + searchKey + "\" found");
		}
		return value;
	}
		


	function insertTable(refNode)
	{
		var aBuddies = new Array();
		
		
		
		
		// formular container
		var myForm = document.createElement("form");
		with (myForm) 
		{
			setAttribute("action", "");
			setAttribute("method", "post");
			setAttribute("id", "myForm");
			
			var n = document.createElement("div");
			n.setAttribute("id", "col1");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col2");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col3");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col4");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("br");
			n.setAttribute("class", "clearer");
			appendChild(n);
		}
		
		// css für myForm
		GM_addStyle("#myForm { display: block; width: 100%; float: left; }");
		GM_addStyle(".formColumn { float: left; width: 24%; margin-top: 15px; margin-bottom: 35px; margin-left: 1%; }");
		GM_addStyle(".formColumn label { display:block; background-color:#f4f4f4; margin: 4px 0; padding: 2px 0; border: none; }");
		GM_addStyle(".formColumn label.accent { background-color: #e0e9f8; }");
		GM_addStyle(".formColumn label input { margin-right: 7px }");
		GM_addStyle(".clearer { clear: both; }")
		GM_addStyle("#col4 input { margin-top: 4px; margin-left: 15px; }");
		
		
		// myForm in dom einfügen, damit getElementById greift
		if (document.getElementById("myForm") == null) 
		{
			refNode.appendChild(myForm);
		}
		else 
		{
			refNode.replaceChild(myForm, document.getElementById("myForm"));
		}
		
		// kontrollvariablen für contentbefüllung
		var counter = new Number(1);
		var nextStep = new Number(0);
		var linesPerCol = Math.ceil(parseInt(getElement("BDAY-COUNTER")) / 3);
		
		
		// contentspalten befüllen
		for (j = 1; j <= 3; j++) 
		{
		
			// zwischenziele setzen
			(j < 3) ? nextStep += linesPerCol : nextStep = parseInt(getElement("BDAY-COUNTER")) - 1;
			
			
			with (document.getElementById("col" + j)) 
			{
				var tmpLabel;
				
				while (counter <= nextStep) 
				{
					tmpLabel = document.createElement("label");
					if (counter % 2) 
					{
						tmpLabel.setAttribute("class", "accent");
					}
					var tmpCheckbox = document.createElement("input");
					tmpCheckbox.setAttribute("type", "checkbox");
					tmpCheckbox.setAttribute("name", "name_" + aBuddies[counter]);
					tmpCheckbox.setAttribute("value", "value_" + counter);
					tmpCheckbox.setAttribute("checked", "true");
					var strRe = /([\u0000-\uFFFF]*)--X--([\u0000-\uFFFF]*)/.exec(getElement("BDAY" + decorateNumber(counter, 5)));
					var tmpTitle = document.createTextNode(strRe[1] + "  (" + strRe[2] + ")");
					//var tmpBr = document.createElement("br");
					
					tmpLabel.appendChild(tmpCheckbox);
					tmpLabel.appendChild(tmpTitle);
					//tmpLabel.appendChild(tmpBr);
					
					appendChild(tmpLabel);
					
					counter++;
				}
			}
		}
		
		// button in vierte spalte einfügen
		var tmpButton = document.createElement("input");
		with (tmpButton) 
		{
			setAttribute("type", "submit");
			setAttribute("name", "name_ABsenden");
			setAttribute("value", "Ausgewählte Exportieren");
			setAttribute("id", "myBtn");
			//addEventListener("click", cbOnSubmit, false);
		}
		document.getElementById("col4").appendChild(tmpButton);
		
		
		
	}
	
	function removeNodes(aNodeList)
	{
		while (aNodeList.length) 
		{
			var n = aNodeList.pop();
			n.parentNode.removeChild(n);
		}
	}
	
	function cbChangeSel(e)
	{
		var selPatterns = {
		
			pattern: "//input[@type='checkbox']",
			all: function(refNode)
			{
				refNode.checked = true;
			},
			none: function(refNode)
			{
				refNode.checked = false;
			},
			invert: function(refNode)
			{
				if (refNode.checked) 
				{
					refNode.checked = false;
				}
				else 
				{
					refNode.checked = true;
				}
			}
			
		};
		var result = document.evaluate(selPatterns.pattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		
		
		for (var i = 0; i < result.snapshotLength; i++) 
		{
			selPatterns[e.target.id](result.snapshotItem(i));
		}
		
	}
	
	
	function changeText(refNode)
	{
		with (refNode) 
		{
			childNodes[1].childNodes[0].nodeValue = "Geburtstage als VCS-Termin exportieren";
			

			with (childNodes[3]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "all";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Alle auswählen";
			}
			
			with (childNodes[5]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "none";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Auswahl aufheben";
			}
			
			with (childNodes[7]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "invert";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Auswahl umkehren";
			}
		}
	}
	
	function cbClick(eventObj)
	{
		removeNodes(getRefNode("//div[@id='rahmen']/table/tbody/tr/td[@valign='top']/h2[1]/following-sibling::*"));
		
		var targetNode = getRefNode("//div[@id='rahmen']/table/tbody/tr/td[@valign='top']");
		changeText(targetNode);
		insertTable(targetNode);
	}
	
	function getRefNode(strXPath)
	{
		var result = document.evaluate(strXPath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		if (result.snapshotLength == 1) 
		{
			return result.snapshotItem(0);
		}
		else 
		{
			var aTmp = [];
			for (var i = 0; i < result.snapshotLength; i++) 
			{
				aTmp.push(result.snapshotItem(i));
			}
			return aTmp;
		}
	}
	
	
	function startInjecting()
	{
		cbClick();
	}
	
}	// END CLASS "CElementGrabber"


function start()
{
	var myGrabber = new CElementGrabber();
	var aUrls = [];
	for (var k = 1; k <= 12; k++) 
	{
		aUrls.push("http://www.wer-kennt-wen.de/events/calendar/year/2009/month/" + k);
	}
	myGrabber.grab("//td[starts-with(@class,'thisMonth')]/div[@class='clearfix']/ul[@class='events']/li[@class='birthday']/a", aUrls);
}

var res = document.evaluate("//div[@id='navigation']/ul/li[not(@class)][last()]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var myRefNode = res.snapshotItem(0);
var myClonedRefNode = myRefNode.cloneNode(true);
with (myClonedRefNode.childNodes[0]) 
{
	title = tagName;
	addEventListener("click", start, false);
	href = "javascript:void()";
	childNodes[0].nodeValue = "Grab BDays!";
}
myRefNode.parentNode.appendChild(myClonedRefNode);

Revision: 10340
at February 21, 2009 13:09 by preasha


Updated Code
// ==UserScript==
// @name           WKW-ElemGrabber
// @namespace      http://dev.3muskeeters.com
// @description    Grabs birthday dates of all your buddies
// @include		   http://www.wer-kennt-wen.de/events/calendar/year/*
// ==/UserScript==

/*
	- Grabs birthday dates, saves them in an Array ( key: BDAY00000 -> value: SURNAME NAME--X--DD-MM )
*/

//--------------------------------------------------------------------------------------
//	Some obvious prototyping
//--------------------------------------------------------------------------------------
//
//
//	@method	Checks wether a key already exists (using the double equal as log. op.)
//
Array.prototype.contains = 	function(strKey)
							{
								for (key in this)
								{
									if (key == strKey)
									{
										return true;
									}
								}
								return false;
							}
//
//	@method	Counts all contained (associative) keys
//
Array.prototype.getLength =	function()
							{
								var i = 0;
								for each (k in this)
								{
									if (typeof(k) != "function")
									{
										i++;
									}
								}
								return i;
							}
//							
//--------------------------------------------------------------------------------------						
//--------------------------------------------------------------------------------------
//
//	@name 		CElementGrabber()
//	@class		Baseclass for the whole grabbing thing.
//
function CElementGrabber()
{
	var aTempNodes = new Array(); // holds all requested resources
	var addElement, getElement, dumpElements;	// Dummy declaration, used by following closure
	
	(	// BEGIN GETTER/SETTER CLOSURE

		function()
		{
			var grabbedElements = new Array();
			
			//
			// @name	addElement(key, value)
			// @method	Setter for array of grabbed elements
			// @params	nothing to explain; only key has to be != null/undefined
			//
			addElement = 	function(key, value)
					{
						try 
						{
							if (key) 
							{
								//GM_log("addElement( " + key + " ,  " + value + " );");
								grabbedElements[key] = value;
							}
							else 
							{
								throw new TypeError("Invalid element was returned from XPath query");
							}
						}
						catch (error)
						{
							alert(error.name + ": " + error.message);
						}
					};
			//
			// @name	getElement(index)
			// @method	Getter for array of grabbed elements
			// @params	key:	the key that should be returned; if key is omitted,
			//					a whole "copy" of grabbedElements is being returned
			//		
			getElement = 	function(key)
							{	
								// no index passed => return complete "copy" of array
								if (key == undefined)
								{
									return	(
												function(tmp)
												{
													//GM_log("     getElement(undefined):  WHOLE ARRAY");
													return tmp;
												}
									
											)(grabbedElements);
								}
								// valid index passed 
								else if ((typeof(key) == "string") && key)
								{
									//GM_log("getElement( " + key + " ):  " + grabbedElements[key]);
									return grabbedElements[key];
								}
								// invalid parameter
								else
								{
									return null;
								}
								
							};
							
			dumpElements = 	function()
							{
								//GM_log("Listing the content of grabbedElements:\n\n");
								for (key in grabbedElements)
								{
									GM_log("grabbedElements[ " + key + "] = " + grabbedElements[key])
								}
							};
		}
	)()	// END GETTER/SETTER CLOSURE
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	dump()
	// @method	Privileged method, lists all grabbed Elements in error console
	//
	this.dump = function()
				{
					dumpElements();
				}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------			
	//
	// @name	grab(strRule, strURL)
	// @method	privileged method; Executes a XPath query to the current document, if nodes are found
	//			the given callback function is called with argsCallback as argument
	// @params	strRule: string, xpath query to execute
	//			aUrlList: array, contains all urls that should be filtered
	// 
	this.grab = function(strXPathExpr, aUrlList)
	{
		//GM_log("ENTER grab");
		try 
		{
			if (!!aUrlList)	// when a url list is passed
			{
				for (var i = 0; i < aUrlList.length; i++) 
				{
					if (!load(aUrlList[i], filterElements, [strXPathExpr]))	// when load() wasn't successfull
					{
						throw new Error("Error occured while loading url: " + aUrlList[i]);
					}
				}
				//alert("All urls in aUrlList loaded");
			}
			else	// only the current document should be filtered
			{
				filterElements(strXPathExpr);
			}
		} 
		catch (error) 
		{
			alert("grab()->try-statement:   " + error.name + ": " + error.message);
			return false;
		}
		//GM_log("LEAVE grab");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------	
	//
	// @name	filterElements(strURL, strExpression)
	// @method	callback function; Gets called through load(), applies a passed xpath to the 
	//			current document and passes each matched node to getBDayDetails()
	// @params	strURL:	string, the current url
	//			strExpression:	string, xpath to apply
	//
	function filterElements(strURL, aArgs)
	{
		//GM_log("ENTER filterElements");
		var result = document.evaluate(	aArgs[0],
										aTempNodes[aArgs[1]],
										null,
										XPathResult.ORDERED_NODE_ITERATOR_TYPE,
										null
										);
		var currentNode =  
		{
			count: 1,
			node: result.iterateNext()		
		};
		
		while (currentNode.node)
		{
 			// there are nodes in result to iterate through
			try
			{
 				getBDayDetails(currentNode.node, currentNode.count, strURL);
				currentNode.count++;
				currentNode.node = result.iterateNext();
			}
			catch (error)
			{
				alert("filterElements()->try-statement:   " + error.name + ": " + error.message);
				return false;
			}
		}
		if (aArgs[1] == 11)
		{
			startInjecting();
		}
		return true;
		//GM_log("LEAVE filterElements");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	getBDayDetails(nodeCapture, numIndex, strURL)
	// @method	Callback function; Gets captured node, index of that node and some optionally passed
	//			in arguments in a string.
	// @params	nodeCapture: 	dom-node, the captured node
	//			numIndex:		number, the index of the node inside the whole captured collection
	//			aPassedArgs:	array, the optionally passed in arguments
	//	
	function getBDayDetails(nodeCapture, numIndex, strURL)
	{
 
		var aBirthday = new Array();
		var nodecollSpans = nodeCapture.parentNode.parentNode.parentNode.getElementsByTagName("span");
		for (var i = 0; i < nodecollSpans.length; i++)
		{
			if (nodecollSpans[i].getAttribute("class") == "day")
			{
				aBirthday["day"] = nodecollSpans[i].childNodes[0].nodeValue;
 				i = nodecollSpans.length;
			}
			
		}
 
		var aREReturn = /^http:\/\/www\.wer-kennt-wen\.de\/events\/calendar\/year\/(\d{4,4})\/month\/(\d{1,2})/.exec(strURL);
		
		// month
		aBirthday["month"] = aREReturn[2];
 		// year
		aBirthday["year"] = aREReturn[1];
 		// name of birthday child
		if (nodeCapture.hasAttribute("title"))	// birthday of a buddy
		{
			if (nodeCapture.getAttribute("title").length) 
			{
				// using unicode-ranges cause some dumbasses are using "funny" symbols
				// i am wondering why the wkw-team permitted those characters
				aBirthday["who"] = /([\u0000-\uFFFF]+)\swird\s\d{2,3}/.exec(nodeCapture.getAttribute("title"))[1];
			}
		}
		else	// thats my own birthday, returning
		{
			return false;
		}
 
		//GM_log("     Capture #" + numIndex + "/" + getElement("BDAY-COUNTER") + ":   " + aBirthday["who"] + " -> " + aBirthday["day"] + "-" +	aBirthday["month"] + "-" + aBirthday["year"]);
		
		if (parseInt(getElement("BDAY-COUNTER")) >= 0) 
		{
			// bday counter already exists, so we increment him by one
			addElement("BDAY-COUNTER", parseInt(getElement("BDAY-COUNTER")) +  1);
		}
		else
		{
			// bday coutner doesnt exist, so we create him
			addElement("BDAY-COUNTER", 1);
		}
		//GM_log("     Current BDay-Counter: " + getElement("BDAY-COUNTER"));
		
		addElement(("BDAY" + decorateNumber(getElement("BDAY-COUNTER"), 5)), (aBirthday["who"] + "--X--" + aBirthday["month"] + "-" + aBirthday["day"]));
 
 
		return true;
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	decorateNumber(numInput, templength)
	// @method	private method, takes a string and "fills" him up with zeros up to a legth
	//			specified by numLength. If the passed in string is already longer than numLength
	//			it will be returned without any modification.
	// @params	numInput: 	string, number that should be decorated
	//			numLength:	number, the length numInput should be filled up to
	//	
	function decorateNumber(numInput, numLength)
	{
		if (numInput.toString().length < numLength) {
			
			var strTemp = new String();
			for (var i =0; i < numLength - String(numInput).length; i++)
			{
				strTemp += "0";
			}
			return strTemp + numInput.toString(); 
		} 
		else
		{
			return numInput;
		}

	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	loadURL(strURL, cbFunc, aCbArgs)
	// @method	private method; Requests the resource at the given url
	// @params	strURL:	str, url to request
	//			cbFunc: function ref; callback function thats gonna be passed through
	//			aCbArgs: array; arguments that are gonna be passed through
	//
	function load(strURL, cbFunc, aCbArgs)
	{
		//GM_log("ENTER load");
		if (new RegExp(/http\:\/\/[\w0-9-_\.@\/\+\?]+/).test(strURL)) 
		{
			var objReqDetails = {
				method: "GET",
				url: strURL,
				headers: {
					"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4)",
					"Accept": "application/atom+xml,application/xml,text/xml",
					"Referer": "http://www.wer-kennt-wen.de/events/calendar",
					"Cookie": document.cookie.split(/__utma=.*;\s(?=__utma=)/)[1],
					"Accept-Language": "de-de,en-us;q=0.7,en;q=0.3",
					"Accept-Encoding": "gzip,deflate",
					"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
					"Keep-Alive": "300",
					"Connection": "keep-alive"
				},
				onerror: handleReqError,
				onreadystatechange: function(respDetails)
									{
										if (respDetails.readyState == 4) 
										{
											interpretRespData(respDetails, strURL, cbFunc, aCbArgs);
										}
									}
			};
			GM_xmlhttpRequest(objReqDetails);
			//GM_log("LEAVE grab");
			return true;
		}
		else
		{
			alert("load: You gave me an invalid url");
			//GM_log("LEAVE grab");
			return false;
		}
	}



	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	interpretRespData(responseDetails, strURL, cbFunc, aCbArgs)
	// @method	Joins the properties contained in responseDetails, and alerts the result
	// @params	responseDetails: object, details about the request process
	//			strURL: string; url of requested resource -> passed through
	//			cbFunc: callback function; passed through
	//			aCbArgs: array; arguments for callback function -> passed through
	//
	function interpretRespData(responseDetails, strURL, cbFunc, aCbArgs)
	{
		/*
		GM_log("ENTERED interpretRespData");
		GM_log("     interpretRespData-> complete. The request is completed and all response data is available in other fields");
		GM_log("     interpretRespData-> HTTP-Status: " + responseDetails.statusText);
		GM_log("     interpretRespData-> Response headers: " + responseDetails.responseHeaders);
		GM_log("     interpretRespData-> Status: " + responseDetails.status);
		*/
		
		var currIndex = changeDocElement(responseDetails.responseText);
		aCbArgs.push(currIndex)
		cbFunc(strURL, aCbArgs);
		
		//GM_log("LEAVING interpretRespData");
	}


	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	function handleReqError(responseDetails)
	{
		//GM_log("ENTERED handleReqError");

		var strMsg = 	"handleReqError-> During the request/response an error occured.\n" + 
						"handleReqError-> Status text: " + responseDetails.statusText;
		alert(strMsg);
		
		//GM_log("LEAVING handleReqError");
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	changeDocElement(strInnerHTML)
	// @method	private method; replaces the current body with the one in strInnerHTML
	// @params	strInnerHTML:	string; contains the new html code
	//	
	function changeDocElement(strInnerHTML)
	{
		var currIndex = aTempNodes.push(document.createElement("div")) - 1;
		aTempNodes[currIndex].innerHTML = /(\x3Cbody[\s\u0000-\uFFFF]*?\x3E)([\s\u0000-\uFFFF]*)(\x3C\/body\x3E)/.exec(strInnerHTML)[2];
		return currIndex;
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------	
	this.save = function()
	{

		// checking for bday counter inside the greasemonkey space
		if (getData("BDAY-COUNTER") == null) 
		{
			// bday coutner doesnt exist, so we create him
			saveData("BDAY-COUNTER", 0);
		}
		
		var numGrabbedElements = parseInt(getElement("BDAY-COUNTER"));
		
		if (numGrabbedElements != NaN)
		{
			alert("     grabbedElements.length = " + getElement().getLength());	
			alert("     numGrabbedElements = " + numGrabbedElements);
			
			//dumpElements();
			
			for (var i=1; i <= numGrabbedElements; i++)
			{
				alert("i: " + i + "  /  " + decorateNumber(i, 5));
				var strTmpKey = "BDAY" + decorateNumber(i, 5);
				alert(strTmpKey);
				var tmpValues = {	key: strTmpKey,
									value: getElement(strTmpKey)
									};
				GM_log("     Saving: " + tmpValues.key + " -> " + tmpValues.value);
				saveData(tmpValues.key, tmpValues.value);
				saveData("BDAY-COUNTER", parseInt(getData("BDAY-COUNTER")) + 1);
			}
			alert("Everything saved!");
			
		}
		else
		{
			return false;
		}
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	saveData(key, value)
	// @method	Saving a key-value pair into the gm persistent memory
	// @params	key: string, property name
	//			value: string, value
	//
	function saveData(key, value)
	{
		if (!!key)
		{
			GM_setValue(key, value);
		}		
	}
	
	
	
	//							
	//--------------------------------------------------------------------------------------						
	//--------------------------------------------------------------------------------------
	//
	// @name	getData(searchKey)
	// @method	Looks for a key with searchKey as name and returns his value
	// @params	searchKey: string, property name to search for
	//
	function getData(searchKey)
	{
		var value = GM_getValue(searchKey);
		if (value == undefined)
		{
			value = null;
			alert("No key \"" + searchKey + "\" found");
		}
		return value;
	}
		


	function insertTable(refNode)
	{
		var aBuddies = new Array();
		
		
		
		
		// formular container
		var myForm = document.createElement("form");
		with (myForm) 
		{
			setAttribute("action", "");
			setAttribute("method", "post");
			setAttribute("id", "myForm");
			
			var n = document.createElement("div");
			n.setAttribute("id", "col1");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col2");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col3");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("div");
			n.setAttribute("id", "col4");
			n.setAttribute("class", "formColumn");
			appendChild(n);
			
			n = document.createElement("br");
			n.setAttribute("class", "clearer");
			appendChild(n);
		}
		
		// css für myForm
		GM_addStyle("#myForm { display: block; width: 100%; float: left; }");
		GM_addStyle(".formColumn { float: left; width: 24%; margin-top: 15px; margin-bottom: 35px; margin-left: 1%; }");
		GM_addStyle(".formColumn label { display:block; background-color:#f4f4f4; margin: 4px 0; padding: 2px 0; border: none; }");
		GM_addStyle(".formColumn label.accent { background-color: #e0e9f8; }");
		GM_addStyle(".formColumn label input { margin-right: 7px }");
		GM_addStyle(".clearer { clear: both; }")
		GM_addStyle("#col4 input { margin-top: 4px; margin-left: 15px; }");
		
		
		// myForm in dom einfügen, damit getElementById greift
		if (document.getElementById("myForm") == null) 
		{
			refNode.appendChild(myForm);
		}
		else 
		{
			refNode.replaceChild(myForm, document.getElementById("myForm"));
		}
		
		// kontrollvariablen für contentbefüllung
		var counter = new Number(1);
		var nextStep = new Number(0);
		var linesPerCol = Math.ceil(parseInt(getElement("BDAY-COUNTER")) / 3);
		
		
		// contentspalten befüllen
		for (j = 1; j <= 3; j++) 
		{
		
			// zwischenziele setzen
			(j < 3) ? nextStep += linesPerCol : nextStep = parseInt(getElement("BDAY-COUNTER")) - 1;
			
			
			with (document.getElementById("col" + j)) 
			{
				var tmpLabel;
				
				while (counter <= nextStep) 
				{
					tmpLabel = document.createElement("label");
					if (counter % 2) 
					{
						tmpLabel.setAttribute("class", "accent");
					}
					var tmpCheckbox = document.createElement("input");
					tmpCheckbox.setAttribute("type", "checkbox");
					tmpCheckbox.setAttribute("name", "name_" + aBuddies[counter]);
					tmpCheckbox.setAttribute("value", "value_" + counter);
					tmpCheckbox.setAttribute("checked", "true");
					var strRe = /([\u0000-\uFFFF]*)--X--([\u0000-\uFFFF]*)/.exec(getElement("BDAY" + decorateNumber(counter, 5)));
					var tmpTitle = document.createTextNode(strRe[1] + "  (" + strRe[2] + ")");
					//var tmpBr = document.createElement("br");
					
					tmpLabel.appendChild(tmpCheckbox);
					tmpLabel.appendChild(tmpTitle);
					//tmpLabel.appendChild(tmpBr);
					
					appendChild(tmpLabel);
					
					counter++;
				}
			}
		}
		
		// button in vierte spalte einfügen
		var tmpButton = document.createElement("input");
		with (tmpButton) 
		{
			setAttribute("type", "submit");
			setAttribute("name", "name_ABsenden");
			setAttribute("value", "Ausgewählte Exportieren");
			setAttribute("id", "myBtn");
			//addEventListener("click", cbOnSubmit, false);
		}
		document.getElementById("col4").appendChild(tmpButton);
		
		
		
	}
	
	function removeNodes(aNodeList)
	{
		while (aNodeList.length) 
		{
			var n = aNodeList.pop();
			n.parentNode.removeChild(n);
		}
	}
	
	function cbChangeSel(e)
	{
		var selPatterns = {
		
			pattern: "//input[@type='checkbox']",
			all: function(refNode)
			{
				refNode.checked = true;
			},
			none: function(refNode)
			{
				refNode.checked = false;
			},
			invert: function(refNode)
			{
				if (refNode.checked) 
				{
					refNode.checked = false;
				}
				else 
				{
					refNode.checked = true;
				}
			}
			
		};
		var result = document.evaluate(selPatterns.pattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		
		
		for (var i = 0; i < result.snapshotLength; i++) 
		{
			selPatterns[e.target.id](result.snapshotItem(i));
		}
		
	}
	
	
	function changeText(refNode)
	{
		with (refNode) 
		{
			childNodes[1].childNodes[0].nodeValue = "Geburtstage als VCS-Termin exportieren";
			
			with (childNodes[3]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "all";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Alle auswählen";
			}
			
			with (childNodes[5]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "none";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Auswahl aufheben";
			}
			
			with (childNodes[7]) 
			{
				title = tagName;
				href = "javascript:void()";
				id = "invert";
				addEventListener("click", cbChangeSel, false);
				childNodes[0].nodeValue = "Auswahl umkehren";
			}
		}
	}
	
	function cbClick(eventObj)
	{
		removeNodes(getRefNode("//div[@id='rahmen']/table/tbody/tr/td[@valign='top']/h2[1]/following-sibling::*"));
		
		var targetNode = getRefNode("//div[@id='rahmen']/table/tbody/tr/td[@valign='top']");
		changeText(targetNode);
		insertTable(targetNode);
	}
	
	function getRefNode(strXPath)
	{
		var result = document.evaluate(strXPath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		if (result.snapshotLength == 1) 
		{
			return result.snapshotItem(0);
		}
		else 
		{
			var aTmp = [];
			for (var i = 0; i < result.snapshotLength; i++) 
			{
				aTmp.push(result.snapshotItem(i));
			}
			return aTmp;
		}
	}
	
	
	function startInjecting()
	{
		cbClick();
	}
	
}	// END CLASS "CElementGrabber"


function start()
{
	var myGrabber = new CElementGrabber();
	var aUrls = [];
	for (var k = 1; k <= 12; k++) 
	{
		aUrls.push("http://www.wer-kennt-wen.de/events/calendar/year/2009/month/" + k);
	}
	myGrabber.grab("//td[starts-with(@class,'thisMonth')]/div[@class='clearfix']/ul[@class='events']/li[@class='birthday']/a", aUrls);
}

var res = document.evaluate("//div[@id='navigation']/ul/li[not(@class)][last()]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var myRefNode = res.snapshotItem(0);
var myClonedRefNode = myRefNode.cloneNode(true);
with (myClonedRefNode.childNodes[0]) 
{
	title = tagName;
	addEventListener("click", start, false);
	href = "javascript:void()";
	childNodes[0].nodeValue = "Grab BDays!";
}
myRefNode.parentNode.appendChild(myClonedRefNode);

Revision: 10339
at December 19, 2008 18:27 by preasha


Initial Code
// ==UserScript==
// @name           ElementGrabber-Tryout
// @namespace      tag:[email protected],2008-12-18:elemgrab-tryout
// @description    Working file wkw-grabber
// @include        http://www.wer-kennt-wen.de/events/calendar
// @include		   http://www.wer-kennt-wen.de/events/calendar/*
// ==/UserScript==


/*for (i=0; i < 3; i++)
{
	window.setTimeout(function() { alert("hallo"); }, 300)
}*/


/*
var obj_Tryouts = 
{
	this.getUserPic: function() 
					{
						var allElements, thisElement;
						allElements = document.evaluate(
														'//div[@id="person_picture"]',
														document,
														null,
														XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
														null
														);
						
						if (allElements.snapshotLength == 1)
						{
							alert(allElements.snapshotItem(0).im);  
						}
					}
};
*/

function CElementGrabber()
{
	var addElement, getElement;
	(
		//
		// @name	getElement(index)/addElement(elemNew)
		// @method	Getter/Setter for array of grabbed elements
		// @params	elemNew:	element for appending to the array
		// 			index:		index of the element that should be returned
		//
		function()
		{
			var grabbedElements = new Array();
			addElement = 	function(elemNew)
					{
						try 
						{
							if (!!elemNew) {
								grabbedElements.push(elemNew);
							}
							else {
								throw new TypeError("Invalid element was returned from XPath query");
							}
						}
						catch (error)
						{
							alert(error.name + ": " + error.message);
						}
					};
					
			getElement = 	function(index)
							{	
								// no index passed => return complete "copy" of array
								if (index == undefined)
								{
									return (
												function(retElements)
												{
													return retElements;
												}
											)(grabbedElements)
								}
								// valid index passed 
								else if ((typeof(index) == "number") && (index < grabbedElements.length))
								{
									return grabbedElements[index];
								}
								// index points to a non-existing array element => return last element
								else
								{
									return grabbedElements[-1];
								}
								
							};
		}
	)()
	
	//
	// @name	applyXPath(strRule, callbackOnSuccess, argsCallback)
	// @method	Executes a XPath query to the current document, if nodes are found
	//			the given callback function is called with argsCallback as argument
	// @params	strRule: string, xpath query to execute
	//			callbackOnSuccess: callback/function, is called for every node beeing returned
	//			argsCallback: array, contains the arguments that should be given to the cb
	// 
	var applyXPath = function(strRule, callbackOnSuccess, argsCallback)
		{
			var result = document.evaluate(
											strRule,
											document,
											null,
											XPathResult.ORDERED_NODE_ITERATOR_TYPE,
											null
										);
			
			var currentNode =  
			{
				count: 0,
				node: result.iterateNext()		
			};
			
			while (currentNode.node)
			{
				try
				{
					callbackOnSuccess(currentNode.node, currentNode.count, argsCallback);
				}
				catch (error)
				{
					alert(error.name + ": " + error.message);
					return 0;
				}
			}
			
			return true;
		}
	
	//
	// @name	showRespDetails(responseDetails)
	// @method	Joins the properties contained in responseDetails, and alerts the result
	// @params	responseDetails: object, details about the request process
	//
	var showRespDetails = function(responseDetails)
	{
		var strMsg = new String(showRespDetails.caller + ":\n\n");
		for each (detail in responeDetails)
		{
		    strMsg += detail + ": " + detail.valueOf() + "\n";
		}
		if (strMsg.indexOf("\n\n") == strMsg.length - 2)
		{
			strMsg =  showRespDetails.caller + ":  No properties in responseDetails";
		}
		alert(strMsg);
	};
	
	//
	// @name	saveData(key, value)
	// @method	Saving a key-value pair into the gm persistent memory
	// @params	key: string, property name
	//			value: string, value
	//
	function saveData(key, value)
	{
		alert("drin");
		if (!!key)
		{
			GM_setValue(key.valueOf(), value.valueOf());
		}		
	}
	
	//
	// @name	getData(searchKey)
	// @method	Looks for a key with searchKey as name and returns his value
	// @params	searchKey: string, property name to search for
	//
	function getData(searchKey)
	{
		var value = GM_getValue(searchKey);
		if (value == undefined)
		{
			value = false;
			alert("No key \"" + searchKey + "\" found");
		}
		return value;
	}
		
	//
	// @name	loadURL(strURL)
	// @method	Open page at given URL
	// @params	strURL:	str, url to open
	//
	function loadURL(strURL)
	{
		if (strURL.test(/\Ahttp:\/\/[a-zA-Z0-9-_\.@\/\+\?]+\Z/)) 
		{
			var objReqDetails = {
				method: "GET",
				url: strURL,
				headers: {
					"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4)",
					"Accept": "application/atom+xml,application/xml,text/xml",
					"Referer": "http://www.wer-kennt-wen.de/events/calendar",
					"Cookie": document.cookie.split(/__utma=.*;\s(?=__utma=)/)[1],
					"Accept-Language": "de-de,en-us;q=0.7,en;q=0.3",
					"Accept-Encoding": "gzip,deflate",
					"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
					"Keep-Alive": "300",
					"Connection": "keep-alive"
				},
				onload: showRespDetails,
				onerror: showRespDetails,
				onreadystatechange: showRespDetails
			};
			
			GM_xmlhttpRequest(objReqDetails);
		}
		else
		{
			alert("gotoURL: You gave me an invalid url");
		}
	}
	
	function test()
	{
		saveData("vorname", "paul");
		saveData("nachname", "knallkopf");
		alert(this.getData("vorname"));
	}
}


var myGrabber = new CElementGrabber();
myGrabber.test();

Initial URL

                                

Initial Description
Because WKW is a german social community, wird auch deutsch Kommentiert: Sobald der Kalender-Bereich aufgerufen wird, gesellt sich oben in der Menüzeile ein neuer Punkt hinzu "Grab BDdays!". Ein klick darauf listet alle Buddies mitsamt Geburtstagen auf. Das Script ist noch nicht fertig. Das Kernfeature - der Export als VCS-Datei - fehlt noch, die Codedokumentation ist nicht sauber, genauso wie der Code an sich. Ein funktionierender Prototype quasi.

Initial Title
GM_BuddyGrabber

Initial Tags
js

Initial Language
JavaScript