From d37ce3b921279702313aa3a688cfdba51266dabb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20=C3=85kre=20Solberg?= <andreas.solberg@uninett.no>
Date: Thu, 5 May 2011 08:01:07 +0000
Subject: [PATCH] Updated the single file DiscoJuice version, and added a
 minified version...

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2828 44740490-163a-0410-bde0-09ae8108e29a
---
 .../discojuice/www/discojuice/discojuice.js   | 758 +++++++++++++-----
 .../www/discojuice/discojuice.min.js          |   1 +
 2 files changed, 547 insertions(+), 212 deletions(-)
 create mode 100644 modules/discojuice/www/discojuice/discojuice.min.js

diff --git a/modules/discojuice/www/discojuice/discojuice.js b/modules/discojuice/www/discojuice/discojuice.js
index 78e77720c..6423b1312 100644
--- a/modules/discojuice/www/discojuice/discojuice.js
+++ b/modules/discojuice/www/discojuice/discojuice.js
@@ -20,7 +20,6 @@ var DiscoJuice = {};
  */
 DiscoJuice.Constants = {
 	"Countries": {
-
 		'CZ': 'Czech',
 		'DK': 'Denmark',
 		'FI': 'Finland',
@@ -42,6 +41,7 @@ DiscoJuice.Constants = {
 		'CH': 'Switzerland',
 		'TR': 'Turkey',
 		'US': 'USA',
+		'GB': 'UK',
 		'XX': 'Experimental'
 	},
 	"Flags": {
@@ -65,7 +65,8 @@ DiscoJuice.Constants = {
 		'SE': 'se.png',
 		'CH': 'ch.png',
 		'TR': 'tr.png',
-		'US': 'us.png',
+		'GB': 'gb.png',
+		'US': 'us.png'
 	}
 };
 
@@ -86,6 +87,9 @@ DiscoJuice.Utils = {
 			},
 			"set": function(opts) {
 				options = opts;
+			},
+			"update": function(key, value) {
+				options[key] = value;
 			}
 		}
 	}(),
@@ -142,9 +146,30 @@ DiscoJuice.Utils = {
 			}
 		}
 		return false;
+	},
+
+
+
+	// calculate distance between two locations
+	"calculateDistance": function (lat1, lon1, lat2, lon2) {
+		var R = 6371; // km
+		var dLat = this.toRad(lat2-lat1);
+		var dLon = this.toRad(lon2-lon1); 
+		var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+				Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) * 
+				Math.sin(dLon/2) * Math.sin(dLon/2); 
+		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
+		var d = R * c;
+		return d;
+	},
+
+	"toRad": function (deg) {
+		return deg * Math.PI/180;
 	}
 
 
+
+
 };
 
 
@@ -178,9 +203,6 @@ DiscoJuice.Utils = {
 if (typeof DiscoJuice == "undefined") var DiscoJuice = {};
 
 
-
-
-
 DiscoJuice.UI = {
 	// Reference to the top level DiscoJuice object
 	"parent" : DiscoJuice,
@@ -191,6 +213,7 @@ DiscoJuice.UI = {
 	// Reference to the 
 	"popup": null,
 	
+	
 	// Entities / items
 	"resulthtml": 'Loading data…',
 
@@ -205,6 +228,7 @@ DiscoJuice.UI = {
 	"focusSearch": function() {
 		$("input.discojuice_search").focus();
 	},
+	
 	"hide": function() {
 		$("div#discojuice_overlay").fadeOut("slow"); //fadeOut("fast");
 		this.popup.fadeOut("slow");
@@ -213,43 +237,108 @@ DiscoJuice.UI = {
 	"clearItems": function() {
 		this.resulthtml = '';
 	},
-	"addItem": function(current, substring, flag) {
+	
+	// addItem(item, description, {country, flag}, keywordmatch, distance)	 		
+	// addItem(current, current.descr || null, countrydef, search, current.distance);
+	"addItem": function(item, countrydef, search, distance) {
 		var textLink = '';
 		var classes = '';
-		if (current.weight < -50) classes += 'hothit';
+		if (item.weight < -50) classes += 'hothit';
 
 		var iconpath = this.parent.Utils.options.get('discoPath', '') + 'logos/';
 		var flagpath = this.parent.Utils.options.get('discoPath', '') + 'flags/';
+		var clear = false;
 		
-		var flagtext = '';
+		var debugweight = this.parent.Utils.options.get('debug.weight', false);
 		
-		if (flag) {
-			flagtext = '<img src="' + flagpath + flag + '" alt="' + escape(substring) + '" /> ';
+		
+		// Add icon element first
+		if (item.icon) {
+			textLink += '<img class="logo" src="' + iconpath + item.icon + '" />';
+			clear = true;
+		}
+		
+		// Add title
+		textLink += '<span class="title">' + item.title + '</span>';
+		
+		// Add matched search term
+		if (search && search !== true) {
+			textLink += '<span class="substring">– ' + search + '</span>';
+		} else if (item.descr) {
+			textLink += '<span class="substring">– ' +  item.descr + '</span>';
 		}
+		
+		
 
-		if (current.icon) {
-			if (!substring) {
-				textLink += '<a href="" class="' + classes + '" rel="' + escape(current.entityid) + '" title="' + current.title + '">' + 
-					'<img class="logo" src="' + iconpath + current.icon + '" />' +
-					'<span class="title">' + current.title + '</span><hr style="clear: both; height: 0px; visibility:hidden" /></a>';
-			} else {
-				textLink += '<a href="" class="' + classes + '" rel="' + escape(current.entityid) + '" title="' + current.title + '">' + 
-					'<img class="logo" src="' + iconpath +  current.icon + '" />' +
-					'<span class="title">' + current.title + '</span>' + 
-					'<span class="substring">' + flagtext + substring + '</span>' +
-					'<hr style="clear: both; height: 0px; visibility:hidden" /></a>';
-						}
-		} else {
-			if (!substring) {
-				textLink += '<a href="" class="' + classes + '" rel="' + escape(current.entityid) + '"><span class="title">' + current.title + '</span></a>';		
-			} else {
-				textLink += '<a href="" class="' + classes + '" rel="' + escape(current.entityid) + '"><span class="title">' + current.title + '</span><span class="substring">' + flagtext + substring + '</span></a>';					
+		if (countrydef || (distance != undefined)) {
+				
+			textLink += '<span class="location">';
+			if (countrydef) {
+				textLink += '<span class="country">';
+				if (countrydef.flag) textLink += '<img src="' + flagpath + countrydef.flag + '" alt="' + escape(countrydef.country) + '" /> ';
+				textLink += countrydef.country + '</span>';
 			}
 	
+			
+			if (distance != undefined) {
+				if (distance < 1) {
+					textLink += '<span class="distance">Nearby</span>';
+				} else {
+					textLink += '<span class="distance">' +  Math.round(distance) + ' km' + '</span>';
+				}
+
+			}
+			textLink += '</span>';
 		}
+		
+		if (debugweight) {
+			textLink += '<div class="debug">';
+			
+			if (item.subID) {
+				textLink += '<input value="' + item.subID + '" />';
+			}
+			
+			var w = 0;
+			if (item.weight) {
+				w += item.weight;
+			}
+			if (item.distanceweight) {
+				w += item.distanceweight;
+			}
+			textLink += 'Weight <strong style="color: #888">' + Math.round(100*w)/100 + '</strong> ';
+
+			if (item.weight) {
+				textLink += ' (base ' + item.weight + ')   ';
+			}
+			if (item.distanceweight) {
+				textLink += '(dist ' + Math.round(100*item.distanceweight)/100 + ')';
+			}
+
+
+			textLink += '</div>';
+		}
+
+		
+		// Add a clear bar. 
+		if (clear) {
+			textLink += '<hr style="clear: both; height: 0px; visibility:hidden" />';
+		}
+		
+		
+		var relID = item.entityID;
+		if (item.subID) {
+			relID += '#' + item.subID;
+		}
+		
+		// Wrap in A element
+		textLink = '<a href="" class="' + classes + '" rel="' + escape(relID) + '" title="' + escape(item.title) + '">' + 
+			textLink + '</a>';
+
+
 		this.resulthtml += textLink;
 	},
-	"refreshData": function() {
+		
+	"refreshData": function(showmore, show, listcount) {
 		var that = this;
 		
 		this.parent.Utils.log('DiscoJuice.UI refreshData()');
@@ -260,49 +349,86 @@ DiscoJuice.UI = {
 			$(this).click(function(event) {
 				event.preventDefault();
 				overthere.hide();
-				var entityid = unescape($(this).attr('rel'));
-				overthere.control.selectProvider(entityid);
+							
+				// The "rel" attribute is containing: 'entityid#subid'
+				// THe following code, decodes that.
+				var relID = unescape($(this).attr('rel'));
+				var entityID = relID;
+				var subID = undefined;
+				if (relID.match(/^.*#.+?$/)) {
+					var matched = /^(.*)#(.+?)$/.exec(relID);
+					entityID = matched[1];
+					subID = matched[2];
+				}
+				overthere.control.selectProvider(entityID, subID);
 			});
 		});
+		
+		if (showmore) {
+			var moreLink = '<a class="discojuice_showmore textlink" href="">Results limited to ' + show + ' entries – show more…</a>';
+			this.popup.find("p.discojuice_moreLinkContainer").empty().append(moreLink);
+			this.popup.find("p.discojuice_moreLinkContainer a.discojuice_showmore").click(function(e) {
+				event.preventDefault();
+				that.control.increase();
+			});
+		} else {
+			this.popup.find("p.discojuice_moreLinkContainer").empty();
+			if (listcount > 10) {
+				var moreLink = '<span style="color: #888">' + listcount + ' entries listed</span>';
+				this.popup.find("p.discojuice_moreLinkContainer").append(moreLink);
+			} 
+		}
 	},
 
 	"enable": function(control) {
+		var imgpath = this.parent.Utils.options.get('discoPath', '') + 'images/';
+		
+		var textSearch = this.parent.Utils.options.get('textSearch', 'or search for a provider, in example Univerity of Oslo');
+		var textHelp = this.parent.Utils.options.get('textHelp', 'Help me, I cannot find my provider');
+		var textHelpMore = this.parent.Utils.options.get('textHelpMore', 'If your institusion is not connected to Foodle, you may create a new account using any of the Guest providers, such as <strong>OpenIdP (Guest users)</strong>.');
+	
 		var html = 	'<div style="display: none" class="discojuice">' +
 			'<div class="top">' +
 				'<a href="#" class="discojuice_close">&nbsp;</a>' +
 				'<p class="discojuice_maintitle">' + this.parent.Utils.options.get('title', 'Title')  +  '</p>' +
 				'<p class="discojuice_subtitle">' + this.parent.Utils.options.get('subtitle', 'Subtitle') + '</p>' +
 			'</div>' +
-			'<div id="content" style="">' +
-				'<p class="moretext"></p>' +
-				'<div class="scroller"></div>' +
+			
+			'<div class="discojuice_listContent" style="">' +
+				'<div class="scroller">' +
+					'<div class="loadingData" ><img src="' + imgpath + 'spinning.gif" /> Loading list of providers...</div>' +
+				'</div>' +
+				'<p class="discojuice_moreLinkContainer" style="margin: 0px; padding: 4px">&nbsp;</p>' +
 			'</div>' +
 	
 			'<div id="search" class="" >' +
-				'<p><input type="search" class="discojuice_search" results=5 autosave="discojuice" name="searchfield" placeholder="or search for a provider, in example Univerity of Oslo" value="" /></p>' +
+				'<p><input type="search" class="discojuice_search" results=5 autosave="discojuice" name="searchfield" placeholder="' + textSearch + '" value="" /></p>' +
 				'<div class="discojuice_whatisthis" style="margin-top: 15px; font-size: 11px;">' +
-					'<a  href="#" class="textlink discojuice_what">Help me, I cannot find my provider</a>' +
-//					'<p class="discojuice_whattext">If your institusion is not connected to Foodle, you may either select to login one of the commercial providers such as Facebook or Google, or you may create a new account using any of the Guest providers, such as Feide OpenIdP.</p>' +
-					'<p class="discojuice_whattext">If your institusion is not connected to Foodle, you may create a new account using any of the Guest providers, such as <strong>OpenIdP (Guest users)</strong>.</p>' +
+					'<a  href="#" class="textlink discojuice_what">' + textHelp + '</a>' +
+					'<p class="discojuice_whattext">' + textHelpMore + '</p>' +
 				'</div>' +
 			'</div>' +
 			
+			'<div id="locatemediv">' +
+				'<div class="locatemebefore">' +
+					'<p style="margin-top: 10px"><a id="locateme" href="">' +
+						'<img style="float: left; margin-right: 5px; margin-top: -10px" src="' + imgpath + 'target.png" alt="locate me..." />' +
+						'Locate me more accurately using HTML5 Geo-Location</a>' +
+					'</p>' +
+					'<p style="color: #999" id="locatemeinfo"></p>' +
+				'</div>' +
+				'<div style="clear: both" class="locatemeafter"></div>' +
+			'</div>' +
+			
+			'<div style="display: none">' + 
+				'<button id="discojuiceextesion_listener" />' +
+			'</div>' +
+			
 			'<div class="filters bottom">' +
-				'<p id="filterCountry"></p>' +
-				'<p id="filterType"></p>' +
-				'<p class="discojuice_showall" ><a class="discojuice_showall textlink" href="">Show all providers</a></p>' +
-				'<p style="margin 0px; text-align: right; color: #ccc; font-size: x-small">DiscoJuice &copy; 2011, UNINETT</p>' +
+				'<p style="margin 0px; text-align: right; color: #ccc; font-size: 75%">DiscoJuice &copy; UNINETT</p>' +
 			'</div>' +
 	
-// 			'<dd id="locatemediv">' +
-// 				'<img style="float: left; margin-right: 5px" src="ulx/images/target.png" alt="locate me..." />' +
-// 				'<p style="margin-top: 10px"><a id="locateme" href="">' +
-// 					'Locate me</a> to show providers nearby' +
-// 				'</p>' +
-// 				'<p style="color: #999" id="locatemeinfo"></p>' +
-// 				'<div style="clear: both" >' +
-// 				'</div>' +
-// 			'</dd>' +
+
 		'</div>';
 		var that = this;
 		
@@ -326,6 +452,9 @@ DiscoJuice.UI = {
 			});
 		}
 
+		this.popup.find("#discojuiceextesion_listener").click(function() {
+			that.control.discojuiceextension();
+		});
 
 		// Add listeners to the close button.
 		this.popup.find(".discojuice_close").click(function() {
@@ -338,77 +467,26 @@ DiscoJuice.UI = {
 		});
 
 
-// 	
-// 		
-// 		// Add listener to show all providers button.
-// 		$("p#showall a").click(function(event){
-// 			event.preventDefault();
-// 			$("select#filterCountrySelect").val('all');	
-// 			DiscoJuice.listResults(true);
-// 			$("p#showall").hide();
-// 		});
-// 		$("p#showall").hide();
-// 		
-// 		//locateMe();
-// 	
-// 		// Setup filter by type.
-// 		if (DiscoJuice.options.get('location', false) && navigator.geolocation) {
-// 			$("#locateme").click(function(event) {
-// 				event.preventDefault();
-// 				DiscoJuice.locateMe();
-// 			});
-// 		} else {
-// 			$("dd#locatemediv").hide();
-// 		}	
-// 	
-// 	
-// 		// Setup filter by type.
-// 		if (DiscoJuice.options.get('type', false)) {
-// 			DiscoJuice.filterTypeSetup();
-// 		}
-// 	
-// 	
-// 		// Setup filter by country.
-// 		if (DiscoJuice.options.get('country', false)) {
-// 			DiscoJuice.filterCountrySetup();
-// 		}
-// 		
-// 		
-
-// 		
-// 			
-// 		if (DiscoJuice.options.get('location', false)) {
-// 			$("#locateme").click(function(event) {
-// 				event.preventDefault();
-// 				DiscoJuice.locateMe();
-// 			});
-// 		} else {
-// 			$("dd#locatemediv").hide();
-// 		}	
-// 		
-// 		/*
-// 			Initialise the search box.
-// 			*/
-// 		$("input#ulxSearchField").autocomplete({
-// 			minLength: 2,
-// 			source: function( request, response ) {
-// 				var term = request.term;
-// 				var result;
-// 				
-// 				$("select#filterCountrySelect").val('all');
-// 							
-// 	//			$("dd#content img.spinning").show();
-// 				DiscoJuice.listResults();
-// 	//			$("dd#content img.spinning").hide();
-// 			}
-// 		});
-// 	
-// 		// List the initial results...
-// 		// DiscoJuice.listResults();
+		if (this.parent.Utils.options.get('location', false) && navigator.geolocation) {
+			var that = this;
+			$("#locateme").click(function(event) {
+				var imgpath = that.parent.Utils.options.get('discoPath', '') + 'images/';
+				event.preventDefault();
+				$("div.locatemebefore").hide();
+				$("div.locatemeafter").html('<div class="loadingData" ><img src="' + imgpath + 'spinning.gif" /> Getting your location...</div>');
+				that.control.locateMe();
+			});
+		} else {
+			$("dd#locatemediv").hide();
+		}	
 
 	
 	},
 	
+	"setLocationText": function(html) {
+		return $("div.locatemeafter").html(html);
+	},
+	
 	"addContent": function(html) {
 		return $(html).appendTo($("body"));
 	},
@@ -439,6 +517,13 @@ DiscoJuice.Control = {
 	// Set filter values to filter the result.
 	"filters": {},
 	
+	"location": null,
+	"showdistance": false,
+
+	"maxhits": 25,
+	
+	"extensionResponse": null,
+	
 	/*
 	 * Fetching JSON Metadata using AJAX.
 	 * Callback postLoad is called when data is returned.
@@ -453,51 +538,248 @@ DiscoJuice.Control = {
 		
 		$.getJSON(metadataurl, function(data) {
 			that.data = data;
-			that.parent.Utils.log('Successfully loaded metadata');
+			that.parent.Utils.log('Successfully loaded metadata (' + data.length + ')');
 			that.postLoad();
 		});
+		
+		
 	},
 	
 	"postLoad": function() {
 		if (!this.data) return;
+		
+		// Iterate through entities, and update title from DisplayNames to support Shibboleth integration.
+		for(i = 0; i < this.data.length; i++) {
+			if (!this.data[i].title) {
+				if (this.data[i].DisplayNames) {
+					this.data[i].title = this.data[i].DisplayNames[0].value;
+				}
+			}
+		}
+
+		
 		this.readCookie();
+		this.readExtensionResponse();
 		this.prepareData();
 		this.discoReadSetup();
-		this.showallSetup();
+		this.discoSubReadSetup();
 		this.searchboxSetup();		
-		this.filterCountrySetup();
+		if (this.parent.Utils.options.get('country', false)) {
+			this.filterCountrySetup();
+		}
+
 		this.getCountry();
 		
 	},
 	
 	"readCookie": function() {
 		if (this.parent.Utils.options.get('cookie', false)) {
-			var selected = this.parent.Utils.readCookie();
-			this.parent.Utils.log('COOKIE read ' + selected);
-			if(selected) this.setWeight(selected, -100);			
+			var selectedRelID = this.parent.Utils.readCookie();
+			
+			var entityID = selectedRelID;
+			var subID = undefined;
+			if (selectedRelID && selectedRelID.match(/^.*#.+?$/)) {
+				var matched = /^(.*)#(.+?)$/.exec(selectedRelID);
+				entityID = matched[1];
+				subID = matched[2];
+			}
+			
+			this.parent.Utils.log('COOKIE read ' + selectedRelID);
+			if(selectedRelID) this.setWeight(-100, entityID, subID);
 		}
 	},
 	
+	"readExtensionResponse": function() {
+	
+		if (!this.extensionResponse) return;
+		
+		if(!!this.extensionResponse.autologin) {
+			this.selectProvider(this.extensionResponse.entityID, this.extensionResponse.subID);
+		}
+
+		if(this.extensionResponse.selectedRelID) {
+			this.setWeight(-100, this.extensionResponse.entityID, this.extensionResponse.subID);
+		}
+		this.parent.Utils.log('DiscoJuice Extension readExtensionResponse ' + this.extensionResponse.entityID + ' ' + this.extensionResponse.subID);
+
+	},
+
+	
+	"discojuiceextension": function() {
+		
+// 		console.log('Listener activated...');
+		
+//		this.ui.show();
+	
+		var selectedRelID = $("meta#discojuiceextension_id").attr('content');
+		if (!selectedRelID) return;
+		
+// 		console.log('Value found: ' + selectedRelID);
+		
+		var entityID = selectedRelID;
+		var subID = undefined;
+		if (selectedRelID && selectedRelID.match(/^.*#.+?$/)) {
+			var matched = /^(.*)#(.+?)$/.exec(selectedRelID);
+			entityID = matched[1];
+			subID = matched[2];
+		}
+		
+		this.parent.Utils.log('DiscoJuice Extension read ' + selectedRelID + ' ' + entityID + ' ' + subID);
+		
+		var autologin = $("meta#discojuice_autologin").attr('content');
+		
+		this.extensionResponse = {
+			selectedRelID: selectedRelID,
+			entityID: entityID,
+			subID: subID,
+			autologin: autologin
+		};
+
+		
+	},
+	
 	
 	
 	/*
 	 * Set weight to a specific data entry.
 	 */
-	"setWeight": function(entityid, weight) {
+	"setWeight": function(weight, entityID, subID) {
 		for(i = 0; i < this.data.length; i++) {
-			if (this.data[i].entityid == entityid) {
-				if (isNaN(this.data[i].weight)) this.data[i].weight = 0;
-				this.data[i].weight += weight;
-				this.parent.Utils.log('COOKIE Setting weight to ' + this.data[i].weight);
+			if (this.data[i].entityID !== entityID) continue;				
+			if (subID && !this.data[i].subID) continue;
+			if (subID && subID !== this.data[i].subID) continue;
+			if (this.data[i].subID && !subID) continue;
+
+			if (isNaN(this.data[i].weight)) this.data[i].weight = 0;
+			this.data[i].weight += weight;
+			this.parent.Utils.log('COOKIE Setting weight to ' + this.data[i].weight);
+			return;
+		}
+		this.parent.Utils.log('DiscoJuice setWeight failer (no entries found for) ' + entityID + ' # ' + subID);
+	},
+	
+	"discoResponse": function(sender, entityID, subID) {
+		this.parent.Utils.log('DiscoResponse Received from [' + sender  + '] entityID: ' + entityID + ' subID: ' + subID);
+		
+		var settings = this.parent.Utils.options.get('disco');
+		if (settings) {
+			var stores = settings.subIDstores;
+			if (stores) {
+				if (stores[entityID] && !subID) {
+					this.parent.Utils.log('Ignoring discoResponse from entityID: ' + entityID + ' because subID was required and not provided');
+					return;
+				}
 			}
 		}
+		
+		this.setWeight(-100, entityID, subID);
+		this.prepareData();
 	},
 	
-	"discoResponse": function(entityid) {
-		this.setWeight(entityid, -100);
+	"calculateDistance": function() {
+		var targets, distances;
+		for(var i = 0; i < this.data.length; i++) {
+			if (this.data[i].geo) {
+				
+				targets = [];
+				distances = [];
+				
+				// Support multiple geo coordinates. Make targets be an array of targets.
+				if (typeof(this.data[i].geo)=='object' && (this.data[i].geo instanceof Array)) {
+					targets = this.data[i].geo;
+				} else {
+					targets.push(this.data[i].geo);
+				}
+
+// 				console.log('targets'); console.log(targets);
+				
+				
+				// Iterate through all targets, and stuff the distances in to 'distances'.
+				for(var j = 0; j < targets.length; j++) {
+			
+// 					console.log(targets[j]);
+					distances.push(
+						this.parent.Utils.calculateDistance(targets[j].lat, targets[j].lon, this.location[0], this.location[1])
+					);
+				}
+				this.data[i].distance = Math.min.apply( Math, distances);
+				
+// 				console.log('distances'); console.log(distances);
+// 				console.log('distance'); console.log(this.data[i].distance);
+			
+// 				this.data[i].distance = this.parent.Utils.calculateDistance(
+// 					this.data[i].geo.lat, this.data[i].geo.lon, this.location[0], this.location[1]
+// 				);
+				
+				this.data[i].distanceweight = (2 * Math.log(this.data[i].distance + 1)) - 10;
+				
+//				console.log('object'); console.log(this.data[i]);
+			}
+		}
+// 		for(i = 0; i < this.data.length; i++) {
+// 			if (this.data[i].distance) {
+// 				console.log('Distance for [' + this.data[i].title + '] ' + this.data[i].distance);
+// 			} else {
+// 				console.log('Distance for [' + this.data[i].title + '] NA');
+// 			}
+// 		}
+		this.showdistance = true;
 		this.prepareData();
 	},
 	
+	"locateMe": function() {
+		var that = this;
+		this.parent.Utils.log('Locate Me');
+		
+		if (navigator.geolocation) {
+			navigator.geolocation.getCurrentPosition( 
+	
+				function (position) {  
+	
+					// Did we get the position correctly?
+					// alert (position.coords.latitude);
+	
+					// To see everything available in the position.coords array:
+					// for (key in position.coords) {alert(key)}
+	
+					//console.log('You are here: lat ' + position.coords.latitude + ' lon ' + position.coords.longitude);
+					
+					that.ui.setLocationText('You are here: ' + position.coords.latitude + ', ' + position.coords.longitude + '. Nearby providers shown on top.');
+					
+					that.location = [position.coords.latitude, position.coords.longitude];
+					that.calculateDistance();
+					
+				}, 
+				// next function is the error callback
+				function (error) {
+					switch(error.code) {
+						case error.TIMEOUT:
+							that.ui.setLocationText('Timeout');
+							break;
+						case error.POSITION_UNAVAILABLE:
+							that.ui.setLocationText('Position unavailable');
+							break;
+						case error.PERMISSION_DENIED:
+							that.ui.setLocationText('Permission denied');
+							break;
+						case error.UNKNOWN_ERROR:
+							that.ui.setLocationText('Unknown error');
+							break;
+					}
+				}
+			);
+		} else {
+			this.parent.Utils.log('Did not find navigator.geolocation');
+		}
+		
+	},
+	
+	"increase": function() {
+		
+		this.maxhits += 100;
+		this.prepareData();
+		
+	},
 	
 	"prepareData": function(showall) {
 	
@@ -506,40 +788,35 @@ DiscoJuice.Control = {
 		this.parent.Utils.log('DiscoJuice.Control prepareData()');
 		
 		var hits, i, current, search;
- 		var maxhits = 10;
-// 		
+		var someleft = false;
+
  		var term = this.getTerm();
  		var categories = this.getCategories();
-// 	
-// 		var textIcon = '';
-		
+
 		if (!this.data) return;
 		
 		/*
 		 * Sort data by weight...
 		 */
 		this.data.sort(function(a, b) {
+		
+			// Weight
 			var xa, xb;		
 			xa = (a.weight ? a.weight : 0);
 			xb = (b.weight ? b.weight : 0);
+			
+			if (a.distanceweight) xa += a.distanceweight;
+			if (b.distanceweight) xb += b.distanceweight;
+
 			return (xa-xb);
 		});
 		
-		if (term || categories) {
+		if (term || categories) {
 			this.ui.popup.find("p.discojuice_showall").show();
 		} else {
 			this.ui.popup.find("p.discojuice_showall").hide();
 		}
-		if (categories) {
-			maxhits = 25;
-		}
-		if (showall) {
-			maxhits = 200;
-		}
-// 		if (term) {
-// 			maxhits = 10;
-// 		}
-	
+
 		this.ui.clearItems();
 		
 		hits = 0;
@@ -567,83 +844,68 @@ DiscoJuice.Control = {
 // 				if (categories.type !== current.ctype && current.weight > -50) continue;
 // 			}
 
-			if (++hits > maxhits) { //  && showall !== true) {
-				this.ui.popup.find("p.discojuice_showall").show();
+			if (++hits > this.maxhits) {
+				someleft = true;
 				break;
 			}
 			
 	// 		DiscoJuice.log('Accept: ' + current.title);
 	
-			if (search === true) {
-				if (current.descr) {
-					this.ui.addItem(current, current.descr);
-				} else if (current.country) {
-					var cname = (this.parent.Constants.Countries[current.country] ? this.parent.Constants.Countries[current.country] : current.country);
-					if (cname === '_all_') cname = '';
-					var cflag = (this.parent.Constants.Flags[current.country] ? this.parent.Constants.Flags[current.country] : undefined);
-					this.ui.addItem(current, cname, cflag);
-				} else {
-					this.ui.addItem(current);
-				}
-
-			} else if (search === null) {
-//				this.ui.addItem(current);
-
+			var countrydef = null;
+			if (current.country) {
 				var cname = (this.parent.Constants.Countries[current.country] ? this.parent.Constants.Countries[current.country] : current.country);
-				if (cname === '_all_') cname = '';
-				var cflag = (this.parent.Constants.Flags[current.country] ? this.parent.Constants.Flags[current.country] : undefined);
-
-
-				if (current.descr) {
-					this.ui.addItem(current, current.descr, cflag);
-				} else if (!categories.country && current.country) {
-					this.ui.addItem(current, cname, cflag);
-				} else {
-					this.ui.addItem(current);
+				if (cname !== '_all_')  {
+					var cflag = (this.parent.Constants.Flags[current.country] ? this.parent.Constants.Flags[current.country] : undefined);
+					countrydef = {'country': cname, 'flag': cflag};
 				}
-
-			} else {
-				this.ui.addItem(current, search);
 			}
+	
+			var descr = current.descr || null;
+	
+			// addItem(item, {country, flag}, keywordmatch, distance)
+			this.ui.addItem(current, countrydef, search, current.distance);
 
 		}
-		if (hits < maxhits) { //  && showall !== true) {
-//			this.ui.popup.find("p.discojuice_showall").hide();
-		}
 		
-		this.ui.refreshData();
-		
-		//log('Loaded ' + DiscoJuice.data.length + ' accounts to select from');
+		this.ui.refreshData(someleft, this.maxhits, hits);
 	},
 	
-	"discoWrite": function(entityid) {
-		
-	},
 	
-	"selectProvider": function(entityid) {			
+	"selectProvider": function(entityID, subID) {
+	
+		// console.log('entityid: '  + entityID);
+	
 		var callback;
 		var that = this;
-		var mustwait = that.discoWrite(entityid);
+		var mustwait = that.discoWrite(entityID, subID);
 		
 		if (this.parent.Utils.options.get('cookie', false)) {
-			this.parent.Utils.log('COOKIE write ' + entityid);
-			this.parent.Utils.createCookie(entityid);		
+			var relID = entityID;
+			if (subID) relID += '#' + subID;
+			
+			this.parent.Utils.log('COOKIE write ' + relID);
+			this.parent.Utils.createCookie(relID);
 		}
 
 		var entity = null;
 		for(i = 0; i < this.data.length; i++) {
-			if (this.data[i].entityid == entityid) {
-				entity = this.data[i];
+			if (this.data[i].entityID == entityID) {
+				if (!subID || subID == this.data[i].subID) {
+					entity = this.data[i];
+				}
 			}
 		}
 
-		console.log(entity);
+// 		console.log('Entity Selected');
+// 		console.log(entity);
+// 		return;
 
 		callback = this.parent.Utils.options.get('callback');	
 		if (callback) {
 			if (mustwait) {
 				$.doTimeout(1000, function(){
 					callback(entity);
+					// alert('done');
 				});
 				
 			} else {
@@ -657,6 +919,7 @@ DiscoJuice.Control = {
 	// Setup an iframe to read discovery cookies from other domains
 	"discoReadSetup": function() {
 		var settings = this.parent.Utils.options.get('disco');
+		
 		if (!settings) return;
 	
 		var html = '';
@@ -670,16 +933,42 @@ DiscoJuice.Control = {
 		
 		for(i = 0; i < stores.length; i++) {
 			currentStore = stores[i];
-			
+			this.parent.Utils.log('Setting up DisoJuice Read from Store [' + currentStore + ']');
 			iframeurl = currentStore + '?entityID=' + escape(spentityid) + '&isPassive=true&returnIDParam=entityID&return=' + escape(returnurl);
-			
+			html = '<iframe src="' + iframeurl + '" style="display: none"></iframe>';
+			this.ui.addContent(html);
+		}
+	},
+	
+	// Setup an iframe to read discovery cookies from other domains
+	"discoSubReadSetup": function() {
+		var settings = this.parent.Utils.options.get('disco');
+		
+		if (!settings) return;
+	
+		var html = '';
+		var returnurl = settings.url;
+		var spentityid = settings.spentityid;
+		var stores = settings.subIDstores;
+		var i;
+		var currentStore;
+		
+		if (!stores) return;
+		
+		for(var idp in stores) {
+			returnurl = settings.url + 'entityID=' + escape(idp);
+			currentStore = stores[idp];
+			this.parent.Utils.log('Setting up SubID DisoJuice Read from Store [' + idp + '] =>  [' + currentStore + ']');
+			iframeurl = currentStore + '?entityID=' + escape(spentityid) + '&isPassive=true&returnIDParam=subID&return=' + escape(returnurl);
+			this.parent.Utils.log('iFrame URL is  [' + iframeurl + ']');
+			this.parent.Utils.log('return URL is  [' + returnurl + ']');
 			html = '<iframe src="' + iframeurl + '" style="display: none"></iframe>';
 			this.ui.addContent(html);
 		}
 	},
 
 
-	"discoWrite": function(e) {
+	"discoWrite": function(entityID, subID) {
 	
 		var settings = this.parent.Utils.options.get('disco');
 		if (!settings) return false;
@@ -690,10 +979,32 @@ DiscoJuice.Control = {
 		var spentityid = settings.spentityid;
 		var writableStore = settings.writableStore;
 		
-		this.parent.Utils.log('DiscoJuice.Control discoWrite(' + e + ') to ' + writableStore);
+		if (subID) {
+			
+			if (settings.subIDwritableStores && settings.subIDwritableStores[entityID]) {
+			
+				writableStore = settings.subIDwritableStores[entityID];
+				
+				this.parent.Utils.log('DiscoJuice.Control discoWrite(' + entityID + ') with SubID [' + subID + ']');
+					
+				iframeurl = writableStore + escape(subID);
+				this.parent.Utils.log('DiscoJuice.Control discoWrite iframeURL (' + iframeurl + ') ');
+					
+				html = '<iframe src="' + iframeurl + '" style="display: none"></iframe>';
+				this.ui.addContent(html);
+				return true;
+				
+			
+			} else {
+				return false;
+			}
+			
+		}
+		
+		this.parent.Utils.log('DiscoJuice.Control discoWrite(' + entityID + ') to ' + writableStore);
 			
 		iframeurl = writableStore + '?entityID=' + escape(spentityid) + '&IdPentityID=' + 
-			escape(e) + '&isPassive=true&returnIDParam=bogus&return=' + escape(returnurl);
+			escape(entityID) + '&isPassive=true&returnIDParam=bogus&return=' + escape(returnurl);
 			
 		html = '<iframe src="' + iframeurl + '" style="display: none"></iframe>';
 		this.ui.addContent(html);
@@ -744,7 +1055,9 @@ DiscoJuice.Control = {
 				ftext += '<option value="' + key + '" >' + this.parent.Constants.Countries[key] + '</option>';
 			}
 		}
-		ftext += '</select></p>';
+		ftext += '</select>';
+		ftext += ' <a class="discojuice_showall textlink" href="">show all countries</a>';
+		ftext += '</p>';
 		
 		this.ui.addFilter(ftext).find("select").change(function(event) {
 			event.preventDefault();
@@ -752,8 +1065,22 @@ DiscoJuice.Control = {
 			//DiscoJuice.listResults();
 			that.resetTerm();
 			that.ui.focusSearch();
+			if (that.ui.popup.find("select.discojuice_filterCountrySelect").val() !== 'all') {
+				that.ui.popup.find("a.discojuice_showall").show();
+			} else {
+				that.ui.popup.find("a.discojuice_showall").hide();
+			}
 			that.prepareData();
 		});
+		this.ui.popup.find("a.discojuice_showall").click(function(event) {
+			event.preventDefault();
+			that.resetCategories();
+			that.resetTerm();
+			that.prepareData(true);
+			that.ui.focusSearch();
+			that.ui.popup.find("a.discojuice_showall").hide();
+		});
+		
 	},
 	"setCountry": function(country) {
 		if (this.parent.Constants.Countries[country]) {
@@ -761,6 +1088,10 @@ DiscoJuice.Control = {
 			this.prepareData();		
 		}
 	},
+	"setPosition": function(lat, lon) {
+		this.location = [lat, lon];
+		this.calculateDistance();
+	},
 	"getCountry": function() {
 		// If countryAPI is set, then lookup by IP.
 		var countryapi = this.parent.Utils.options.get('countryAPI', false);
@@ -768,21 +1099,34 @@ DiscoJuice.Control = {
 		
 		if (countryapi) {
 			
-			var countrycache = this.parent.Utils.readCookie('Country');
+			var countrycache = this.parent.Utils.readCookie('Country2');
+			var geocachelat = parseFloat(this.parent.Utils.readCookie('GeoLat'));
+			var geocachelon = parseFloat(this.parent.Utils.readCookie('GeoLon'));
 		
 			if (countrycache) {
 				
 				this.setCountry(countrycache);
 				this.parent.Utils.log('DiscoJuice getCountry() : Found country in cache: ' + countrycache);
 				
+				if (geocachelat && geocachelon) {
+					this.setPosition(geocachelat, geocachelon);
+				}
+				
 			} else {
 				
 				$.getJSON(countryapi, function(data) {
 		//			DiscoJuice.log(data);
 					if (data.status == 'ok' && data.country) {
-						that.parent.Utils.createCookie(data.country, 'Country');
+						that.parent.Utils.createCookie(data.country, 'Country2');
 						that.setCountry(data.country);
 						that.parent.Utils.log('DiscoJuice getCountry() : Country lookup succeeded: ' + data.country);
+						
+						if (data.geo && data.geo.lat && data.geo.lon) {
+							that.setPosition(data.geo.lat, data.geo.lon);
+							that.parent.Utils.createCookie(data.geo.lat, 'GeoLat');
+							that.parent.Utils.createCookie(data.geo.lon, 'GeoLon');
+						}
+						
 					} else {
 						that.parent.Utils.log('DiscoJuice getCountry() : Country lookup failed: ' + (data.error || ''));
 					}
@@ -792,17 +1136,7 @@ DiscoJuice.Control = {
 		}
 	},
 	
-	"showallSetup": function() {
-		var that = this;
-		this.ui.popup.find("a.discojuice_showall").click(function(event) {
-			event.preventDefault();
-			that.resetCategories();
-			that.resetTerm();
-			that.prepareData(true);
-			that.ui.focusSearch();
-		});
-	},
-	
+
 	"resetCategories": function() {
 		//this.ui.popup.find("select.discojuice_filterTypeSelect").val()
 		this.ui.popup.find("select.discojuice_filterCountrySelect").val('all');
@@ -834,7 +1168,7 @@ DiscoJuice.Control = {
 	"resetTerm": function() {
 		//this.ui.popup.find("select.discojuice_filterTypeSelect").val()
 		this.ui.popup.find("input.discojuice_search").val('');
-	},
+	}
 
 
 };
\ No newline at end of file
diff --git a/modules/discojuice/www/discojuice/discojuice.min.js b/modules/discojuice/www/discojuice/discojuice.min.js
new file mode 100644
index 000000000..ec38d5b69
--- /dev/null
+++ b/modules/discojuice/www/discojuice/discojuice.min.js
@@ -0,0 +1 @@
+(function($3){var $5={},$6="doTimeout",$7=Array.prototype.slice;$3[$6]=function(){return $4.apply(window,[0].concat($7.call(arguments)));};$3.fn[c]=function(){var $11=$7.call(arguments),$9=$4.apply(this,[$6+$11[0]].concat($11));return typeof $11[0]==="number"||typeof $11[1]==="number"?this:$9;};function $4($8){var $b=this,$c,$d={},$e=$8?$3.fn:$3,$f=arguments,$10=4,$11=$f[1],$12=$f[2],$13=$f[3];if(typeof $11!=="string"){$10--;$11=$8=0;$12=$f[1];$13=$f[2];}if($8){$c=$b.eq(0);$c.data($8,$d=$c.data($8)||{});}else {if($11){$d=$5[$11]||($5[$11]={});}}$d.id&&clearTimeout($d.id);delete $d.id;function $9(){if($8){$c.removeData($8);}else {if($11){delete $5[$11];}}}function $a(){$d.id=setTimeout(function(){$d.fn();},$12);}if($13){$d.fn=function($14){if(typeof $13==="string"){$13=$e[$13];}$13.apply($b,$7.call($f,$10))===true&&!$14?$a():$9();};$a();}else {if($d.fn){$12===undefined?$9():$d.fn($12===false);return true;}else {$9();}}}})(jQuery);if(typeof console=="undefined")var $1={log:function(){;}};var $2={};$2.Constants={"Countries":{'CZ':'Czech','DK':'Denmark','FI':'Finland','FR':'France','DE':'Germany','GR':'Greece','HR':'Croatia','IE':'Ireland','IT':'Italy','HU':'Hungary','LU':'Luxembourg','NL':'Netherlands','NO':'Norway','PL':'Poland','PT':'Portugal','SI':'Slovenia','ES':'Spain','SE':'Sweden','CH':'Switzerland','TR':'Turkey','US':'USA','GB':'UK','XX':'Experimental'},"Flags":{'CZ':'cz.png','DK':'dk.png','FI':'fi.png','FR':'fr.png','DE':'de.png','GR':'gr.png','HR':'hr.png','IE':'ie.png','IT':'it.png','HU':'hu.png','LU':'lu.png','NL':'nl.png','NO':'no.png','PL':'pl.png','PT':'pt.png','SI':'si.png','ES':'es.png','SE':'se.png','CH':'ch.png','TR':'tr.png','GB':'gb.png','US':'us.png'}};$2.Utils={"log":function($15){$1.log($15);},"options":function(){var $16;return {"get":function($17,$18){if(!$16)return $18;if(!$16[$17])return $18;return $16[$17];},"set":function($19){$16=$19;},"update":function($17,$1a){$16[$17]=$1a;}};}(),"createCookie":function($1a,$1b){var $1b=$1b||'EntityID';var $1c='_DiscoJuice_'+$1b;var $1d=1825;if($1d){var $1e=new Date();$1e.setTime($1e.getTime()+($1d*24*60*60*1000));var $1f="; expires="+$1e.toGMTString();}else var $1f="";document.cookie=$1c+"="+escape($1a)+$1f+"; path=/";},"readCookie":function($1b){var $1b=$1b||'EntityID';var $1c='_DiscoJuice_'+$1b;var $1d=1825;var $20=$1c+"=";var $21=document.cookie.split(';');for(var $10=0;$10<$21.length;$10++){var $6=$21[$10];while($6.charAt(0)==' ')$6=$6.substring(1,$6.length);if($6.indexOf($20)==0)return unescape($6.substring($20.length,$6.length));}return null;},"eraseCookie":function($1b){var $1b=$1b||'EntityID';var $1c='_DiscoJuice_'+$1b;$2.createCookie($1c,"",-1);},"searchMatch":function($22,$23){if($22.title.toLowerCase().search($23.toLowerCase())!==-1)return true;var $17,$10,$24;if($22.keywords){for($17 in $22.keywords){$24=$22.keywords[key];for($10=0;$10<$24.length;$10++){if($24[$10].toLowerCase().search($23.toLowerCase())!==-1)return $24[$10];}}}return false;},"calculateDistance":function($25,$26,$27,$28){var $29=6371;var $2a=this.toRad($27-$25);var $2b=this.toRad($28-$26);var $5=Math.sin($2a/2)*Math.sin($2a/2)+Math.cos(this.toRad($25))*Math.cos(this.toRad($27))*Math.sin($2b/2)*Math.sin($2b/2);var $6=2*Math.atan2(Math.sqrt($5),Math.sqrt(1-$5));var $7=$29*$6;return $7;},"toRad":function($2c){return $2c*Math.PI/180;}};(function($3){$3.fn.DiscoJuice=function($16){return this.each(function(){$2.Utils.options.set($16);$2.Control.ui=$2.UI;$2.UI.control=$2.Control;$2.UI.enable(this);});};})(jQuery);if(typeof $2=="undefined")var $2={};$2.UI={"parent":$2,"control":null,"popup":null,"resulthtml":'Loading data…',"show":function(){this.control.load();this.popup.fadeIn("slow");$("div#discojuice_overlay").show();this.focusSearch();},"focusSearch":function(){$("input.discojuice_search").focus();},"hide":function(){$("div#discojuice_overlay").fadeOut("slow");this.popup.fadeOut("slow");},"clearItems":function(){this.resulthtml='';},"addItem":function($22,$2d,$2e,$2f){var $30='';var $31='';if($22.weight<-50)$31+='hothit';var $32=this.parent.Utils.options.get('discoPath','')+'logos/';var $33=this.parent.Utils.options.get('discoPath','')+'flags/';var $34=false;var $35=this.parent.Utils.options.get('debug.weight',false);if($22.icon){$30+='<img class="logo" src="'+$32+$22.icon+'" />';$34=true;}$30+='<span class="title">'+$22.title+'</span>';if($2e&&$2e!==true){$30+='<span class="substring">– '+$2e+'</span>';}else if($22.descr){$30+='<span class="substring">– '+$22.descr+'</span>';}if($2d||($2f!=undefined)){$30+='<span class="location">';if($2d){$30+='<span class="country">';if($2d.flag)$30+='<img src="'+$33+$2d.flag+'" alt="'+escape($2d.country)+'" /> ';$30+=$2d.country+'</span>';}if($2f!=undefined){if($2f<1){$30+='<span class="distance">Nearby</span>';}else {$30+='<span class="distance">'+Math.round($2f)+' km'+'</span>';}}$30+='</span>';}if($35){$30+='<div class="debug">';if($22.subID){$30+='<input value="'+$22.subID+'" />';}var $36=0;if($22.weight){$36+=$22.weight;}if($22.distanceweight){$36+=$22.distanceweight;}$30+='Weight <strong style="color: #888">'+Math.round(100*$36)/100+'</strong> ';if($22.weight){$30+=' (base '+$22.weight+')   ';}if($22.distanceweight){$30+='(dist '+Math.round(100*$22.distanceweight)/100+')';}$30+='</div>';}if($34){$30+='<hr style="clear: both; height: 0px; visibility:hidden" />';}var $37=$22.entityID;if($22.subID){$37+='#'+$22.subID;}$30='<a href="" class="'+$31+'" rel="'+escape($37)+'" title="'+escape($22.title)+'">'+$30+'</a>';this.resulthtml+=$30;},"refreshData":function($38,$39,$3a){var $3b=this;this.parent.Utils.log('DiscoJuice.UI refreshData()');this.popup.find("div.scroller").empty().append(this.resulthtml);this.popup.find("div.scroller a").each(function(){var $3d=$3b;$(this).click(function($3e){$3e.preventDefault();$3d.hide();var $37=unescape($(this).attr('rel'));var $3f=$37;var $40=undefined;if($37.match(/^.*#.+?$/)){var $41=/^(.*)#(.+?)$/.exec($37);$3f=$41[1];$40=$41[2];}$3d.control.selectProvider($3f,$40);});});if($38){var $3c='<a class="discojuice_showmore textlink" href="">Results limited to '+$39+' entries – show more…</a>';this.popup.find("p.discojuice_moreLinkContainer").empty().append($3c);this.popup.find("p.discojuice_moreLinkContainer a.discojuice_showmore").click(function($9){event.preventDefault();$3b.control.increase();});}else {this.popup.find("p.discojuice_moreLinkContainer").empty();if($3a>10){var $3c='<span style="color: #888">'+$3a+' entries listed</span>';this.popup.find("p.discojuice_moreLinkContainer").append($3c);}}},"enable":function($42){var $43=this.parent.Utils.options.get('discoPath','')+'images/';var $44=this.parent.Utils.options.get('textSearch','or search for a provider, in example Univerity of Oslo');var $45=this.parent.Utils.options.get('textHelp','Help me, I cannot find my provider');var $46=this.parent.Utils.options.get('textHelpMore','If your institusion is not connected to Foodle, you may create a new account using any of the Guest providers, such as <strong>OpenIdP (Guest users)</strong>.');var $47='<div style="display: none" class="discojuice">'+'<div class="top">'+'<a href="#" class="discojuice_close">&nbsp;</a>'+'<p class="discojuice_maintitle">'+this.parent.Utils.options.get('title','Title')+'</p>'+'<p class="discojuice_subtitle">'+this.parent.Utils.options.get('subtitle','Subtitle')+'</p>'+'</div>'+'<div class="discojuice_listContent" style="">'+'<div class="scroller">'+'<div class="loadingData" ><img src="'+$43+'spinning.gif" /> Loading list of providers...</div>'+'</div>'+'<p class="discojuice_moreLinkContainer" style="margin: 0px; padding: 4px">&nbsp;</p>'+'</div>'+'<div id="search" class="" >'+'<p><input type="search" class="discojuice_search" results=5 autosave="discojuice" name="searchfield" placeholder="'+$44+'" value="" /></p>'+'<div class="discojuice_whatisthis" style="margin-top: 15px; font-size: 11px;">'+'<a  href="#" class="textlink discojuice_what">'+$45+'</a>'+'<p class="discojuice_whattext">'+$46+'</p>'+'</div>'+'</div>'+'<div id="locatemediv">'+'<div class="locatemebefore">'+'<p style="margin-top: 10px"><a id="locateme" href="">'+'<img style="float: left; margin-right: 5px; margin-top: -10px" src="'+$43+'target.png" alt="locate me..." />'+'Locate me more accurately using HTML5 Geo-Location</a>'+'</p>'+'<p style="color: #999" id="locatemeinfo"></p>'+'</div>'+'<div style="clear: both" class="locatemeafter"></div>'+'</div>'+'<div style="display: none">'+'<button id="discojuiceextesion_listener" />'+'</div>'+'<div class="filters bottom">'+'<p style="margin 0px; text-align: right; color: #ccc; font-size: 75%">DiscoJuice &copy; UNINETT</p>'+'</div>'+'</div>';var $3b=this;if(this.parent.Utils.options.get('overlay',true)===true){var $48='<div id="discojuice_overlay" style="display: none"></div>';$($48).appendTo($("body"));}this.popup=$($47).appendTo($("body"));if(this.parent.Utils.options.get('always',false)===true){this.popup.find(".discojuice_close").hide();this.show();}else {$($42).click(function($3e){$3e.preventDefault();$3b.show();return false;});}this.popup.find("#discojuiceextesion_listener").click(function(){$3b.control.discojuiceextension();});this.popup.find(".discojuice_close").click(function(){$3b.hide();});this.popup.find(".discojuice_what").click(function(){$3b.popup.find(".discojuice_whatisthis").toggleClass("show");});if(this.parent.Utils.options.get('location',false)&&navigator.geolocation){var $3b=this;$("#locateme").click(function($3e){var $43=$3b.parent.Utils.options.get('discoPath','')+'images/';$3e.preventDefault();$("div.locatemebefore").hide();$("div.locatemeafter").$47('<div class="loadingData" ><img src="'+$43+'spinning.gif" /> Getting your location...</div>');$3b.control.locateMe();});}else {$("dd#locatemediv").hide();}},"setLocationText":function($47){return $("div.locatemeafter").$47($47);},"addContent":function($47){return $($47).appendTo($("body"));},"addFilter":function($47){return $($47).prependTo(this.popup.find('.filters'));}};if(typeof $2=="undefined")var $2={};$2.Control={"parent":$2,"ui":null,"data":null,"filters":{},"location":null,"showdistance":false,"maxhits":25,"extensionResponse":null,"load":function(){var $3b=this;if(this.data)return ;var $49=this.parent.Utils.options.get('metadata');this.parent.Utils.log('metadataurl is '+$49);if(!$49)return ;$.getJSON($49,function($4a){$3b.data=$4a;$3b.parent.Utils.log('Successfully loaded metadata ('+$4a.length+')');$3b.postLoad();});},"postLoad":function(){if(!this.data)return ;for(i=0;i<this.data.length;i++){if(!this.data[i].title){if(this.data[i].DisplayNames){this.data[i].title=this.data[i].DisplayNames[0].value;}}}this.readCookie();this.readExtensionResponse();this.prepareData();this.discoReadSetup();this.discoSubReadSetup();this.searchboxSetup();if(this.parent.Utils.options.get('country',false)){this.filterCountrySetup();}this.getCountry();},"readCookie":function(){if(this.parent.Utils.options.get('cookie',false)){var $4b=this.parent.Utils.readCookie();var $3f=$4b;var $40=undefined;if($4b&&$4b.match(/^.*#.+?$/)){var $41=/^(.*)#(.+?)$/.exec($4b);$3f=$41[1];$40=$41[2];}this.parent.Utils.log('COOKIE read '+$4b);if($4b)this.setWeight(-100,$3f,$40);}},"readExtensionResponse":function(){if(!this.extensionResponse)return ;if(!!this.extensionResponse.autologin){this.selectProvider(this.extensionResponse.entityID,this.extensionResponse.subID);}if(this.extensionResponse.selectedRelID){this.setWeight(-100,this.extensionResponse.entityID,this.extensionResponse.subID);}this.parent.Utils.log('DiscoJuice Extension readExtensionResponse '+this.extensionResponse.entityID+' '+this.extensionResponse.subID);},"discojuiceextension":function(){var $4b=$("meta#discojuiceextension_id").attr('content');if(!$4b)return ;var $3f=$4b;var $40=undefined;if($4b&&$4b.match(/^.*#.+?$/)){var $41=/^(.*)#(.+?)$/.exec($4b);$3f=$41[1];$40=$41[2];}this.parent.Utils.log('DiscoJuice Extension read '+$4b+' '+$3f+' '+$40);var $4c=$("meta#discojuice_autologin").attr('content');this.extensionResponse={selectedRelID:$4b,entityID:$3f,subID:$40,autologin:$4c};},"setWeight":function($4d,$3f,$40){for(i=0;i<this.data.length;i++){if(this.data[i].entityID!==$3f)continue;if($40&&!this.data[i].subID)continue;if($40&&$40!==this.data[i].subID)continue;if(this.data[i].subID&&!$40)continue;if(isNaN(this.data[i].weight))this.data[i].weight=0;this.data[i].weight+=$4d;this.parent.Utils.log('COOKIE Setting weight to '+this.data[i].weight);return ;}this.parent.Utils.log('DiscoJuice setWeight failer (no entries found for) '+$3f+' # '+$40);},"discoResponse":function($4e,$3f,$40){this.parent.Utils.log('DiscoResponse Received from ['+$4e+'] entityID: '+$3f+' subID: '+$40);var $4f=this.parent.Utils.options.get('disco');if($4f){var $50=$4f.subIDstores;if($50){if($50[$3f]&&!$40){this.parent.Utils.log('Ignoring discoResponse from entityID: '+$3f+' because subID was required and not provided');return ;}}}this.setWeight(-100,$3f,$40);this.prepareData();},"calculateDistance":function(){var $51,$52;for(var $10=0;$10<this.data.length;$10++){if(this.data[i].geo){$51=[];$52=[];if(typeof (this.data[i].geo)=='object'&&(this.data[i].geo instanceof Array)){$51=this.data[i].geo;}else {$51.push(this.data[i].geo);}for(var $12=0;$12<$51.length;$12++){$52.push(this.parent.Utils.calculateDistance($51[$12].lat,$51[$12].lon,this.location[0],this.location[1]));}this.data[i].distance=Math.min.apply(Math,$52);this.data[i].distanceweight=(2*Math.log(this.data[i].distance+1))-10;}}this.showdistance=true;this.prepareData();},"locateMe":function(){var $3b=this;this.parent.Utils.log('Locate Me');if(navigator.geolocation){navigator.geolocation.getCurrentPosition(function($53){$3b.ui.setLocationText('You are here: '+$53.coords.latitude+', '+$53.coords.longitude+'. Nearby providers shown on top.');$3b.location=[$53.coords.latitude,$53.coords.longitude];$3b.calculateDistance();},function($54){switch($54.code){case $54.TIMEOUT:$3b.ui.setLocationText('Timeout');break;case $54.POSITION_UNAVAILABLE:$3b.ui.setLocationText('Position unavailable');break;case $54.PERMISSION_DENIED:$3b.ui.setLocationText('Permission denied');break;case $54.UNKNOWN_ERROR:$3b.ui.setLocationText('Unknown error');break;}});}else {this.parent.Utils.log('Did not find navigator.geolocation');}},"increase":function(){this.maxhits+=100;this.prepareData();},"prepareData":function($55){var $55=($55?true:false);this.parent.Utils.log('DiscoJuice.Control prepareData()');var $56,$10,$57,$2e;var $58=false;var $23=this.getTerm();var $59=this.getCategories();if(!this.data)return ;this.data.sort(function($5,$4){var $5d,$5e;$5d=($5.weight?$5.weight:0);$5e=($4.weight?$4.weight:0);if($5.distanceweight)$5d+=$5.distanceweight;if($4.distanceweight)$5e+=$4.distanceweight;return ($5d-$5e);});if($23||$59){this.ui.popup.find("p.discojuice_showall").show();}else {this.ui.popup.find("p.discojuice_showall").hide();}this.ui.clearItems();$56=0;for($10=0;$10<this.data.length;$10++){$57=this.data[i];if(!$57.weight)$57.weight=0;if($23){$2e=this.parent.Utils.searchMatch($57,$23);if($2e===false&&$57.weight>-50)continue;}else {$2e=null;}if($59&&$59.country){if(!$57.country)continue;if($57.country!=='_all_'&&$59.country!==$57.country&&$57.weight>-50)continue;}if(++$56>this.maxhits){$58=true;break;}var $2d=null;if($57.country){var $5a=(this.parent.Constants.Countries[current.country]?this.parent.Constants.Countries[current.country]:$57.country);if($5a!=='_all_'){var $5b=(this.parent.Constants.Flags[current.country]?this.parent.Constants.Flags[current.country]:undefined);$2d={'country':$5a,'flag':$5b};}}var $5c=$57.descr||null;this.ui.addItem($57,$2d,$2e,$57.distance);}this.ui.refreshData($58,this.maxhits,$56);},"selectProvider":function($3f,$40){var $5f;var $3b=this;var $60=$3b.discoWrite($3f,$40);if(this.parent.Utils.options.get('cookie',false)){var $37=$3f;if($40)$37+='#'+$40;this.parent.Utils.log('COOKIE write '+$37);this.parent.Utils.createCookie($37);}var $61=null;for(i=0;i<this.data.length;i++){if(this.data[i].entityID==$3f){if(!$40||$40==this.data[i].subID){$61=this.data[i];}}}$5f=this.parent.Utils.options.get('callback');if($5f){if($60){$.doTimeout(1000,function(){$5f($61);});}else {$5f($61);}return ;}},"discoReadSetup":function(){var $4f=this.parent.Utils.options.get('disco');if(!$4f)return ;var $47='';var $62=$4f.url;var $63=$4f.spentityid;var $50=$4f.stores;var $10;var $64;if(!$50)return ;for($10=0;$10<$50.length;$10++){$64=$50[$10];this.parent.Utils.log('Setting up DisoJuice Read from Store ['+$64+']');iframeurl=$64+'?entityID='+escape($63)+'&isPassive=true&returnIDParam=entityID&return='+escape($62);$47='<iframe src="'+iframeurl+'" style="display: none"></iframe>';this.ui.addContent($47);}},"discoSubReadSetup":function(){var $4f=this.parent.Utils.options.get('disco');if(!$4f)return ;var $47='';var $62=$4f.url;var $63=$4f.spentityid;var $50=$4f.subIDstores;var $10;var $64;if(!$50)return ;for(var $65 in $50){$62=$4f.url+'entityID='+escape($65);$64=$50[$65];this.parent.Utils.log('Setting up SubID DisoJuice Read from Store ['+$65+'] =>  ['+$64+']');iframeurl=$64+'?entityID='+escape($63)+'&isPassive=true&returnIDParam=subID&return='+escape($62);this.parent.Utils.log('iFrame URL is  ['+iframeurl+']');this.parent.Utils.log('return URL is  ['+$62+']');$47='<iframe src="'+iframeurl+'" style="display: none"></iframe>';this.ui.addContent($47);}},"discoWrite":function($3f,$40){var $4f=this.parent.Utils.options.get('disco');if(!$4f)return false;if(!$4f.writableStore)return false;var $47='';var $62=$4f.url;var $63=$4f.spentityid;var $66=$4f.writableStore;if($40){if($4f.subIDwritableStores&&$4f.subIDwritableStores[entityID]){$66=$4f.subIDwritableStores[entityID];this.parent.Utils.log('DiscoJuice.Control discoWrite('+$3f+') with SubID ['+$40+']');iframeurl=$66+escape($40);this.parent.Utils.log('DiscoJuice.Control discoWrite iframeURL ('+iframeurl+') ');$47='<iframe src="'+iframeurl+'" style="display: none"></iframe>';this.ui.addContent($47);return true;}else {return false;}}this.parent.Utils.log('DiscoJuice.Control discoWrite('+$3f+') to '+$66);iframeurl=$66+'?entityID='+escape($63)+'&IdPentityID='+escape($3f)+'&isPassive=true&returnIDParam=bogus&return='+escape($62);$47='<iframe src="'+iframeurl+'" style="display: none"></iframe>';this.ui.addContent($47);return true;},"searchboxSetup":function(){var $3b=this;this.ui.popup.find("input.discojuice_search").autocomplete({minLength:0,source:function($67,$68){var $23=$67.term;if($23.length===1)return ;$3b.prepareData();}});},"filterCountrySetup":function($69){var $3b=this;var $17;var $6a=this.parent.Utils.options.get('setCountry');if(!$69&&$6a){if(filterOptions[$6a])$69=$6a;}var $6b='<p class="discojuice_filter_country">Show providers in '+'<select class="discojuice_filterCountrySelect" name="filterCountrySelect">';if($69){$6b+='<option value="all">all countries</option>';}else {$6b+='<option value="all" selected="selected">all countries</option>';}for($17 in this.parent.Constants.Countries){if($17===$69){$6b+='<option value="'+$17+'" selected="selected">'+this.parent.Constants.Countries[key]+'</option>';}else {$6b+='<option value="'+$17+'" >'+this.parent.Constants.Countries[key]+'</option>';}}$6b+='</select>';$6b+=' <a class="discojuice_showall textlink" href="">show all countries</a>';$6b+='</p>';this.ui.addFilter($6b).find("select").change(function($3e){$3e.preventDefault();$3b.resetTerm();$3b.ui.focusSearch();if($3b.ui.popup.find("select.discojuice_filterCountrySelect").val()!=='all'){$3b.ui.popup.find("a.discojuice_showall").show();}else {$3b.ui.popup.find("a.discojuice_showall").hide();}$3b.prepareData();});this.ui.popup.find("a.discojuice_showall").click(function($3e){$3e.preventDefault();$3b.resetCategories();$3b.resetTerm();$3b.prepareData(true);$3b.ui.focusSearch();$3b.ui.popup.find("a.discojuice_showall").hide();});},"setCountry":function($6c){if(this.parent.Constants.Countries[country]){this.ui.popup.find('select.discojuice_filterCountrySelect').val($6c);this.prepareData();}},"setPosition":function($6d,$6e){this.location=[$6d,$6e];this.calculateDistance();},"getCountry":function(){var $6f=this.parent.Utils.options.get('countryAPI',false);var $3b=this;if($6f){var $70=this.parent.Utils.readCookie('Country2');var $71=parseFloat(this.parent.Utils.readCookie('GeoLat'));var $72=parseFloat(this.parent.Utils.readCookie('GeoLon'));if($70){this.setCountry($70);this.parent.Utils.log('DiscoJuice getCountry() : Found country in cache: '+$70);if($71&&$72){this.setPosition($71,$72);}}else {$.getJSON($6f,function($4a){if($4a.status=='ok'&&$4a.country){$3b.parent.Utils.createCookie($4a.country,'Country2');$3b.setCountry($4a.country);$3b.parent.Utils.log('DiscoJuice getCountry() : Country lookup succeeded: '+$4a.country);if($4a.geo&&$4a.geo.lat&&$4a.geo.lon){$3b.setPosition($4a.geo.lat,$4a.geo.lon);$3b.parent.Utils.createCookie($4a.geo.lat,'GeoLat');$3b.parent.Utils.createCookie($4a.geo.lon,'GeoLon');}}else {$3b.parent.Utils.log('DiscoJuice getCountry() : Country lookup failed: '+($4a.error||''));}});}}},"resetCategories":function(){this.ui.popup.find("select.discojuice_filterCountrySelect").val('all');},"getCategories":function(){var $73={};var $1b,$6c;$1b=this.ui.popup.find("select.discojuice_filterTypeSelect").val();if($1b&&$1b!=='all'){$73.type=$1b;}$6c=this.ui.popup.find("select.discojuice_filterCountrySelect").val();if($6c&&$6c!=='all'){$73.country=$6c;}return $73;},"getTerm":function(){return this.ui.popup.find("input.discojuice_search").val();},"resetTerm":function(){this.ui.popup.find("input.discojuice_search").val('');}};
-- 
GitLab