Initial commit of website to git. Has the "old" ob3 website as the main site, and...
[dana/openbox-web.git] / h / xmlnews.js
1 // list of valid feeds
2 var feeds = new Array();
3 feeds['news'] = './rss/news/.xml';
4 feeds['commits'] = './rss/local/.xml.commits';
5 feeds['planet'] = './rss/planet/.xml';
6 feeds['miniplanet'] = './rss/mini/.xml';
7
8 function showError(out, m) {
9   out.innerHTML='<b>Error</b> showing XML news feed!<br />'+m;
10 }
11
12 function fetch(me, feed) {
13   // the file to load
14   me.url = feeds[feed];
15
16   //me.out.innerHTML='Initializing ticker...';
17
18   // read the xml document
19   me.ajax=createAjaxObj();
20   if (me.ajax) {
21     //me.ajax.onreadystatechange=function(){response(me);};
22     me.ajax.open('GET', me.url, false);  // synchronous
23     me.ajax.send(null);
24     response(me);
25   }
26   else {
27     showError(me.out, 'Unable to create AJAX object');
28   }
29 }
30
31 function twitter_nametolink(t, url) {
32   return t.replace(/^([^:]+)/, function(a) {
33     return '<a href="'+url+'">'+a+'</a>';
34   });
35 }
36
37 function striptags(t) {
38   /* remove tags (script tags have already been removed) */
39   return t.replace(/<\/?[a-zA-Z]+( [^>]*)?>/g, '');
40 }
41
42 function ident_linkize(t) {
43   t = t.replace(/@([a-zA-Z_0-9\/]+)/g, function(a, b) {
44     return '@<a href="http://identi.ca/'+b+'">'+b+'</a>';
45   });
46   t = t.replace(/#([a-zA-Z_0-9\/]+)/g, function(a, b) {
47     return '#<a href="http://identi.ca/tag/'+b+'">'+b+'</a>';
48   });
49   return t;
50 }
51
52 function twitter_linkize(t) {
53   t = t.replace(/@([a-zA-Z_0-9\/]+)/g, function(a, b) {
54     return '@<a href="http://twitter.com/'+b+'">'+b+'</a>';
55   });
56   t = t.replace(/#([a-zA-Z_0-9\/]+)/g, function(a, b) {
57     return '#<a href="http://twitter.com/search?q=%23'+b+'">'+b+'</a>';
58   });
59   return t;
60 }
61
62 function linkize(t) {
63   // turn urls into links
64   // - don't let them end with .,:;)]}!
65   // - don't replace links inside a tag attribute
66
67   return t.replace(/(<[a-zA-Z]+( +[a-zA-Z]+=("(\\"|[^"])*"|'(\\'|[^'])*'))* +[a-zA-Z]+=\"(\\"|[^"])*)?([a-z]+:\/\/[A-Z0-9a-z%_#?&$@+=!\*\(\)\[\]{};:\'\"\\\|,.\/-]+[A-Z0-9a-z%_#?&$@+=\*\(\[{\'\"\\\|\/-])/g,
68                    function(all) {
69                      if (all.charAt(0) == '<')
70                        return all;
71                      else
72                        return '<a href="'+all+'">'+all+'</a>';
73                    });
74 }
75
76 function strip_whitespace(t) {
77   return t.replace(/[\n\r\t ]+/g, ' ');
78 }
79
80 function ellipsize(t, len) {
81   t = strip_whitespace(t); // size matters
82   var r = '';
83   for (var i = 0; i < len; i++) {
84     var m = t.match(/^(&#[0-9]+;|&(gt|lt|amp|quot|apos);|.)/);
85     if (!m) break;
86     r += m[0];
87     t = t.slice(m[0].length);
88   }
89   return r + (t.length == 0 ? '' : '...');
90 }
91
92 function response(me) {
93   // are we ready yet ?
94   if (me.ajax.readyState!=4)
95     return;
96   if (me.ajax.status!=200) {
97     showError(me.out, 'Status: '+me.ajax.status+'<br>'+me.url);
98     return;
99   }
100
101   // get the xml document
102   me.xml=me.ajax.responseXML;
103   if (me.xml==null) {
104     showError(me.out, 'No XML response: '+me.ajax.responseText);
105     return;
106   }
107
108   // get the feed
109   var feed=me.xml.getElementsByTagName('feed')[0];
110
111   var items=feed.getElementsByTagName('item');
112   if (items.length==0) {
113     this.showError(me.out, 'No items found.');
114     return;
115   }
116
117   // the output for the div
118   var c='<ul>';
119
120   // add all the items in the feed
121   for (var i=0; i<items.length && i<me.count; i++){
122     var last=(i+1>=items.length||i+1>=me.count);
123     var item=items[i];
124     var n,date,time,title,link,desc,id,name,www,image;
125
126     if (me.options.showname) {
127       n = item.getElementsByTagName("name")[0].firstChild;
128       name = n ? n.nodeValue : '';
129       n = item.getElementsByTagName("feedurl")[0].firstChild;
130       www = n.nodeValue;
131     }
132
133     n = item.getElementsByTagName("image")[0].firstChild;
134     if (n)
135       image = striptags(n.nodeValue);
136     else
137       image = null;
138
139     if (me.options.showdate) {
140       n = item.getElementsByTagName("date")[0].firstChild;
141       var t=new Date();
142       var offset=t.getTimezoneOffset();
143       t.setTime((parseInt(n.nodeValue)-offset*60)*1000);
144       date=t.format('mediumDate');
145       time=t.format('shortTime');
146     }
147
148     n=item.getElementsByTagName("title")[0].firstChild;
149     title=n.nodeValue;
150     n=item.getElementsByTagName("id")[0].firstChild;
151     id=n.nodeValue;
152     if (me.options.titlelinktoid)
153       link = me.options.titlelinktoid+'#'+id;
154     else if (me.options.twitter) {
155       n=item.getElementsByTagName("feedurl")[0].firstChild;
156       link=n.nodeValue;
157     }
158     else {
159       n=item.getElementsByTagName("link")[0].firstChild;
160       link=n.nodeValue;
161     }
162
163     if (me.options.showdescription && !me.options.twitter) {
164       var j, k;
165       k = item.getElementsByTagName("text")[0].childNodes.length;
166       desc = '';
167       // firefox truncates the firstChild at 4096 bytes, so grab from
168       // all children and join it together
169       for (j = 0; j < k; j++) {
170         n = item.getElementsByTagName("text")[0].childNodes[j];
171         desc += n.nodeValue;
172       }
173     }
174
175     // massage the output
176     if (me.options.twitter) {
177       /* twitter mode */
178       title = linkize(title);
179
180       n = item.getElementsByTagName("feedurl")[0].firstChild;
181       if (n.nodeValue.match(/twitter.com/))
182         title = twitter_linkize(title);
183       if (n.nodeValue.match(/identi.ca/))
184         title = ident_linkize(title);
185
186       title = twitter_nametolink(title, link);
187     }
188     else if (me.options.fulldescription) {
189       /* full description */
190       if (me.options.links)
191         desc = linkize(desc);
192     }
193     else if (me.options.showdescription) {
194       /* short description */
195       desc = striptags(desc);
196       desc = ellipsize(desc, 140);
197     }
198
199     c+='<li>';
200     if (me.options.showimage && image)
201       c+='<div class="image"><img src="'+image+'" /></div>';
202     if (me.options.showname && !me.options.shownamebottom) {
203       c+='<div class="name">';
204       if (me.options.shownamelink && www)
205         c+='<a href="'+www+'">';
206       c+=name;
207       if (www)
208         c+='</a>';
209       c+=':</div>';
210     }
211     if (me.options.idname)
212       c+='<a name="'+id+'"></a>';
213     c+='<div class="title">';
214     if (me.options.twitter)
215       c+=title;
216     else
217       c+='<a href="'+link+'">'+title+'</a>';
218     c+='</div>';
219     if (me.options.showdescription)
220       c+='<div class="description">'+desc+'</div>';
221     c+='<div class="footer">';
222     if (me.options.showname && options.shownamebottom) {
223       c+='<div class="name">';
224       if (me.options.shownamelink && www)
225         c+='<a href="'+www+'">';
226       c+=name;
227       if (www)
228         c+='</a>';
229       c+='</div>';
230     }
231     if (me.options.showdate){
232       c+='<div class="datetime">';
233       c+='<div class="date">'+date+'</div>';
234       c+='<div class="time">'+time+'</div>';
235       c+='</div>';
236     }
237     c+='</div>';
238     if (!last && me.options.fulldescription)
239       c+='<hr />'; // separate things in full description mode
240     c+='</li>';
241   }
242   c+='</ul>';
243
244   me.out.innerHTML=c;
245 }
246
247 function xmlNews(feed, to, count, options)
248 {
249   var me = this;
250   me.out=document.getElementById(to); // destination container
251   me.count = count;
252
253   me.options = function(){};
254   me.options.twitter=options.match(/twitter/);
255   me.options.links=options.match(/links/);
256   me.options.showdescription=options.match(/(show|full)description/);
257   me.options.fulldescription=options.match(/fulldescription/);
258   me.options.showimage=options.match(/showimage/);
259   me.options.showdate=options.match(/showdate/);
260   me.options.showname=options.match(/showname/);
261   me.options.shownamebottom=options.match(/shownamebottom/);
262   me.options.shownamelink=options.match(/shownamelink/);
263   me.options.titlelinktoid=options.match(/titlelinktoid=(.[^, ]*)/);
264   if (me.options.titlelinktoid) me.options.titlelinktoid=me.options.titlelinktoid[1];
265   me.options.idname=options.match(/idname/);
266
267   fetch(me, feed);
268 }