Up version
[ff_comments.user.js] / ff_comments.user.js
1 // ==UserScript==
2 // @name        FriendFeed comments
3 // @description Add FriendFeed 'likes' and comments to any page
4 // @namespace   http://oblomov.myopenid.com
5 // @include     http://*
6 // @exclude     http://friendfeed.com/*
7 // @exclude     http://*.friendfeed.com/*
8 // @exclude     http://friendfeed-api.com/*
9 // @author      Giuseppe "Oblomov" Bilotta
10 // @version     20091221
11 // ==/UserScript==
12
13 if (typeof(unsafeWindow) == 'undefined') unsafeWindow = window;
14
15 (function() {
16
17  var ff_preload = new Image();
18  ff_preload.src = 'http://friendfeed.com/favicon.ico';
19  ff_preload.src = 'http://friendfeed.com/static/images/logo-small.png';
20
21
22  unsafeWindow.ujs_now = new Date();
23
24 unsafeWindow.ujs_ff_load = function(url) {
25         var e = unsafeWindow.document.createElement('script');
26         e.type = 'text/javascript';
27         e.src = url;
28         unsafeWindow.document.getElementsByTagName('head')[0].appendChild(e);
29 };
30
31 unsafeWindow.ujs_ff_load_entries = function(str) {
32         var weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
33         var month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
34
35         var last_body = '';
36         if (str.entries && str.entries.length > 0) {
37                 var doc = unsafeWindow.document;
38
39                 var pdiv = doc.getElementById('ujs_friendfeed');
40                 var div;
41                 if (pdiv) {
42                         div = pdiv.lastChild;
43                 } else {
44                         pdiv = doc.createElement('div');
45                         pdiv.setAttribute('id', 'ujs_friendfeed');
46                         pdiv.setAttribute('title', 'FriendFeed comments on this page');
47                         pdiv.style.position = 'absolute';
48                         pdiv.style.top = 0;
49                         pdiv.style.left = 0;
50                         pdiv.style.zIndex = 100000;
51                         pdiv.style.maxWidth = '30%';
52                         pdiv.style.height='auto';
53                         pdiv.style.border='3px outset lightblue';
54                         pdiv.style.margin = 0;
55                         pdiv.style.padding = 0;
56                         pdiv.style.textAlign = 'center';
57                         pdiv.style.fontSize = '0px';
58                         pdiv.style.lineHeight = 1;
59                         //  pdiv.style.opacity = 0.7;
60                         pdiv.style.backgroundColor = 'white';
61
62                         doc.body.appendChild(pdiv);
63
64                         var logo = doc.createElement('img');
65                         logo.src = 'http://friendfeed.com/favicon.ico';
66                         logo.setAttribute('alt', 'FriendFeed logo');
67                         logo.setAttribute('title', 'FriendFeed logo');
68                         logo.style.margin='0 auto 0 auto';
69                         logo.style.padding=0;
70                         pdiv.appendChild(logo);
71
72                         div = doc.createElement('div');
73                         div.style.fontSize = 'small';
74                         div.style.display = 'none';
75                         pdiv.appendChild(div);
76
77                         function displayToggle() {
78                                 // don't toggle if we were dragging
79                                 if (pdiv.dragged) {
80                                         pdiv.dragged = false;
81                                         return;
82                                 }
83                                 var d = pdiv.lastChild;
84                                 if (d.style.display == 'none') {
85                                         d.style.display = 'block';
86                                         logo.src = 'http://friendfeed.com/static/images/logo-small.png';
87                                         logo.style.padding = '5px';
88                                 } else {
89                                         d.style.display = 'none';
90                                         logo.src = 'http://friendfeed.com/favicon.ico';
91                                         logo.style.padding = 0;
92                                 }
93                         };
94
95                         logo.addEventListener('click', displayToggle, false);
96
97                         var dragging=false;
98                         pdiv.dragged=false;
99                         function drag(ev) {
100                                 if (dragging) {
101                                         var dx = ev.pageX - dragging.x;
102                                         var dy = ev.pageY - dragging.y;
103                                         pdiv.style.left = (parseInt(pdiv.style.left) + dx) + 'px';
104                                         pdiv.style.top = (parseInt(pdiv.style.top) + dy) + 'px';
105                                         dragging.x = ev.pageX;
106                                         dragging.y = ev.pageY;
107                                         ev.preventDefault();
108                                         ev.stopPropagation();
109
110                                         pdiv.dragged = true;
111                                 }
112                         }
113                         logo.addEventListener('mousedown',
114                                         function (ev) {
115                                                 dragging=new Object();
116                                                 dragging.x = ev.pageX;
117                                                 dragging.y = ev.pageY;
118                                                 ev.preventDefault();
119                                                 ev.stopPropagation();
120                                         }, false);
121                         logo.addEventListener('mouseup',
122                                         function (ev) {
123                                                 dragging=false;
124                                                 ev.preventDefault();
125                                                 ev.stopPropagation();
126                                         }, false);
127                         // handle on the whole document because otherwise fast
128                         // movements will make the mouse get out of the logo, thus
129                         // 'dropping' the drag
130                         doc.addEventListener('mousemove', drag, false);
131                 }
132
133
134                 var ecount = str.entries.length;
135                 for (var i=0; i < ecount; ++i) {
136                         var entry = str.entries[i];
137
138                         var p_entry_id = 'ujs_ff_entry/' + entry.id;
139
140                         // skip this entry if we already added it from a different source
141                         if (doc.getElementById(p_entry_id))
142                                 continue;
143
144                         var date2link = function(d, l) {
145                                 var cal = new Date();
146                                 var str
147
148                                 cal.setUTCFullYear(parseInt(d.substring(0,4)));
149                                 cal.setUTCMonth(parseInt(d.substring(5,7)) - 1);
150                                 cal.setUTCDate(parseInt(d.substring(8,10)));
151                                 cal.setUTCHours(parseInt(d.substring(11,13)));
152                                 cal.setUTCMinutes(parseInt(d.substring(14,16)));
153                                 cal.setUTCSeconds(parseInt(d.substring(17,19)));
154
155                                 var delta = (ujs_now - cal)/1000;
156
157                                 if (delta < 48*3600) {
158                                         if (cal.getDate() == ujs_now.getDate()) {
159                                                 str = 'today';
160                                         } else {
161                                                 str = 'yesterday';
162                                         }
163                                 } else if (cal.getYear() == ujs_now.getYear()) {
164                                         str = 'on ' + weekday[cal.getDay()] + ', ' + month[cal.getMonth()] + ' ' + cal.getDate(); 
165                                 } else {
166                                         str = 'on ' + [cal.getYear(), cal.getMonth() + 1, cal.getDate()].join('-');
167                                 }
168
169                                 str += ' at ' + [cal.getHours(), cal.getMinutes()].join(':');
170
171                                 if (l)
172                                         return '<a href="' + l + '">' + str + '</a>';
173                                 else
174                                         return str;
175                         }
176
177                         var from2link = function(from) {
178                                 return '<a href="http://friendfeed.com/' + from.id + '">' + from.name + '</a>';
179                         }
180
181                         var from2linkimg = function(from) {
182                                 return '<a style="margin: 0 1ex .5ex 0;float:left;" href="http://friendfeed.com/' + from.id + '"><img src="http://friendfeed-api.com/v2/picture/' + from.id + '?size=small" /></a>';
183                         }
184
185
186                         var fed = '';
187                         var ediv;
188                         if (entry.body != last_body) {
189                                 last_body = entry.body;
190                                 fed += '<p style="margin:0;clear:both">' + entry.body;
191
192                                 ediv = doc.createElement('div');
193                                 ediv.style.margin=0;
194                                 ediv.style.padding='.5ex';
195                                 ediv.style.borderTop='.25ex dashed lightblue';
196                                 ediv.style.textAlign = 'justify';
197                                 ediv.style.display = 'block';
198                                 div.appendChild(ediv);
199                         } else {
200                                 ediv = div.lastChild;
201                                 fed = ediv.innerHTML;
202                         }
203                         fed += '<p id="' + p_entry_id + '" style="margin:.5ex 1ex .5ex 0;clear:both">' + from2linkimg(entry.from) + 'By ' + from2link(entry.from) + '<br/>' + date2link(entry.date, entry.url);
204                         fed += '<div style="margin:0;margin-left:2.2em"></div>';
205                         ediv.innerHTML = fed;
206                         ediv = ediv.lastChild;
207
208                         var likes = entry.likes || [];
209                         var jcount = likes.length;
210                         if (jcount > 0) {
211                                 var liked = '<p style="margin:0 2ex;text-indent:-2ex">Liked by ';
212                                 for (var j=0; j < jcount; ++j) {
213                                         var like = likes[j];
214                                         if (like.from)
215                                                 liked += (j > 0 ? ', ' : '') + from2link(like.from);
216                                         else
217                                                 liked += ' and ' + like.body;
218                                 }
219
220                                 var ldiv = doc.createElement('div');
221                                 ldiv.innerHTML = liked;
222                                 ediv.appendChild(ldiv);
223                         }
224
225                         var comments = entry.comments || [];
226                         jcount = comments.length;
227                         if (jcount > 0) {
228                                 for (var j=0 ; j < jcount; ++j) {
229                                         var comment = comments[j];
230                                         var cdiv = doc.createElement('div');
231                                         cdiv.style.borderTop = '.1ex dotted blue';
232                                         cdiv.style.padding = '1ex .5ex';
233                                         ediv.appendChild(cdiv);
234
235                                         if (comment.from) {
236                                                 cdiv.innerHTML = from2linkimg(comment.from) +
237                                                         '<p style="margin:0;font-size:smaller;line-height:150%">' + date2link(comment.date) + ' by ' + from2link(comment.from) +
238                                                         '</span><p style="margin:0">' + comment.body;
239                                         } else {
240                                                 cdiv.innerHTML += comment.body;
241                                         }
242                                 }
243
244                         }
245                 }
246         }
247 };
248
249 // escape() does not escape +, but we want it escaped too
250 var encoded_loc = escape(unsafeWindow.location.toString()).replace('+','%2b');
251 var ff_url = 'http://friendfeed-api.com/v2/url?url=' + encoded_loc + '&callback=ujs_ff_load_entries&cache=' + Math.floor(Math.random()*1024*1024);
252
253 unsafeWindow.ujs_ff_load(ff_url);
254
255 ff_url = 'http://friendfeed-api.com/v2/search?q=' + encoded_loc + '&callback=ujs_ff_load_entries&cache=' + Math.floor(Math.random()*1024*1024);
256
257 unsafeWindow.ujs_ff_load(ff_url);
258
259 })();
260