1 // Flickr Group Page Enhancer
4 // Copyright (c) 2006, Pierre Andrews.
5 // Released under the GPL license
6 // http://www.gnu.org/copyleft/gpl.html
9 // @name Flickr Group Page Enhancer
10 // @namespace http://6v8.gamboni.org/Flickr-Groug-Page-Enhancer.html
11 // @description Add more information on the groups
12 // @source http://6v8.gamboni.org/Flickr-Groug-Page-Enhancer.html
13 // @identifier http://6v8.gamboni.org/IMG/js/flickrgrouppageenhancer.user.js
16 // @creator Pierre Andrews (mortimer.pa@free.fr)
17 // @include http://*flickr.com/groups
18 // @include http://*flickr.com/groups/
19 // @include http://*flickr.com/groups/#*
20 // @include http://*flickr.com/people/*
27 var win = (unsafeWindow || window.wrappedJSObject || window);
31 name: "Flickr Group Page Enhancer",
32 namespace: "http://6v8.gamboni.org/Flickr-Groug-Page-Enhancer.html",
33 description: "Add more information on the groups",
34 source: "http://6v8.gamboni.org/Flickr-Groug-Page-Enhancer.html", // script homepage/description URL
35 identifier: "http://6v8.gamboni.org/IMG/js/flickrgrouppageenhancer.user.js",
36 version: "0.6", // version
37 date: (new Date(2006, 6, 6)) // update date
41 //======================================================================
45 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
46 * Digest Algorithm, as defined in RFC 1321.
47 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
48 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
49 * Distributed under the BSD License
50 * See http://pajhome.org.uk/crypt/md5 for more info.
54 * Configurable variables. You may need to tweak these to be compatible with
55 * the server-side, but the defaults work in most cases.
57 var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
58 var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
59 var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
62 * These are the functions you'll usually want to call
63 * They take string arguments and return either hex or base-64 encoded strings
65 function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
66 function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
67 function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
68 function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
69 function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
70 function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
73 * Perform a simple self-test to see if the VM is working
75 function md5_vm_test()
77 return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
81 * Calculate the MD5 of an array of little-endian words, and a bit length
83 function core_md5(x, len)
86 x[len >> 5] |= 0x80 << ((len) % 32);
87 x[(((len + 64) >>> 9) << 4) + 14] = len;
94 for(var i = 0; i < x.length; i += 16)
101 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
102 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
103 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
104 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
105 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
106 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
107 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
108 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
109 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
110 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
111 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
112 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
113 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
114 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
115 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
116 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
118 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
119 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
120 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
121 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
122 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
123 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
124 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
125 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
126 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
127 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
128 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
129 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
130 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
131 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
132 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
133 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
135 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
136 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
137 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
138 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
139 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
140 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
141 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
142 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
143 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
144 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
145 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
146 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
147 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
148 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
149 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
150 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
152 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
153 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
154 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
155 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
156 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
157 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
158 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
159 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
160 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
161 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
162 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
163 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
164 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
165 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
166 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
167 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
169 a = safe_add(a, olda);
170 b = safe_add(b, oldb);
171 c = safe_add(c, oldc);
172 d = safe_add(d, oldd);
174 return Array(a, b, c, d);
179 * These functions implement the four basic operations the algorithm uses.
181 function md5_cmn(q, a, b, x, s, t)
183 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
185 function md5_ff(a, b, c, d, x, s, t)
187 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
189 function md5_gg(a, b, c, d, x, s, t)
191 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
193 function md5_hh(a, b, c, d, x, s, t)
195 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
197 function md5_ii(a, b, c, d, x, s, t)
199 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
203 * Calculate the HMAC-MD5, of a key and some data
205 function core_hmac_md5(key, data)
207 var bkey = str2binl(key);
208 if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
210 var ipad = Array(16), opad = Array(16);
211 for(var i = 0; i < 16; i++)
213 ipad[i] = bkey[i] ^ 0x36363636;
214 opad[i] = bkey[i] ^ 0x5C5C5C5C;
217 var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
218 return core_md5(opad.concat(hash), 512 + 128);
222 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
223 * to work around bugs in some JS interpreters.
225 function safe_add(x, y)
227 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
228 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
229 return (msw << 16) | (lsw & 0xFFFF);
233 * Bitwise rotate a 32-bit number to the left.
235 function bit_rol(num, cnt)
237 return (num << cnt) | (num >>> (32 - cnt));
241 * Convert a string to an array of little-endian words
242 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
244 function str2binl(str)
247 var mask = (1 << chrsz) - 1;
248 for(var i = 0; i < str.length * chrsz; i += chrsz)
249 bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
254 * Convert an array of little-endian words to a string
256 function binl2str(bin)
259 var mask = (1 << chrsz) - 1;
260 for(var i = 0; i < bin.length * 32; i += chrsz)
261 str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
266 * Convert an array of little-endian words to a hex string.
268 function binl2hex(binarray)
270 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
272 for(var i = 0; i < binarray.length * 4; i++)
274 str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
275 hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
281 * Convert an array of little-endian words to a base-64 string
283 function binl2b64(binarray)
285 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
287 for(var i = 0; i < binarray.length * 4; i += 3)
289 var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
290 | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
291 | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
292 for(var j = 0; j < 4; j++)
294 if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
295 else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
303 //======================================================================
306 // http status constants
309 // xmlhttprequest readystate
314 //======================================================================
316 var procException = function(msg, code, req) {
323 //======================================================================
324 //to do the closure and get the right this.
325 //adapted from http://persistent.info/greasemonkey/gmail.user.js
327 function getObjectMethodClosure(object, method) {
329 return object[method]();
333 function getObjectMethodClosure0(object, method,args) {
335 return object[method](args);
339 function getObjectMethodClosure1(object, method) {
340 return function(arg) {
341 return object[method](arg);
346 function getObjectMethodClosure11(object, method,args3) {
347 return function(arg) {
348 return object[method](arg,args3);
352 function getObjectMethodClosure2(object, method) {
353 return function(arg,arg2) {
354 return object[method](arg,arg2);
357 function getObjectMethodClosure21(object, method,args3) {
358 return function(arg,arg2) {
359 return object[method](arg,arg2,args3);
365 //======================================================================
367 //this code blatantly lifted from the Flickr Super Batch scripts
368 //http://webdev.yuan.cc/
369 var status_msg_container = document.createElement('div');
370 status_msg_container.style.left = '50%';
371 status_msg_container.style.width = '400px';
372 //status_msg_container.style.height = '400px';
373 status_msg_container.style.zIndex = 60000;
374 //status_msg_container.style.overflow = 'visible';
375 status_msg_container.style.position = 'absolute';
376 status_msg_container.style.display = 'none';
377 //status_msg_container.style.textAlign = 'center';
378 status_msg_container.innerHTML = '<div id="status_msg_fgpe" style="position:relative;left: -50%;top:100px;background:#d5eaff;padding:10px;font:bold 12px Arial, Helvetica, sans-serif; color:#000000;border:solid 1px #ccddee;"></div>';
380 var ip = document.evaluate( '//div[@class="TopBar"]',
381 document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
383 ip.appendChild(status_msg_container);
386 var status_msg = document.getElementById('status_msg_fgpe');
387 status_msg.submitfunc = function() {};
388 status_msg.on = false;
389 status_msg.show = function(msg) {
391 this.innerHTML = '<img src="http://www.flickr.com/images/pulser2.gif" style="vertical-align:middle;margin-right:4px;border:0px #ffffff" />';
392 this.innerHTML += msg;
393 status_msg_container.style.display = 'block';
395 status_msg.msgbox = function(msg) {
397 this.innerHTML = msg;
398 this.innerHTML += "<div align=center>[<a id='closeBox'>close</a>]</div>";
399 a = document.getElementById('closeBox');
400 a.addEventListener('click',this.clicky,true);
401 status_msg_container.style.display = 'block';
403 status_msg.msgbox2 = function(msg,button,callback) {
405 this.innerHTML = msg;
406 this.innerHTML += "<div align=center>[<a id='closeBox'>"+button+"</a>]</div>";
407 a = document.getElementById('closeBox');
409 a.addEventListener('click',function(event) {self.clicky2(event,callback)},true);
410 status_msg_container.style.display = 'block';
412 status_msg.hide = function() {
413 status_msg.on = false;
414 status_msg_container.style.display = 'none';
415 status_msg_container.style.textAlign = 'left';
417 status_msg.prompt = function(msg, fn) {
418 status_msg.submitfunc = fn;
420 this.innerHTML = msg;
421 var form = document.createElement('form');
422 form.addEventListener('submit',this.entered,true);
423 var input = document.createElement('input');
426 form.appendChild(input);
427 input = document.createElement('input');
428 input.type = 'submit';
430 form.appendChild(input);
431 this.appendChild(form);
432 status_msg_container.style.display = 'block';
435 status_msg.entered = function(event) {
436 var input = document.getElementById('woowoo');
437 status_msg.submitfunc(input.value);
438 event.preventDefault();
439 event.returnValue = false;
443 status_msg.clicky = function(event) {
445 event.preventDefault();
446 event.returnValue = false;
450 status_msg.clicky2 = function(event,callback) {
452 event.preventDefault();
453 event.returnValue = false;
460 //======================================================================
461 //Simple calls to flickr REST API, from the batch enhancer script
462 // needs the md5 and status_msg code above
464 win.FlickrAPI = function(){;}
466 win.FlickrAPI.prototype = { // flickr api
468 init: function(api_key,shared_secret) {
469 this.api_key = api_key;
470 this.shared_secret = shared_secret;
471 this.auth_token = GM_getValue('auth_'+this.api_key);
473 if (this.shared_secret && !this.auth_token) {
479 askForAuth: function() {
480 this.flickr_api_call("flickr.auth.getFrob",
481 {api_sig: this.getMethodSig("flickr.auth.getFrob", {api_key: this.api_key})},
482 getObjectMethodClosure2(this,'frob_loaded'),
483 getObjectMethodClosure1(this,'frob_failed'));
486 frob_loaded: function(req, rsp) {
488 this.frob = rsp..frob[0];
489 if(DEBUG) GM_log("received Frob "+this.frob);
490 var api_sig = this.getMethodSig(false, {api_key: this.api_key,frob:this.frob,perms:"read"});
491 var url= "http://flickr.com/services/auth/?api_key="+this.api_key+"&perms=read&frob="+this.frob+"&api_sig="+api_sig;
492 //Here, we need the status_msg code
493 status_msg.msgbox2("This script needs to be authorized. <br>" +
494 "<b style=\"font-variant:small-caps;\">Click [<a onclick='window.open(\""+url+"\"); return false'>Step1</a>]</b>, " +
495 "follow the instructions in the popup window,<br> " +
496 "then return here click Step2.<br> " +
497 "Popup blockers may cause this not to work.<br>You'll only have to do this once.","Step2",getObjectMethodClosure1(this,'getToken'));
500 frob_failed: function(e) {
501 status_msg.msgbox('Couldn\'t authorize, for whatever reason.');
504 token_loaded: function(req,rsp) {
506 var token = rsp..token[0];
507 this.nsid = rsp..user.@nsid[0];
509 if(DEBUG) GM_log("authenticated with user "+this.nsid+": "+token);
512 GM_setValue('auth_'+this.api_key,""+token);
515 token_failed:function(e) {
516 status_msg.msgbox('Couldn\'t authorize, for whatever reason.');
523 status_msg.show('authorizing...');
524 var api_sig = this.getMethodSig("flickr.auth.getToken", {api_key: this.api_key,frob:this.frob});
525 this.flickr_api_call("flickr.auth.getToken",
526 {frob: this.frob,api_sig: api_sig},
527 getObjectMethodClosure2(this,'token_loaded'),
528 getObjectMethodClosure1(this,'token_failed'));
531 do_req: function ( method, proc_request, url, referer, data ) {
532 var headers = new Object();
535 onload : function(d) { proc_request(d) },
541 headers['Referer'] = referer;
544 headers['Content-Type'] = 'application/x-www-form-urlencoded';
545 details['data'] = data;
548 GM_xmlhttpRequest( details );
553 // a proc just spins around waiting for the thing to succeed or fail
554 // then calls a callback, if we got 200 OK message.
555 make_proc: function (op_name, ok_cb, fail_cb) {
557 return function(req) {
561 document.body.style.cursor = 'progress';
563 if (req.readyState != COMPLETE) {
567 // if (alert_response) { alert(req.responseText); }
569 if( req.status != OK ) {
570 throw new procException( op_name + " request status was '" + req.status + "'", 0, req )
578 document.body.style.cursor = 'default';
581 if (e instanceof procException) {
582 if( fail_cb != null )
587 GM_log(e.req.responseText);
597 document.body.style.cursor = 'default';
602 // this is wraps the spinning proc like above,
603 // except it parses the flickr api response a little before deciding all is well,
604 // and passing control to the all-is-well callback
605 make_flickr_api_proc: function(op_name, ok_cb, fail_cb) {
607 function parse_and_ok_cb(req) {
608 if(DEBUG) GM_log(req.responseText);
609 var rsp = req.responseText.replace(/<\?xml.*\?>/,'');
610 var rsp = new XML(rsp);
611 // var rsp = req.responseXML.getElementsByTagName('rsp').item(0);
614 throw new procException( "Could not understand Flickr's response.", 0, req );
617 var stat = rsp.@stat;
619 throw new procException( "Could not find status of Flickr request", 0, req);
623 if (stat == 'fail') {
624 var err_node = rsp.err[0];
625 var code = err_node.@code;
626 var err_msg = err_node.@msg;
627 throw new procException( err_msg, code, req );
629 throw new procException("Unknown error status: '" + stat + "'", 0, req)
636 return this.make_proc(op_name, parse_and_ok_cb, fail_cb);
639 getMethodSig: function(method, args)
641 var data = new Array();
642 var names = new Array();
643 var sig = this.shared_secret;
646 data['method'] = method;
647 names.push('method');
649 for (var key in args) {
650 data[key] = args[key];
655 sig += names[i] + data[names[i]];
661 // construct a flickr api request, with method and args,
662 // if that worked, call callback with request object.
663 flickr_api_call: function( method, args, ok_cb, fail_cb,with_auth) {
665 var http_method = args['http_method'];
666 http_method = ( http_method ? http_method : 'GET' );
667 delete args['http_method'];
669 args['api_key'] = this.api_key;
671 if (this.shared_secret && with_auth && this.auth_token) {
672 args['auth_token'] = this.auth_token;
673 args['api_sig'] = this.getMethodSig(method, args);
674 } else if(DEBUG) GM_log('not signing: ' + method);
677 var url = 'http://www.flickr.com/services/rest/?method=' + encodeURIComponent(method);
679 for (var key in args) {
680 url += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
682 if(DEBUG) GM_log(url);
684 var proc = this.make_flickr_api_proc( method, ok_cb, fail_cb )
686 this.do_req(http_method, proc, url, null, null)
691 //======================================================================
693 var MAX_DAY_COUNT = 5;
694 var NUMBER_OF_LAST_PHOTOS = 8;
696 win.FlickrGroupPage = function() {;}
699 win.FlickrGroupPage.prototype = {
700 init: function(key,secret) {
701 this.api = new win.FlickrAPI();
702 this.api.init(key,secret);
704 this.user_id = unsafeWindow.global_nsid;
705 var auctionLinks = document.evaluate(
706 "/html/body/div[@id='Main']/table[2]/tbody/tr/td[1]/ul/li|/html/body/div[@id='Main']/div/table[@id='ProfileInfo']/tbody/tr/td[@id='Left']/table[1]/tbody/tr/td/ul/li",
708 document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); // Get all group
710 for(var i = 0; i < auctionLinks.snapshotLength; i++) { // For each group...
712 var al = auctionLinks.snapshotItem(i);
713 var showA = al.appendChild(document.createElement('A'));
714 showA.innerHTML = "More...";
715 showA.title="Display more information about this group.";
716 showA.href="#"+"fgpe_groupLI_"+i;
717 showA.setAttribute("style","font-size:85%;color:grey;text-decoration: underline;");
718 al.fgpeShowA = showA;
719 al.id="fgpe_groupLI_"+i;
720 showA.addEventListener('click', getObjectMethodClosure21(this,'fetchGroupInfo',al), true);
723 fetchGroupInfo: function(a,b,groupLI) {
725 var showA = groupLI.fgpeShowA;
726 showA.style.display = 'none';
728 var closeA = groupLI.fgpeCloseA;
730 closeA = groupLI.appendChild(document.createElement('A'));
731 closeA.addEventListener('click',function() {item.style.display='none';showA.style.display='block';closeA.style.display='none';}, true);
732 closeA.innerHTML = "Hide";
733 closeA.title="Hide the additional informations on this group.";
734 closeA.href="#"+groupLI.id;
735 closeA.setAttribute("style","font-size:85%;color:grey;text-decoration: underline;");
738 var item = groupLI.fgpeItem;
740 var matches = /<a href="\/groups\/(.*?)">/.exec(groupLI.innerHTML);
743 item = groupLI.appendChild(document.createElement('DIV'));
744 item.setAttribute("style","border:1px solid black; font-size:80%; padding: 0 7px;");
745 if(groupLI.parentNode.parentNode.className == "List") item.style.width="640px";
746 item.innerHTML = '<img id="fgpe_pulser" src="http://www.flickr.com/images/pulser2.gif" style="vertical-align:middle;margin-right:4px;border:0px #ffffff" />';
748 this.api.flickr_api_call('flickr.urls.lookupGroup',
749 { url: "http://www.flickr.com/groups/"+id, http_method: 'POST' },
750 getObjectMethodClosure21(this,'lookupGroup_done', item),
751 getObjectMethodClosure11(this,'request_failed',item));
752 groupLI.fgpeItem = item;
755 item.style.display="block";
759 request_failed: function(err,item) {
760 var groupLI = item.parent;
761 item.style.display='none';
762 groupLI.fgpeShowA.style.display='block';
763 groupLI.fgpeCloseA.style.display='none';
764 status_msg.msgbox('Sorry, there was an error.');
767 lookupGroup_done: function(req,rsp,item) {
768 var id = rsp.group[0].@id;
770 this.api.flickr_api_call('flickr.groups.pools.getPhotos',
771 { group_id: id, user_id: this.user_id,per_page: MAX_DAY_COUNT+1, http_method: 'POST' },
772 getObjectMethodClosure21(this,'displayLastDate_done', new Array(item,id)),
773 getObjectMethodClosure11(this,'displayLastDate_failed',new Array(item,id)),true);
775 item.innerHTML += '<a href="http://www.krazydad.com/gustavog/FlickRandom.pl?group='+id+'" title="See random pictures from the group">FlickrRandom</a><br/>';
776 this.postPoneDescription(new Array(item,id,0));
777 this.postPonePhotos(new Array(item,id,0));
779 postPoneDescription: function(args) {
783 if(item.fgpeCompleteDate || cnt > 10){
784 this.api.flickr_api_call('flickr.groups.getInfo',
785 {group_id: id, http_method: 'POST' },
786 getObjectMethodClosure21(this,'addDescription_done', new Array(item)),
787 getObjectMethodClosure11(this,'request_failed',item),true);
789 setTimeout(getObjectMethodClosure0(this,'postPoneDescription',args),1000);
792 addDescription_done: function(req,rsp, arrayArgs) {
793 var item = arrayArgs[0];
794 item.innerHTML += "<div style=\"color:black;max-height:20ex;border:1px dashed black; padding: 0 3px;overflow:auto;\">"+rsp..description[0]+"</div>";
795 item.fgpeCompleteDescription = true;
798 postPonePhotos: function(args) {
802 if(item.fgpeCompleteDescription || cnt > 10){
803 this.api.flickr_api_call('flickr.groups.pools.getPhotos',
804 {group_id: id, per_page: NUMBER_OF_LAST_PHOTOS, http_method: 'POST' },
805 getObjectMethodClosure21(this,'displayGroupPhotos_done', new Array(item,id)),
806 getObjectMethodClosure11(this,'request_failed',item),true);
808 setTimeout(getObjectMethodClosure0(this,'postPonePhotos',args),1000);
811 addPhotoLi_done: function(req,rsp,arrayArgs) {
812 var photo = arrayArgs[0];
813 var item = arrayArgs[1];
814 var groupID = arrayArgs[2];
815 item.innerHTML += "<li style=\"display:inline;\"><a titel=\""+photo.@title+"\" href=\"http://www.flickr.com/photos/"+photo.@owner+"/"+photo.@id+"/in/pool-"+groupID+"\"><img alt=\""+photo.@title+" (square size)\" src=\""+rsp..size.@source[0]+"\"/></a></li>";
818 displayGroupPhotos_done: function(req,rsp,arrayArgs) {
819 var item = arrayArgs[0];
820 var groupID = arrayArgs[1];
822 if(rsp.photo.@total) total = rsp.photos.@total;
823 item.innerHTML += total+" photo(s)";
824 item.innerHTML += '<ul style="list-style-type:none;">';
825 for each(photo in rsp..photo) {
826 this.api.flickr_api_call('flickr.photos.getSizes',
827 { photo_id: photo.@id, http_method: 'POST' },
828 getObjectMethodClosure21(this,'addPhotoLi_done',new Array(photo,item,groupID)),
829 getObjectMethodClosure11(this,'request_failed',item));
831 item.innerHTML += '</ul>';
832 item.removeChild(document.getElementById('fgpe_pulser'));
835 displayLastDate_failed: function(err,item) {
836 unsafeWindow.console.log(item);
838 var group_id = args[1];
839 if(document.location.pathname.indexOf('/people') >= 0) {
840 //we are in a user profile.
842 var hisid = document.evaluate("/html/body/div[@id='Main']/div[3]/table[@id='ProfileInfo']/tbody/tr/td[@id='Right']/p[1]/a",
843 document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
846 var matches = /\?to=(.+)$/.exec(hisid.href);
848 item.innerHTML += "<a title=\"View The photos this user posted\" href=\"http://flickr.com/groups/"+group_id+"/pool/"+matches[1]+"\">Current user contributions.</a> ";
854 displayLastDate_done: function(req,rsp,args) {
856 var group_id = args[1];
858 if(parseInt(rsp..photos.@total) > 0) {
859 var first_date = new Date(parseInt(rsp..photo.@dateadded[0])*1000);
861 for each (photo in rsp..photo) {
862 var last = parseInt(photo.@dateadded[0])*1000;
863 var date = new Date(last);
864 var diff = (Date.now()-date.getTime())/(1000*3600*24);
870 html = "<span style=\"color:green !important;\">";
872 html = "<span style=\"color:red !important;\">";
873 html += "<a title=\"View The photos you posted\" href=\"http://flickr.com/groups/"+group_id+"/pool/"+this.user_id+"\">";
874 html += "Your Last Post:</a> "+first_date.toLocaleString()+"</span>";
876 if(cnt <= 5) html += ",today: "+cnt;
877 else if (cnt > 5) html += ",today: >5";
881 if(document.location.pathname.indexOf('/people') >= 0) {
882 //we are in a user profile.
884 var hisid = document.evaluate("/html/body/div[@id='Main']/div[3]/table[@id='ProfileInfo']/tbody/tr/td[@id='Right']/p[1]/a",
885 document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
888 var matches = /\?to=(.+)$/.exec(hisid.href);
890 html += "<a title=\"View The photos this user posted\" href=\"http://flickr.com/groups/"+group_id+"/pool/"+matches[1]+"\">Current user contributions.</a> ";
894 item.innerHTML += html;
895 item.fgpeCompleteDate = true;
899 // update automatically (http://userscripts.org/scripts/show/2296)
901 window.addEventListener("load", function () {
903 win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
906 var flickrgp = new win.FlickrGroupPage();
907 flickrgp.init( "e8c3239ff04c102ce2d6ed885bf99005","247fcd31d50cdef4");