<?xml version="1.0" encoding="UTF-8" ?>
<Module>
	<ModulePrefs 
		title="__UP_title__" 
		directory_title="Google Groups Reader"
		description="Google Groups Reader. Read any Google Group via this gadget! Groups by subject, filters, auto-refresh, custom title, many styling options, etc. Makes reading Google Groups via Gadget very easy!" 
		author="Matt Kruse" 
		author_email="gadget@mattkruse.com" 
		screenshot="http://www.JavascriptToolbox.com/gadget/groups/groups.png" 
		thumbnail="http://www.JavascriptToolbox.com/gadget/groups/groups_thumb.png"
		singleton="false"
		author_affiliation="Matt Kruse" 
		author_location="IL, USA" 
		author_link="http://www.MattKruse.com/" 
		height="50"
		> 
		<Require feature="dynamic-height" /> 
		<Require feature="setprefs" /> 
		<Require feature="minimessage"/>
	</ModulePrefs>
		<UserPref name="title" display_name="Display Title:" default_value="(Edit Prefs to Change Display Title)" />
		<UserPref name="titlelink" display_name="Title Link:" default_value="" />
		<UserPref name="group" display_name="Group Name (not necessarily its display title! ex: 'jquery-en' NOT 'jQuery (English)':" default_value="" required="true" />
		<UserPref name="num" display_name="Items to show (1-100):" default_value="50"/>
		<UserPref name="format" display_name="Display Format:" default_value="&lt;div class=mc&gt;%STAR%&lt;a href=&quot;%URL%&quot; oncontextmenu=&quot;_toggle(this.nextSibling);resize();return false;&quot; title=&quot;right-click to view summary&quot; class=&quot;%A_CLASSNAME%&quot; target=&quot;%TARGET%&quot;&gt;%BULLET%%TITLE%&amp;nbsp;&lt;span style=&quot;color:#aaa;&quot;&gt;(%M%-%D%)&lt;/span&gt;&lt;/a&gt;&lt;div style=&quot;display:none&quot; class=&quot;summary&quot;&gt;%SUMMARY%&lt;/div&gt;&lt;/div&gt;" />
		<UserPref name="newwindow" display_name="Open Links In A New Window:" datatype="bool" default_value="true" />
		<UserPref name="expandbydefault" display_name="Expand Threads By Default:" datatype="bool" default_value="false" />
		<UserPref name="fontsize" display_name="Font Size:" default_value="100%" />
		<UserPref name="filter" datatype="list" display_name="Filter Out Items Containing:"/>
		<UserPref name="star" datatype="list" display_name="Star Items Containing:"/>
		<UserPref name="replace" datatype="list" display_name="Search/Replace rules on subject (format: /search/replace/[i])" />
		<UserPref name="refresh" display_name="Refresh Interval (minutes):" default_value="15" />
		<UserPref name="lastseen" display_name="Last Seen URL (do not change manually!):" />
		<UserPref name="lastmsg" datatype="hidden" default_value="0" />
		<Content type="html"> 
		<![CDATA[ 
<script type="text/javascript">
function _toggle(a){if(a)if(a.style.display==""||a.style.display=="block")a.style.display="none";else if(a.style.display=="none")a.style.display="block"} 

// Functions for handling miniMessages
var prefs = new _IG_Prefs();
var lastmsg = prefs.getInt("lastmsg");
var mmsg = new _IG_MiniMessage();
function addMsg(dt,msg) {
	if (dt>lastmsg) { mmsg.createDismissibleMessage(msg,function(){ prefs.set("lastmsg",dt); }); }
}

// Gadget messages
addMsg(1,"To view summaries, right-click subjects. Expand threads by clicking. Get rid of this message by clicking the X!");

function GoogleGroup() {
	var me = this;
	var p = this.prefs = new _IG_Prefs();
	this.title = p.getString('title');
	this.titlelink = p.getString('titlelink');
	this.group = p.getString('group');
	this.num = p.getInt('num');
	this.groupurl = "http://groups.google.com/group/" + this.group;
	this.url = this.groupurl + "/feed/rss_v2_0_msgs.xml?num="+this.num;
	this.filter = p.getString('filter');
	this.hideregexobj = null;
	if (this.filter) { this.hideregexobj = new RegExp(this.filter,"i"); }
	this.star = p.getString('star');
	this.starregexobj = null;
	if (this.star) { this.starregexobj = new RegExp(this.star,"i"); }
	this.interval = null;
	this.lastseen = p.getString('lastseen');
	this.firstlink = null;
	this.expandbydefault = p.getBool('expandbydefault');
	this.subjectlist = [];
	this.subjects = {};
	this.subjects_star = {};
	this.replace = p.getArray('replace');

	this.TPL_entry = p.getString('format');
	this.itemList={};
	this.highlightNewItemsTimeout=null;
	this.loaded=false;
	
	this.msg = function(txt) { _gel("msg").innerHTML = txt; _gel("status").style.display = "block"; _gel("display").style.display = "none"; };
	this.startRefresh = function() { this.interval = setInterval(function(){me.refresh()}, (60000 * p.getInt('refresh'))); };
	this.clearRefresh = function() { clearInterval(this.interval); };
	this.init = function() { this.startRefresh(); this.load(); };
	this.load = function() { _IG_FetchFeedAsJSON(this.url,function(){me.render.apply(me,arguments)},this.num,true); };
	this.refresh = function() {
		if (this.highlightNewItemsTimeout!=null) { clearTimeout(this.highlightNewItemsTimeout); }
		this.load();
	};
	
	this.addEntry = function(index, url, title, summary, date, alternate, star) {
		var tpl = this.TPL_entry;
		tpl = tpl.replace(/\%INDEX\%/g, index).replace(/\%URL\%/g, _hesc(url));
		var classname = "item";
		if (this.loaded && !this.itemList[title]) {
			classname += " new";
		}

		// Apply all the search/replace options specified in user prefs
		for (var i=0; i<this.replace.length; i++) {
			var re = this.replace[i].split("/");
			if (re && re.length==4) { 
				title = title.replace(new RegExp(re[1],re[3]),re[2]);
			}
		}
		var title = _hesc(title);

		// Need to do this next part up top so alternate logic can be correct
		var sub = title;
		while (/^\s*re\s*:\s*/i.test(sub)) {
			sub = sub.replace(/^\s*re\s*:\s*/i,"");
		}
		
		if (!this.subjects[sub]) {
			this.subjects[sub] = [];
			this.subjectlist.push(sub);
		}
		if ( (this.subjects[sub].length>1 && this.subjects[sub].length%2==1) || (this.subjects[sub].length==1 && alternate) ) {
//		if (!!(this.subjects[sub].length%2==1) || alternate) {
			classname += " alternate";
		}
		this.itemList[title] = true;

		tpl = tpl.replace(/\%BULLET\%/g,"&#8226;&nbsp;").replace(/\%A_CLASSNAME\%/g, classname).replace(/\%TITLE\%/g, title).replace(/\%STAR\%/g, (star)?"<img src=\"http://groups.google.com/groups/img/watched_y.gif\">":"").replace(/\%TARGET\%/g, (p.getBool('newwindow')?"_blank":"") );
		tpl = tpl.replace(/\%SUMMARY\%/g, _hesc(_trim(summary.replace(/\<br\>/gi,"\n").replace(/\<[^\>]*\>/gi,"").replace(/^\n*/m,""))));
		if (date) {
			var d = new Date(date*1000);
			tpl = tpl.replace(/\%N\%/g, ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][d.getDay()]);
			tpl = tpl.replace(/\%D\%/g, d.getDate()).replace(/\%M\%/g, d.getMonth()+1).replace(/\%Y\%/g, d.getFullYear()).replace(/\%h\%/g, d.getHours()).replace(/\%m\%/g, d.getMinutes()).replace(/\%s\%/g, d.getSeconds());
		}
		this.subjects[sub].push(tpl);
		if (!this.subjects_star[sub]) {
			this.subjects_star[sub] = star || false;
		}
		return tpl;
	};
	
	this.render = function(obj) {
		if (!this.loaded && obj && obj.ErrorMsg && obj.ErrorMsg != "") {this.retry(obj.ErrorMsg);return;}
		if (!this.loaded && (!obj || !obj.Entry || obj.Entry.length == 0) ) {
			var msg = "Group messages could not be loaded.<br><br>Verify that your group name is correct. The group name should be the exact text as in:<br><br>http://groups.google.com/group/NAME<br><br>For example, the iGoogle gadget group is called 'iGoogle Developer Forum' but the url is<br><br>http://groups.google.com/group/Google-Gadgets-API<br><br>so the group name is 'Google-Gadgets-API'.";
			this.retry(msg);return;
		}
		this.subjectlist = [];
		this.subjects = {};
		_gel("status").style.display = "none";
		var count = 0;
		if (obj.Entry) {
			_gel("entries").innerHTML = "";
			var hide = false;
			this.firstlink = obj.Entry[0].Link;
			for (var i = 0; i < obj.Entry.length; i++) {
				if (!hide && obj.Entry[i].Link==this.lastseen) { hide = true; }
				if (!hide) {
					if (count==0) {
						_gel("display").style.display = 'block';
					}
					var star = false;
					if (this.hideregexobj!=null && obj.Entry[i].Title && obj.Entry[i].Title.search(this.hideregexobj)>=0) { continue; }
					if (this.starregexobj!=null && obj.Entry[i].Title && obj.Entry[i].Title.search(this.starregexobj)>=0) { star=true; }
					this.addEntry(i,obj.Entry[i].Link,obj.Entry[i].Title,obj.Entry[i].Summary,obj.Entry[i].Date,!!(count++%2==1),star);
				}
			}
			var el = _gel("entries");
			var c = "";
			for (var i=0; i<this.subjectlist.length; i++) {
				var s = this.subjectlist[i];
				// If there is only one entry in a thread, show it without the thread header
				if (this.subjects[s].length==1) {
					c += this.subjects[s][0];
				}
				else {
					var star = (!!this.subjects_star[s])?"<img src=\"http://groups.google.com/groups/img/watched_y.gif\">":"";
					c += '<div class="mc item group_subject" oncontextmenu="this.onclick();return false;" onclick="_toggle(document.getElementById(\'group_thread_posts_'+i+'\'));resize();" title="Click to toggle thread posts">'+star+s+'&nbsp;&nbsp;<span class="count">['+ this.subjects[s].length +']</span></div>';
					c += '<div class="group_thread_posts" id="group_thread_posts_'+i+'" style="display:'+ (this.expandbydefault?'block':'none') +';">';
					for (var j=0; j<this.subjects[s].length; j++) {
						c += this.subjects[s][j];
					}
					c += '</div>';
				}
			}
			el.innerHTML += c;
		}
		this.loaded = true;
		if (count>0) {
			resize();
		}
		else {
			_IG_AdjustIFrameHeight(1);
		}
		setTimeout(function(){me.unhighlightNewItems();}, 10 * 1000);
	};
	this.unhighlightNewItems = function() {
		if (this.highlightNewItemsTimeout!=null) {
			clearTimeout(this.highlightNewItemsTimeout);
		}
		var entries = _gel('entries').getElementsByTagName('A');
		if (entries) {
			for (var i=0; entries && i<entries.length; i++) {
				var a = entries[i];
				if (a && typeof(a.className)=="string") {
					a.className = a.className.replace(new RegExp("\s*new"),'');
				}
			}
		}
	};
	this.retry = function(msg) {
		if (msg) { this.msg(msg); }
		this.clearRefresh();
		resize();
		setTimeout(function(){me.refresh()},15*1000);
	};
	this.clear = function() {
		p.set('lastseen',this.firstlink);
		this.lastseen = this.firstlink;
		_gel("display").style.display = "none";
		resize();
		this.clearRefresh();
		this.startRefresh();
		this.refresh();
	};
	this.post = function() { window.open(this.groupurl + "/post"); };
	this.grouphome = function() { window.open(this.groupurl); };
	this.msgs = function() { window.open(this.groupurl + "/topics"); };
	_IG_RegisterOnloadHandler(function(){me.init()});
}
function resize() {
	_IG_AdjustIFrameHeight();
}
var group = new GoogleGroup();
</script>
<style>
div.mc, div.mc * {
	whitespace:no-wrap;
	overflow:hidden;
	text-overflow:ellipsis;
	padding:0px;
	color:#333;
}
html, body {
	padding:0px;
	margin:0px;
}
body {
	font-size:__UP_fontsize__ !important;
}
.item { 
	display:block;
	text-decoration:none;
}
.alternate {
	background-color: #f6f6f6; 
}
A.item:hover, DIV.group_subject:hover { 
	background-color:yellow !important; 
}
A.new { 
	background-color:#ffffcc !important; 
}
div.mc div.summary {
	border:1px solid #999;
	border-width:0px 1px 1px 1px;
	margin:0px 0px 5px 0px;
	padding:2px;
	background-color: #FFF9DF;
}
.group_button {
	cursor:pointer;
	border:1px solid #cccccc;
	border-color:#ccc #666 #666 #ccc;
	background-color:#C6D8FF;
	padding:0px;
	font-size:10px;
	font-family:arial;
}
.group_subject {
	cursor:pointer;
	padding-left:20px !important;
	background-image:url(http://groups.google.com/groups/img/3/favicon.ico);
	background-position:left center;
	background-repeat:no-repeat;
	background-color:transparent;
}
.group_thread_posts A {
	margin-left:20px;
}
#msg {
	font-style:italic;
	text-align:center;
	font-size:120%;
}
span.count {
	color:#aaa;
}
</style>
<div id="status">
	<div id="msg">Loading...</div>
</div>
<div id="display" style="display:none;">
	<div id="control" style="text-align:center;margin-bottom:3px;">
		<span class="group_button" onclick="group.grouphome()">Group Home</span>
		<span class="group_button" onclick="group.msgs()">All Msgs</span>
		<span class="group_button" onclick="group.post()">Post</span>
		<span class="group_button" onclick="group.clear()">Mark All Read</span>
	</div>
	<div id="entries"></div>
</div>
     ]]> 
   </Content> 
</Module>
