- Fixed a bunch of bugs for existing paginations
[FlickrHacks.git] / _greasemonkey_ / flickrgroupcomments.user.js
blobd8b01235924f68c0cfa880ffdef9c302b65ccb75
1 // Flickr Group Comments
2 // v0.8
3 // 2006-05-26
4 // Copyright (c) 2006, Pierre Andrews.
5 // Released under the GPL license
6 // http://www.gnu.org/copyleft/gpl.html
7 //
8 // ==UserScript==
9 // @name        Flickr Group Comments
10 // @namespace   http://6v8.gamboni.org/Flickr-view-group-comments.html
11 // @description Display the recent comments in your groups directly in the recent change page
12 // @source         http://6v8.gamboni.org/Flickr-view-group-comments.html
13 // @identifier     http://6v8.gamboni.org/IMG/js/flickrgroupcomments.user.js
14 // @version        0.8
15 // @date           2006-05-26
16 // @creator        Pierre Andrews (mortimer.pa@free.fr)
17 // @include http://*flickr.com/recent.gne*
18 // ==/UserScript==
20 //======================================================================
21 // Configuration
23 //number of minutes before the next automatic reload.
24 //if set to false or 0, then there will never be automatic reloads
25 var AUTO_RELOAD = 10;
27 //======================================================================
29 (function () {
31         var win = (unsafeWindow || window.wrappedJSObject || window);
33         //update information
34         var SCRIPT = {
35                 name: "Flickr Group Comments",
36                 namespace: "http://6v8.gamboni.org/Flickr-view-group-comments.html",
37                 description: "Display the recent comments in your groups directly in the recent change page",
38                 source: "http://6v8.gamboni.org/Flickr-view-group-comments.html",                       // script homepage/description URL
39                 identifier: "http://6v8.gamboni.org/IMG/js/flickrgroupcomments.user.js",
40                 version: "0.8",                                                         // version
41                 date: (new Date(2006, 5, 26))           // update date
42                 .valueOf()
43         };
45         //======================================================================
46         //to do the closure and get the right this.
47         //adapted from http://persistent.info/greasemonkey/gmail.user.js
49         function getObjectMethodClosure11(object, method,args3) {
50                 return function(arg) {
51                         return object[method](arg,args3); 
52                 }
53         }
55         function getObjectMethodClosure12(object, method,args3,arg4) {
56                 return function(arg) {
57                         return object[method](arg,args3,arg4); 
58                 }
59         }
62         //======================================================================
63         
64         // constants
65         // http status constants
66         var OK = 200;
67         
68         // xmlhttprequest readystate
69         var COMPLETE = 4;
70         
71         var DEBUG = false;
72                 
73         win.FlickrGroupComments = function() {;}
75         win.FlickrGroupComments.prototype = {
76                 //1
77                 init: function() {
78                         GM_addStyle(".EachGroup ul li.read {color: #AAAAAA; list-style-type: circle; font-size: 80%;}\
79  .EachGroup ul li.read a {color: #99ccff;} ");
80                         var commentsLinks = document.evaluate("/html/body/div[@id='Main']/table[2]/tbody/tr/td[@id='Changes']/table/tbody/tr/td[2]/ul",                                                                           
81                                                                                                  document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);  // Get all group
82                         
83                         for(var i = 0; i < commentsLinks.snapshotLength; i++) {  // For each group...
84                                 var al = commentsLinks.snapshotItem(i);
86                                 this.prepareUL(al);
87                         }
89                         if(AUTO_RELOAD > 0) {
90                                 var change = document.evaluate("//td[@id='Changes']/table[1]",
91                                                                  document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
92                                                                  ).singleNodeValue;
93                                 if(change) {
94                                         setTimeout(function() { document.location.reload(); } , AUTO_RELOAD*60*1000);                                   
95                                         var reload = document.createElement('p');
96                                         reload.innerHTML = "Next automatic reload in: "+AUTO_RELOAD+" min";
97                                         reload.setAttribute("style","background-image: url(../images/dotted.gif); background-repeat: repeat-x; background-position: left top;padding-top:10px;");
98                                         change.parentNode.insertBefore(reload,change.nextSibling);
99                                         var cnt = 0;
100                                         var timeout = function() { 
101                                                 var next = AUTO_RELOAD-(cnt++);
102                                                 reload.innerHTML = "Next automatic reload in: "+
103                                                         next+
104                                                         ' min'; 
105                                                 setTimeout(timeout, 60*1000);
106                                         };
107                                         setTimeout(timeout, 250);
108                                 }
109                         }                               
110                 },
112                 //2
113                 prepareUL: function(element) {
114                         var read = GM_getValue('flickrgroupcomments.read');
115                         
116                         element.parentNode.parentNode.addEventListener('click',
117                                                                                                                    getObjectMethodClosure11(this,"markAllAsRead",element),
118                                                                                                                    true);
119                         
120                         news = element.getElementsByTagName("li");
121                         for(var i=0;i<news.length;i++) {
122                                 var li = news[i];
123                                 var as = li.getElementsByTagName('A');
124                                 if(as.length>0 && !/More\.\.\./.test(as[0].innerHTML)) {
125                                         var num = -1;
126                                         var re = new RegExp('<'+as[0].href+',([0-9]+)>');
127                                         var matches;
128                                         if(as.length > 1) {
129                                                 matches = /\(([0-9]+) repl(ies|y)\)/.exec(li.innerHTML);
130                                                 if(matches) {
131                                                         num = parseInt(matches[1])+1;
132                                                 } 
133                                         }
134                                         if(read && (matches = re.exec(read))) {
135                                                 var show = true;
136                                                 // if we have already marked this one as read, but the
137                                                 // stored number is different, then it's like if we did not read it.
138                                                 // (see comment below)
139                                                 if(num >= 0 && num != matches[1]) show = false; 
140                                                 if(show) {
141                                                         li.className = 'read';
142                                                 }
143                                         }
144                                                 
145                                         
146                                         var showA = li.appendChild(document.createElement('A'));
147                                         showA.innerHTML = "&nbsp;Show...";
148                                         showA.title="Display the message(s).";
149                                         showA.setAttribute("style","font-size:85%;color:grey;text-decoration: underline;");
150                                         li.fgcShowA = showA;
151                                         showA.addEventListener('click', 
152                                                                                    getObjectMethodClosure12(this,"getGroupId",li,element),
153                                                                                    true);
154                                         
155                                         li.addEventListener('click',
156                                                                                 getObjectMethodClosure11(this,"markAsRead",li),
157                                                                                 true);
158                                 }
159                         }
160                 },
162                 //3
163                 markAllAsRead: function(event, ul) {    
164                         if(event.target == ul || event.target.tagName == 'TD'|| event.target.tagName == 'H2') { 
165                                 var news = ul.getElementsByTagName("li");
166                                 for(var i=0;i<news.length;i++) {
167                                         this.markAsRead(null,news[i]);
168                                 }
169                         }
170                 },
171                         
172                 //3
173                 markAsRead: function(event,li) {
174                         if(event) {
175                                 if(event.target == li.fgcShowA) return;
176                         }
177                         var as = li.getElementsByTagName('A');
178                         if(as.length>0 && !/More\.\.\./.test(as[0].innerHTML)) {
179                                 li.className = 'read';
180                                 var num = 1;
181                                 if(as.length > 1) {
182                                         var matches = /\(([0-9]+) repl(ies|y)\)/.exec(li.innerHTML);
183                                         if(matches) {
184                                                 num = parseInt(matches[1])+1;
185                                         } 
186                                 }                               
187                                 var read = GM_getValue('flickrgroupcomments.read');
188                                 if(read) read += '<'+as[0].href+','+num+'>';
189                                 else read = '<'+as[0].href+','+num+'>';
190                                 GM_setValue('flickrgroupcomments.read',read);
191                         }
192                 },
193                 
194                 //3
195                 getGroupId: function(event,li,element) {                        
196                         var showA = li.fgcShowA;
197                         showA.style.display = 'none';
199                         var newDiv = li.fgceNewDiv;
200                         if(!newDiv) {
201                                 newDiv = document.createElement("DIV");
202                                 newDiv.innerHTML = '<img src="http://www.flickr.com/images/pulser2.gif" style="vertical-align:middle;margin-right:4px;border:0px #ffffff" />';
203                                 li.fgceNewDiv = newDiv;
204                         }                               
205                                 
206                         var closeA = li.fgcCloseA;
207                         if(!closeA) {
208                                 closeA = li.appendChild(document.createElement('A'));
209                                 closeA.addEventListener('click',function() {
210                                                                                         newDiv.style.display='none';
211                                                                                         showA.style.display='block';
212                                                                                         closeA.style.display='none';
213                                                                                         li.className = 'read';
214                                                                                 }, true);
215                                 closeA.innerHTML = "&nbsp;Hide";        
216                                 closeA.title="Hide the messages.";
217                                 closeA.setAttribute("style","font-size:85%;color:grey;text-decoration: underline;");
218                         }
219                         li.appendChild(newDiv);
220                         
221                         if(!element.fgceGroupID) {
222                                 matches = /(flickr.com)?\/groups\/(.+?)\//.exec(element.innerHTML);
223                                 
224                                 if(matches) {
225                                         var groupName = matches[2];
226                                         var details = {
227                                                 method    : "POST",
228                                                 onload    : getObjectMethodClosure12(this,"process_groupID",li,element),
229                                                 url       : "http://www.flickr.com/services/rest/?method=flickr.urls.lookupGroup&api_key=e8c3239ff04c102ce2d6ed885bf99005&url=" + encodeURIComponent("http://flickr.com/groups/"+groupName),
230                                         };
231                                         
232                                         GM_xmlhttpRequest( details );
233                                 }
234                         } else {
235                                 this.groupIDReceived(element.fgceGroupID,li,element);
236                         }
237                 },
239                 //4
240                 process_groupID: function(req,li,element) {
241                         if(DEBUG) GM_log(req.responseText);
242                         var rsp = req.responseText.replace(/<\?xml.*\?>/,'');
243                         var rsp = new XML(rsp);
244                         
245                         if (rsp == null) {
246                                 this.error( "Could not understand Flickr's response.", 0, req, li);
247                         } else {                        
248                                 var stat = rsp.@stat;
249                                 if (stat == null) {
250                                         this.error( "Could not find status of Flickr request", 0, req,li);
251                                 } else if (stat != 'ok') {
252                                         if (stat == 'fail') {
253                                                 var err_node = rsp.err[0];
254                                                 var code = err_node.@code;
255                                                 var err_msg = err_node.@msg;
256                                                 this.error( err_msg, code, req,li);
257                                         } else {
258                                                 this.error("Unknown error status: '" + stat + "'", 0, req,li)
259                                         }
260                                 } else {
261                                         element.fgceGroupID = rsp..@id[0];                                                              
262                                         this.groupIDReceived(element.fgceGroupID,li,element);
263                                 }
264                         }
265                 },
266                 
268                 //5
269                 groupIDReceived: function(id,li,element) {
270                         if(!element.rssFeed) {
271                                 var details = {
272                                         method    : "GET",
273                                         onload    : getObjectMethodClosure12(this,"getGroupFeed",li,element),
274                                         url       : "http://flickr.com/groups_feed.gne?id="+id+"&format=rss_200",
275                                 };
276                         
277                                 GM_xmlhttpRequest( details );
278                         } else {
279                                 this.getGroupFeed(null,li,element);
280                         }
281                 },
283                 //6
284                 getGroupFeed: function(req,li,element) {                
285                         if(DEBUG) GM_log(req.responseText);
286                         
287                         if(!element.rssFeed) {
288                                  var rsp = req.responseText.replace(/<\?xml.*\?>/,'');
289                                  rsp = new XML(rsp);
290                                  
291                                  if (rsp == null) {
292                                          this.error( "Could not parse rss.", 0, req,li);
293                                          return;
294                                  } else {                       
295                                          element.rssFeed = rsp;
296                                  }
297                         }
298                         this.getLastMessage(li,element.rssFeed);
299                 },
301                 //7
302                 getLastMessage: function(threadLi,rss) {
303                         var links = threadLi.getElementsByTagName("a");
304                         var newDiv = threadLi.fgceNewDiv;
305                         newDiv.style.display = 'block';
306                         if(links.length > 0){
307                                 var matches = /^([0-9]+) new replies$/.exec(links[0].innerHTML);
308                                 var html = '';
309                                 var href = '';
310                                 if(matches) {
311                                         var num = parseInt(matches[1]);
312                                         href = links[1].href;
313                                 } else if(links[0].innerHTML == "New reply") {
314                                         num = 1;
315                                         href = links[1].href;
316                                 } else {
317                                         var matches = /\(([0-9]+) repl(ies|y)\)/.exec(threadLi.innerHTML);
318                                         if(matches) {
319                                                 num = parseInt(matches[1])+1;
320                                         } else
321                                                 num = 1;
322                                         href = links[0].href;
323                                 } 
324                                 //mark this one as read with X messages.
325                                 //we need to keep track of the number for the case of the "New Topic ... (X replies)"
326                                 //where the href is the same but does not always point to the same number of message
327                                 var read = GM_getValue('flickrgroupcomments.read');
328                                 if(read) read += '<'+links[0].href+','+num+'>';
329                                 else read = '<'+links[0].href+','+num+'>';
330                                 GM_setValue('flickrgroupcomments.read',read);
331                                 newDiv.innerHTML = this.findMessages(rss,href,num);
332                         }
333                 },
335                 //8
336                 findMessages: function(rss,link,num) {
337                         var mess = '';
338                         var messArray = new Array();
339                         cnt = 1;
340                         //we have to introduce the www. as the rss links always contains it,
341                         // but you could have links in the web page without them.
342                         link = link.replace(/^http:\/\/(www.)?/,"http://www."); 
343                         for each(item in rss..item) {
344                                 if(item.link.indexOf(link) == 0 && cnt <= num) {
345                                         //mark all the one we see here are read too.
346                                         var read = GM_getValue('flickrgroupcomments.read');
347                                         if(read) read += '<'+item.link+',1>';
348                                         else read = '<'+item.link+',1>';
350                                         //TODO: here we could only push it if it has not been read yet.
351                                         messArray.push(item.description);
352                                         cnt++;
353                                 } else if(cnt > num) {
354                                         break;
355                                 }
356                         }
357                         if(cnt==1) {
358                                 mess="sorry, message not found";
359                         } else {
360                                 mess = "<ul style=\"list-style-type:none;margin: 0; padding:0;\">";
361                                 for(var i=messArray.length-1;i>=0;i--)
362                                         mess += "<li style=\"background-image: url(../images/dotted.gif); background-repeat: repeat-x; background-position: left bottom;padding-left: 1em;padding-bottom:1em;\">"+messArray[i]+"</li>";
363                                 mess += "</ul>";
364                         }
365                         return mess;
366                 },
368                 error: function(err_msg, code, req, li) {
369                         if(li.fgceNewDiv) li.fgceNewDiv.innerHTML = '<b style="color:red">'+err_msg+'</b>';
370                 }
371         }
372                 
373         //======================================================================
374         // launch
375         try {
376                 window.addEventListener("load", function () {
377                         try {
378                                         
379                                 // update automatically (http://userscripts.org/scripts/show/2296)
380                                 win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
381                         } catch (ex) {} 
382                         
383                         var flickrgp = new win.FlickrGroupComments();
384                         flickrgp.init();        
385                 }, false);
386         } catch (ex) {}
388 })();