fixed sets... added support for user tags
[FlickrHacks.git] / _greasemonkey_ / flickrscientistphotograp.user.js
blob4ab93f4d41465c84e5f0db6ec0faadf7a060d143
1 // Flickr Scientist Photographers tools
2 // v0.2
3 // 2006-24-06
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 Scientist Photographers tools
10 // @namespace http://6v8.gamboni.org/
11 // @description tools for administrators of the scientist photographers group.
12 // @version 0.1
13 // @date 2006-19-06
14 // @creator Pierre Andrews (mortimer.pa@free.fr)
15 // @include http://*flickr.com/groups/sciencegroup*
16 // ==/UserScript==
18 (function () {
20 var PER_PAGE = 500;
22 //======================================================================
24 //update information
25 var SCRIPT = {
26 name: "Flickr Scientist Photographers tools",
27 namespace: "http://6v8.gamboni.org/",
28 description: "Tools for administrators of the scientist photographers group.",
29 identifier: "http://6v8.gamboni.org/IMG/js/flickrscientistphotograp.user.js",
30 version: "0.2", // version
31 date: (new Date(2006, 6, 24)) // update date
32 .valueOf()
36 //======================================================================
37 //to do the closure and get the right this.
38 //adapted from http://persistent.info/greasemonkey/gmail.user.js
40 function getObjectMethodClosure(object, method) {
41 return function(arg) {
42 return object[method](arg);
46 function getObjectMethodClosure0(object, method, arg) {
47 return function() {
48 return object[method](arg);
52 function getObjectMethodClosure01(object, method, arg,arg1) {
53 return function() {
54 return object[method](arg,arg1);
57 function M8_log() {
58 if(unsafeWindow.console)
59 unsafeWindow.console.log(arguments);
60 else
61 GM_log(arguments);
64 var FlickrSPAdminTools = function() {this.init();}
66 FlickrSPAdminTools.prototype = {
67 votes: new Array(),
68 voters: new Array(),
69 imgSrc: new Array(),
70 selectedPhotos: new Array(),
71 removePhotosList: new Array(),
72 removed: 0,
74 init: function() {
75 var threadTitle = document.evaluate(
76 "//td[@id='GoodStuff']/h2",
77 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
78 ).singleNodeValue;
79 var del = document.evaluate("//a[@class='Warning']",
80 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
81 ).singleNodeValue;
82 if(threadTitle && del && del.innerHTML == "delete topic" && (threadTitle.innerHTML.indexOf('Selection Week') >= 0 || threadTitle.innerHTML.indexOf('Selection week') >= 0 || threadTitle.innerHTML.indexOf('selection week') >= 0 || threadTitle.innerHTML.indexOf('Selection') >= 0)) {
83 this.addVotingTool();
85 /* var adminLink = document.evaluate(
86 "//a[@href='/groups/sciencegroup/admin/']",
87 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
88 ).singleNodeValue;
89 if(adminLink) {
90 this.addCleanPoolTool(adminLink.parentNode);
91 }*/
94 showHideDec: function(vote,voteDec) {
95 if(vote.value!="x") voteDec.style.display = 'inline';
96 else voteDec.style.display = 'none';
99 addVotingTool: function() {
100 var message = document.evaluate(
101 "//textarea[@name='message']",
102 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
103 ).singleNodeValue;
104 if(message) {
105 var images = document.evaluate(
106 "//table[@class='TopicReply']//td[@class='Said']/p//img",
107 document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
108 for(var i = 0; i < images.snapshotLength; i++) {
109 var img = images.snapshotItem(i);
110 var vote = document.createElement('select');
111 var voteDec = document.createElement('select');
112 var html = '';
113 for(var j=1; j<10; j++) {
114 html += '<option>'+j+"</option>\n";
116 vote.innerHTML = "<option>x</option>\n"+html+"<option>10</option>\n";
117 voteDec.innerHTML = "<option>0</option>\n"+html;
118 voteDec.style.display ='none';
119 vote.addEventListener('change',getObjectMethodClosure01(this,'showHideDec',vote,voteDec),true);
120 img.parentNode.parentNode.insertBefore(vote,img.parentNode);
121 img.parentNode.parentNode.insertBefore(document.createTextNode('.'),img.parentNode);
122 img.parentNode.parentNode.insertBefore(voteDec,img.parentNode);
123 img.parentNode.parentNode.insertBefore(document.createElement('br'),img.parentNode);
124 this.imgSrc.push(new Array(img.src.replace(/\.jpg/,'_t.jpg'),img.parentNode.href));
125 this.votes.push(vote);
126 this.votes.push(voteDec);
128 var button = document.createElement('button');
129 button.innerHTML = "VOTE";
130 button.type='button';
131 button.className = 'Butt';
132 var self = this;
133 button.addEventListener('click',function() {
134 var msg = '';
135 for(var k = 0;k< self.votes.length;k=k+2) {
136 msg += (k/2+1)+'- '+self.votes[k].value;
137 if(self.votes[k+1].style.display == 'inline') msg+= '.'+self.votes[k+1].value;
138 msg+="\n";
140 message.value = msg;
141 return false;
142 },true);
144 //For counting
146 var buttonTotal = document.createElement('button');
147 buttonTotal.innerHTML = "Make Total";
148 buttonTotal.type='button';
149 buttonTotal.className = 'Butt';
150 var self = this;
151 buttonTotal.addEventListener('click',function() {
152 var paraphs = document.evaluate("//table[@class='TopicReply']//td[@class='Said']/p",
153 document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
154 var grades = new Array();
155 var length = 0;
156 for(var i = 0; i < paraphs.snapshotLength; i++) {
157 var paragraph = paraphs.snapshotItem(i);
158 if(paragraph.innerHTML.indexOf('<img') < 0) {
159 var lines = paragraph.innerHTML.split('<br>');
160 var idx = 0;
161 var cnt = false;
162 for(var j = 0;j<lines.length;j++) {
163 if(!grades[idx]) grades[idx] = new Array();
164 if(matches = /^\s*([0-9]+-\s*)?([0-9x]+(.[0-9]+)?)\s*.*$/mi.exec(lines[j])) {
165 var value = parseFloat(matches[2]);
166 if(value != NaN || matches[2] == 'x' || matches[2] == 'X') {
167 var cnt = true;
168 var l = lines[j].replace(/^\s*[0-9]+-/,'');
169 grades[idx++].push(value);
174 if(cnt) {
175 var author = document.evaluate("h4/a[2]",
176 paragraph.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
177 ).singleNodeValue;
178 if(!author) author = document.evaluate("h4/a[1]",
179 paragraph.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
180 ).singleNodeValue;
181 length++;
182 self.voters.push(self.makeAuthorName(author.innerHTML));
186 var scores = new Array();
187 for(var i=0; i < grades.length;i++) {
188 if(grades[i].length > 0) {
189 message.value += (i+1)+'- ';
190 var tot = 0;
191 var nan = 0;
192 var line = '';
193 for(var j=0; j<grades[i].length;j++) {
194 line += ', '+self.voters[j]+' '+grades[i][j];
195 if(isNaN(grades[i][j])) nan++;
196 else {
197 tot += grades[i][j];
200 nan += length-grades[i].length;
201 if(nan > 0) {
202 M8_log((i+1)+"-"+tot+"/"+(grades[i].length-nan));
203 var moy = tot/(grades[i].length-nan);
204 line = line.replace(/NaN/g,moy);
205 tot += moy*nan;
207 tot = parseInt(tot*100)/100;
208 scores.push(new Array(tot,i));
209 line = line.substr(1);
210 message.value += line+' = '+tot+"\n";
213 scores.sort(function(A, B) {
214 var totA = A[0];
215 var totB = B[0];
216 return totB-totA;
218 var idx = 0;
219 var last = scores[idx][0];
220 var l =0;
221 var places = new Array("First", "Second", "Third");
222 message.value += "\n--------------------\n\n";
224 while(l<3) {
225 var sel = '';
226 var img = '';
227 while(scores[idx][0] == last) {
228 sel += ' and '+(scores[idx][1]+1);
229 img += '<a href="'+self.imgSrc[scores[idx][1]][1]+'"><img src="'+self.imgSrc[scores[idx][1]][0]+'"/></a>'+"\n";
230 idx++;
232 if(idx < scores.length)
233 last = scores[idx][0];
234 else break;
236 sel = sel.substr(4);
238 message.value +=places[l]+" Place: Image "+sel+" ("+scores[idx-1][0]+" points)\n";
239 message.value += img+"\n";
240 l++;
242 },true);
243 message.parentNode.parentNode.insertBefore(buttonTotal,message.parentNode.nextSibling);
244 message.parentNode.parentNode.insertBefore(button,message.parentNode.nextSibling);
249 //======================================================================
250 // Pool cleaning bit
251 //======================================================================
253 addCleanPoolTool: function(links) {
254 links.innerHTML += '<img width="1" height="11" alt="" src="/images/subnavi_dots.gif"/>';
255 var clean = links.appendChild(document.createElement('a'));
256 clean.innerHTML = "Clean Pool";
257 clean.href = '#';
258 clean.style.color = 'red';
259 clean.addEventListener('click',getObjectMethodClosure(this,"cleanPool"),true);
262 cleanPool: function() {
263 var back = document.body.appendChild(document.createElement('div'));
264 back.id="poolCleaningBack";
265 back.setAttribute('style',"position:absolute;background-color: black;opacity: 0.35; display: block; left: 0pt;");
266 back.style.width = document.body.clientWidth+'px';
267 back.style.height = document.body.clientHeight+'px';
268 back.style.top = document.body.scrollTop+'px';
269 var modal = document.body.appendChild(document.createElement('div'));
270 modal.id="poolCleaning";
271 modal.setAttribute('style',"position:absolute;background:white;border: 3px solid black;width: 300px;display: block; left: 442px;");
272 modal.innerHTML = '<div style="padding:12px;background-color: #EEEEEE;clear:both;font-size: 14px;">Remove Photos that were not selected</div>';
273 modal.style.top = document.body.scrollTop+(document.body.clientHeight/2)+'px';
275 var dialog = modal.appendChild(document.createElement('div'));
276 dialog.setAttribute('style',"padding: 18px 16px;clear:both;");
277 var content = dialog.appendChild(document.createElement('div'));
278 content.innerHTML = "Fetching Photos";
280 var caution = dialog.appendChild(document.createElement('div'));
281 caution.style.margin = "1em";
282 caution.style.paddingTop = "1em";
283 caution.style.borderTop = "1px solid black"
284 caution.innerHTML += '<strong>BEWARE</strong> This operation is not reversible and will remove any photo in the pool that has not been tagged with "SP selection" or posted since Monday.';
286 var buttons = dialog.appendChild(document.createElement('div'));
287 var ok = buttons.appendChild(document.createElement('button'));
288 ok.type ='button';
289 ok.disabled = true;
290 ok.className='Butt';
291 ok.innerHTML = '<img id="fgpe_pulser" src="http://www.flickr.com/images/pulser2.gif" style="vertical-align:middle;margin-right:4px;border:0px #ffffff" />';
292 var cancel = buttons.appendChild(document.createElement('button'));
293 cancel.type ='button';
294 cancel.className = 'Butt';
295 cancel.innerHTML = 'Cancel';
297 cancel.addEventListener('click',function() {
298 document.body.removeChild(back);
299 document.body.removeChild(modal);
300 },true);
303 ok.addEventListener('click',getObjectMethodClosure01(this,'removePhotos',ok,content),true);
305 modal.style.top = document.body.scrollTop+((document.body.clientHeight-modal.scrollHeight)/2)+'px';
306 this.fetchGroupPhotos(ok,content);
310 fetchGroupPhotos: function(okButton,contentDiv) {
312 var self = this;
313 var listener = {
314 flickr_groups_pools_getPhotos_onLoad: function(success, responseXML, responseText, params){
315 if(success) self.process_taggedID(responseText,okButton,contentDiv);
316 else {
317 contentDiv.innerHTML = "There was an error fetching photos";
318 M8_log(responseText);
323 unsafeWindow.F.API.callMethod('flickr.groups.pools.getPhotos', {tags:'spselection',group_id:"38873539@N00",per_page:PER_PAGE}, listener);
327 process_taggedID: function(rsp,okButton,contentDiv) {
328 var rsp = rsp.replace(/<\?xml.*\?>/,'');
329 rsp = new XML(rsp);
330 if (rsp == null) {
331 contentDiv.innerHTML = "There was an error fetching photos";
332 M8_log(rsp);
333 } else {
334 for each(photo in rsp..photo) {
335 this.selectedPhotos.push(parseInt(photo.@id));
337 var self = this;
338 var thisweekCnt = 0;
339 var listener = {
340 flickr_groups_pools_getPhotos_onLoad: function(success, responseXML, responseText, params){
341 if(success) {
342 var rsp = responseText.replace(/<\?xml.*\?>/,'');
343 rsp = new XML(rsp);
345 if (rsp == null) {
346 contentDiv.innerHTML = "There was an error fetching photos";
347 M8_log(rsp);
348 } else {
349 var thisweek = new Date();
350 thisweek = thisweek.getTime()
351 //move to midnight
352 +((24-thisweek.getHours())*3600+(60-thisweek.getMinutes())*60
353 //move to sunday
354 -thisweek.getDay()*3600*24)*1000;
355 for each(photo in rsp..photo) {
356 if(photo.@dateadded <= (thisweek/1000)) {
357 if(self.selectedPhotos.indexOf(parseInt(photo.@id)) < 0) {
358 self.removePhotosList.push(photo.@id);
362 contentDiv.innerHTML = self.removePhotosList.length + ' photos found.';
363 okButton.disabled = false;
364 okButton.innerHTML = "Remove";
366 } else {
367 contentDiv.innerHTML = "There was an error fetching photos";
368 M8_log(responseText);
373 unsafeWindow.F.API.callMethod('flickr.groups.pools.getPhotos', {group_id:"38873539@N00",per_page:PER_PAGE}, listener);
377 removePhotos: function(okButton,contentDiv) {
378 contentDiv.innerHTML = "removing...";
379 okButton.innerHTML = '<img id="fgpe_pulser" src="http://www.flickr.com/images/pulser2.gif" style="vertical-align:middle;margin-right:4px;border:0px #ffffff" />';
380 var self = this;
381 for(var i=0;i<this.removePhotosList.length;i++) {
382 unsafeWindow.F.API.callMethod('flickr.groups.pools.remove', {group_id:"38873539@N00",photo_id:this.removePhotosList[i]}, {
383 flickr_groups_pools_remove_onLoad: function(success, responseXML, responseText, params) {
384 if(success) self.removed++;
385 else M8_log("Cannot remove photo "+params['photo_id']+": " +responseText);
389 this.waitForAllRemove();
392 waitForAllRemove: function() {
393 if(this.removed >= this.removePhotosList.length) {
394 document.body.removeChild(document.getElementById('poolCleaning'));
395 document.body.removeChild(document.getElementById('poolCleaningBack'));
396 } else {
397 setTimeout(getObjectMethodClosure(this,'waitForAllRemove'),1000);
401 makeAuthorName: function(name) {
402 var sp = name.toLowerCase().replace(/(^[_'.]|['_.]$)/g,'').replace(/[_'.]/gi,' ');
403 sp = sp.split(' ');
404 if(sp.length > 1) {
405 sp = sp[0].substr(0,1)+'.'+sp[1].substr(0,1)+'.';
406 } else
407 sp = sp[0].substr(0,2);
408 return sp;
412 //======================================================================
413 // launch
414 try {
415 window.addEventListener("load", function () {
416 try {
418 // update automatically (http://userscripts.org/scripts/show/2296)
419 //win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
420 } catch (ex) {}
422 new FlickrSPAdminTools();
423 }, false);
424 } catch (ex) {}
426 })();