1 // Flickr Scientist Photographers tools
4 // Copyright (c) 2006, Pierre Andrews.
5 // Released under the GPL license
6 // http://www.gnu.org/copyleft/gpl.html
9 // @name Flickr Scientist Photographers tools
10 // @namespace http://6v8.gamboni.org/
11 // @description tools for administrators of the scientist photographers group.
14 // @creator Pierre Andrews (mortimer.pa@free.fr)
15 // @include http://*flickr.com/groups/sciencegroup*
22 //======================================================================
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
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) {
48 return object[method](arg);
52 function getObjectMethodClosure01(object, method, arg,arg1) {
54 return object[method](arg,arg1);
58 if(unsafeWindow.console)
59 unsafeWindow.console.log(arguments);
64 var FlickrSPAdminTools = function() {this.init();}
66 FlickrSPAdminTools.prototype = {
70 selectedPhotos: new Array(),
71 removePhotosList: new Array(),
75 var threadTitle = document.evaluate(
76 "//td[@id='GoodStuff']/h2",
77 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
79 var del = document.evaluate("//a[@class='Warning']",
80 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
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)) {
85 /* var adminLink = document.evaluate(
86 "//a[@href='/groups/sciencegroup/admin/']",
87 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
90 this.addCleanPoolTool(adminLink.parentNode);
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
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');
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';
133 button.addEventListener('click',function() {
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;
146 var buttonTotal = document.createElement('button');
147 buttonTotal.innerHTML = "Make Total";
148 buttonTotal.type='button';
149 buttonTotal.className = 'Butt';
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();
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>');
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') {
168 var l = lines[j].replace(/^\s*[0-9]+-/,'');
169 grades[idx++].push(value);
175 var author = document.evaluate("h4/a[2]",
176 paragraph.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
178 if(!author) author = document.evaluate("h4/a[1]",
179 paragraph.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
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)+'- ';
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++;
200 nan += length-grades[i].length;
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);
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) {
219 var last = scores[idx][0];
221 var places = new Array("First", "Second", "Third");
222 message.value += "\n--------------------\n\n";
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";
232 if(idx < scores.length)
233 last = scores[idx][0];
238 message.value +=places[l]+" Place: Image "+sel+" ("+scores[idx-1][0]+" points)\n";
239 message.value += img+"\n";
243 message.parentNode.parentNode.insertBefore(buttonTotal,message.parentNode.nextSibling);
244 message.parentNode.parentNode.insertBefore(button,message.parentNode.nextSibling);
249 //======================================================================
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";
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'));
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);
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) {
314 flickr_groups_pools_getPhotos_onLoad: function(success, responseXML, responseText, params){
315 if(success) self.process_taggedID(responseText,okButton,contentDiv);
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.*\?>/,'');
331 contentDiv.innerHTML = "There was an error fetching photos";
334 for each(photo in rsp..photo) {
335 this.selectedPhotos.push(parseInt(photo.@id));
340 flickr_groups_pools_getPhotos_onLoad: function(success, responseXML, responseText, params){
342 var rsp = responseText.replace(/<\?xml.*\?>/,'');
346 contentDiv.innerHTML = "There was an error fetching photos";
349 var thisweek = new Date();
350 thisweek = thisweek.getTime()
352 +((24-thisweek.getHours())*3600+(60-thisweek.getMinutes())*60
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";
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" />';
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'));
397 setTimeout(getObjectMethodClosure(this,'waitForAllRemove'),1000);
401 makeAuthorName: function(name) {
402 var sp = name.toLowerCase().replace(/(^[_'.]|['_.]$)/g,'').replace(/[_'.]/gi,' ');
405 sp = sp[0].substr(0,1)+'.'+sp[1].substr(0,1)+'.';
407 sp = sp[0].substr(0,2);
412 //======================================================================
415 window.addEventListener("load", function () {
418 // update automatically (http://userscripts.org/scripts/show/2296)
419 //win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
422 new FlickrSPAdminTools();