2 // @name Flickr Photo Compass
3 // @namespace http://6v8.gamboni.org/
4 // @description Show nearby photos at the cardinate points
6 // @identifier http://6v8.gamboni.org/IMG/js/flickrphotocompass.user.js
8 // @creator Pierre Andrews (mortimer.pa@free.fr)
9 // @include http://*flickr.com/photos/*/*
13 // --------------------------------------------------------------------
15 // This is a Greasemonkey user script.
17 // To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
18 // Then restart Firefox and revisit this script.
19 // Under Tools, there will be a new menu item to "Install User Script".
20 // Accept the default configuration and install.
22 // --------------------------------------------------------------------
23 // Copyright (C) 2006 Pierre Andrews
25 // This program is free software; you can redistribute it and/or
26 // modify it under the terms of the GNU General Public License
27 // as published by the Free Software Foundation; either version 2
28 // of the License, or (at your option) any later version.
30 // This program is distributed in the hope that it will be useful,
31 // but WITHOUT ANY WARRANTY; without even the implied warranty of
32 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 // GNU General Public License for more details.
35 // The GNU General Public License is available by visiting
36 // http://www.gnu.org/copyleft/gpl.html
38 // Free Software Foundation, Inc.
39 // 51 Franklin Street, Fifth Floor
40 // Boston, MA 02110-1301
48 name: "Flickr Photo Compass",
49 namespace: "http://6v8.gamboni.org/",
50 description: "Show nearby photos at the cardinate points",
51 identifier: "http://6v8.gamboni.org/IMG/js/flickrphotocompass.user.js",
52 version: "0.9", // version
53 date: (new Date("2007-04-01")) // update date
59 if(unsafeWindow.console)
60 unsafeWindow.console.log(arguments);
66 function getObjectMethodClosureB3(object, method,arg0,arg1,arg2) {
67 return function(arg) {
68 return object[method](arg0,arg1,arg2);
72 function getObjectMethodClosure3(object, method,arg1,arg2,arg3) {
73 return function(arg) {
74 return object[method](arg,arg1,arg2,arg3);
78 var DIR_N = 'data:image/gif;base64,R0lGODlhEAAQAPMAALUJCcM/P////759fbceHrtZWcPIyLpNTb1ra8Cfn7+NjcTQ0LUEBAAfk8Xf3////yH5BAEAAA8ALAAAAAAQABAAAARM8MlJq5Uh3Jt3bQzTeE/THCFiXo2zACHhOOPnKGGY0LYT5IzDrCZpGWA5wII3aQ2AoQGz6CgwCAJBbEqdeYeW1tdLpJi+K48pTSJFAAA7';
79 var DIR_NE = 'data:image/gif;base64,R0lGODlhEAAQALMJAM9dXcBGRjoXZv77+7wuLrYLC7UEBAAfk8Xf3////wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAARFMMlJq70458OPHABQcUiJCEJhENRhEkYsj0igyrE4uXVxx6eWKTAY5BCenamkKpSSEt6wAHjSlgHrdakdSZHQSyeswUQAADs=';
80 var DIR_NW = 'data:image/gif;base64,R0lGODlhEAAQALMJAM9dXcBGRjoXZv77+7wuLrYLC7UEBAAfk8Xf3////wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAARFMMlJq704VwCGPOBxEUYhCEiKgJbhvoQqUsD7FsFaoXaBp7MPomYYDHJAyiFVKKmSk+Xw9wwKEUiZRfqEVkBV6zakKUcAADs=';
81 var DIR_E = 'data:image/gif;base64,R0lGODlhEAAQAPMAAAsdi7YLC7cZGcI/P76Cgv///7tSUsTLy7UHB8Cfn2wPPrgoKAAfk7UEBMXf3////yH5BAEAAA8ALAAAAAAQABAAAARD8MlJq704Z8aZ5k7ocBcjGsQRepUZNg0yEEArOgIMBwrlhgWdcCD5OYJCGPFhTAp6PhEMYUiwoqFFalUykjYdjfgRAQA7';
82 var DIR_W = 'data:image/gif;base64,R0lGODlhEAAQAPMAAAsdi7YLC7cZGcI/P76Cgv///7tSUsTLy7UHB8Cfn2wPPrgoKAAfk7UEBMXf3////yH5BAEAAA8ALAAAAAAQABAAAARD8MlJq704Z8aZ5k7ocBcTHoQhehVADEjTrJUSyLIgjtKA/4Udy/eTBWkThaAorDAShtgsxKKYHKgF0nmlVksdjfgRAQA7';
83 var DIR_SE = 'data:image/gif;base64,R0lGODlhEAAQALMJAM9dXcBGRjoXZv77+7wuLrYLC7UEBAAfk8Xf3////wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAARFMMlJq70458OP5kiIcNchnqNlnkHoUasYFIALo4VR2FMcDAODofaSrGY5oQEhqJhmSiXAKSJEhaoYU5AjlDqSAWCqsUQAADs=';
84 var DIR_SW = 'data:image/gif;base64,R0lGODlhEAAQALMJAM9dXcBGRjoXZv77+7wuLrYLC7UEBAAfk8Xf3////wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAAARFMMlJq70468PPPkiIcBconl5lBueohkDBopRZGEWbSiBgGIPBzDURIH6/giy0S/iQSVYzAf0RRE0CTmDETgGAAa+jKUcAADs=';
85 var DIR_S = 'data:image/gif;base64,R0lGODlhEAAQAPMAALUJCf///7ceHr59fcY/P7tZWbk/P7pNTb1ra8Cfn7+NjcTNzbUEBAAfk8Xf3////yH5BAEAAA8ALAAAAAAQABAAAARG8MlJq70458ab5k7ocFcjnqNloqFHmQLDBEFcpJM5yDwz4BLTAtADLICP1aFnaFVMiZ4CGQzFGEZqsIGQHUgbmUvzIBAuEQA7';
87 var flickrphotocompass = function() {this.init();}
89 flickrphotocompass.prototype = {
93 coord: {lon:'',lat:''},
99 if( this.coord.lat=='' || this.coord.lon=='' ) return;
102 coordDone: function() {
103 GM_addStyle("a.flickrphotocompass_link:hover {background-color:transparent;}");
104 var uploadedBy = document.evaluate( "/html/body/div[@id='Main']/table[@id='Photo']/tbody/tr/td[2]/div[1]/a[1]/img[1]",
105 document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
107 var photoid = unsafeWindow.page_photo_id;
109 this.nsid = uploadedBy.src.replace(/.*\/buddyicons\/(.*?).jpg\?.*/,'$1');
110 this.user_name = uploadedBy.parentNode.parentNode.getElementsByTagName('a').item(2).innerHTML;
113 this.img_src = {id:photoid,server:unsafeWindow.global_photos[unsafeWindow.page_photo_id].server,secret:unsafeWindow.global_photos[unsafeWindow.page_photo_id].secret};
115 var insertPoint = document.getElementById('otherContexts_div');
116 var div = document.createElement("div");
117 var h3 = div.appendChild(document.createElement('div'));
118 h3.setAttribute('style',"margin: 20 15 0 2; background-color: white; padding: 3 4 4 4; border: 1px solid #F3F3F3; border-bottom: 0px; font-size:14px; font-weight: 400; color: #FF0084;");
119 h3.innerHTML = '<a href="http://maps.yuan.cc" class="currentContextLink">Nearby Photos</a>'+
120 '<img id="flickrphotocompass_wait" src="http://www.flickr.com/images/pulser2.gif" style="margin:0;padding:0;margin-right:4px;border:0px #ffffff;display:none;height: 16px;" />';
121 this.container = div.appendChild(document.createElement('div'));
122 this.container.setAttribute('style','background-color:#f3f3f3;border: 1px solid #E3E3E3;margin:0;width:240px;height:240px;');
123 this.container.innerHTML = 'Searching...';
124 var spanCheck = div.appendChild(document.createElement('div'));
125 spanCheck.setAttribute('style',"margin: 0 15 0 2; background-color: #f3f3f3; padding: 0 4; border: 1px solid #e3e3e3; border-top: 0px; font-size:10px; font-weight: 400;");
126 var onlyuser = spanCheck.appendChild(document.createElement('input'));
127 onlyuser.type = 'checkbox';
128 onlyuser.id = 'flickrphotocompass_check';
130 onlyuser.addEventListener('click',function(ev) {
131 self.only_user = onlyuser.checked;
132 self.getPhotos(self.coord.lat,self.coord.lon,self.img_src);
135 var label = spanCheck.appendChild(document.createElement('label'));
136 label.setAttribute('style',"position:relative;top:-4px;");
137 label.innerHTML = "only "+this.user_name+"'s photos";
138 label.htmlFor = 'flickrphotocompass_check';
140 div.style.width = "220px";
142 insertPoint.parentNode.insertBefore(div,insertPoint);
143 this.getPhotos(this.coord.lat,this.coord.lon,this.img_src);
147 getCoord: function() {
148 var tmp = new Array();
149 var photoid = unsafeWindow.page_photo_id;
150 var tags = tmp.concat(unsafeWindow.global_photos[photoid].tags_rawA);
151 this.coord = {lat: '', lon: ''};
153 var moreLot = document.evaluate(
154 "//td[@class='RHS']/ul//li/a[@class='Plain']",
155 document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null
157 for(var i = 0; i < moreLot.snapshotLength; i++) {
158 var map = moreLot.snapshotItem(i);
159 if(map.innerHTML == 'map') {
160 var ul = map.parentNode.appendChild(document.createElement('ul'));
161 var onclick = map.getAttribute('onclick');
163 if(matches = /new YGeoPoint\(([0-9.-]+),([0-9.-]+)\)/.exec(onclick)) {
164 this.coord.lat = matches[1];
165 this.coord.lon = matches[2];
172 if(this.coord.lat=='' || this.coord.lon=='' ) {
173 while( tags && tags.length > 0 ) {
175 splits = tag.split('=');
176 if( splits[0] == 'geo:lat' ) this.coord.lat = 1*splits[1];
177 if( splits[0] == 'geo:lon' || splits[0] == 'geo:long' ) this.coord.lon = 1*splits[1];
183 if(this.coord.lat == '' || this.coord.lon == '') {
184 var description = document.evaluate("//div[@id='About']/div[@class='photoDescription']",
185 document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
189 if(matches = /(ll|q)=([-0-9.]+),([-0-9.]+)/.exec(description.innerHTML)) {
190 this.coord.lat = matches[2];
191 this.coord.lon = matches[3];
199 if(this.coord.lat=='' || this.coord.lon=='' ) {
202 flickr_photos_getExif_onLoad: function(success, responseXML, responseText, params){
204 var rsp = responseText.replace(/<\?xml.*\?>/,'');
206 lat_dir = (rsp..exif.(@label == 'North or South Latitude').raw == 'S')?-1:1
207 lat = new String(rsp..exif.(@label == 'Latitude').raw);
208 lon_dir = (rsp..exif.(@label == 'East or West Longitude').raw == 'W')?-1:1
209 lon = new String(rsp..exif.(@label == 'Longitude').raw);
210 if((lat.length > 0) && (lon.length > 0)) {
211 lat = lat.split(/[,\/]/);
212 lat_deg = parseInt(lat[0])/parseInt(lat[1]);
213 lat_min = parseInt(lat[2])/parseInt(lat[3]);
214 lat_sec = parseInt(lat[4])/parseInt(lat[5]);
215 self.coord.lat = lat_dir * (lat_deg + (lat_min+lat_sec/60)/60);
217 lon = lon.split(/[,\/]/);
218 lon_deg = parseInt(lon[0])/parseInt(lon[1]);
219 lon_min = parseInt(lon[2])/parseInt(lon[3]);
220 lon_sec = parseInt(lon[4])/parseInt(lon[5]);
221 self.coord.lon = lon_dir * (lon_deg + (lon_min+lon_sec/60)/60);
227 unsafeWindow.F.API.callMethod('flickr.photos.getExif', {
237 compassCell: function(img_src,dir,coord) {
238 var to_ret = document.createElement('td');
239 to_ret.setAttribute('style',"height:75px;width:75px;");
241 var img_dir, pos_l, pos_t;
243 var marker_div = to_ret.appendChild(document.createElement('div'));
244 marker_div.setAttribute('style',"padding:0;margin:0;display:inline;");
245 var img_a = marker_div.appendChild(document.createElement('a'));
246 img_a.href= 'http://www.flickr.com/photos/'+img_src.owner+'/'+img_src.id+"/#in/nearby";
247 img_a.title=img_src.title;
248 var img = img_a.appendChild(document.createElement('img'));
249 img.alt = img_src.title;
250 img.src='http://static.flickr.com/' + img_src.server + '/' + img_src.id + '_' + img_src.secret + '_s.jpg';
343 var dir_div = to_ret.appendChild(document.createElement('div'));
344 dir_div.setAttribute('style',"float:left;height:0;");
346 var span = document.createElement('span');
347 span.setAttribute('style','font-size:80%;font-weight:bold;position:relative;left:'+pos_l+';top:'+pos_t+';');
348 span.innerHTML = dir;
349 if(dir == 'NE' || dir == 'E' || dir == 'SE')
350 dir_div.appendChild(span);
352 var dir_img = document.createElement('img');
353 dir_img.src = img_dir;
354 dir_img.setAttribute('style','position:relative;left:'+pos_l+';top:'+pos_t+';');
356 var move_a = dir_div.appendChild(document.createElement('a'));
357 move_a.href="javascript:;";
358 move_a.className = 'flickrphotocompass_link';
359 move_a.appendChild(dir_img);
360 move_a.addEventListener('click',getObjectMethodClosureB3(this,'getPhotos',coord.lat,coord.lon,img_src),true);
362 dir_div.appendChild(dir_img);
364 if(dir != 'NE' && dir != 'E' && dir != 'SE')
365 dir_div.appendChild(span);
370 photosResults: function(responseDetails,lat,lon,photo_data) {
372 var parser = new unsafeWindow.DOMParser();
373 var dom = parser.parseFromString(responseDetails.responseText, "application/xml");
374 var stat = dom.getElementsByTagName('rsp')[0].getAttribute('stat');
376 var photos = dom.getElementsByTagName('photo');
380 var N, NE, E, SE, S, SW, W, NW;
381 var coord_N, coord_NE, coord_E, coord_SE, coord_S, coord_SW, coord_W, coord_NW;
383 var CENTER = 'http://static.flickr.com/' +
390 while(total < 8 && i < photos.length) {
391 var id = photos[i].getAttribute('id');
392 var owner = photos[i].getAttribute('owner');
393 var secret = photos[i].getAttribute('secret');
394 var server = photos[i].getAttribute('server');
395 var title = photos[i].getElementsByTagName('title').item(0).firstChild.data;
396 var img_s = {server: server, id:id,secret:secret,owner:owner,title:title};
398 if(id != photo_data.id) {
399 var y = 1*photos[i].getElementsByTagName('longitude').item(0).firstChild.data;
400 var x = 1*photos[i].getElementsByTagName('latitude').item(0).firstChild.data;
401 var coord = {lat: x,lon: y};
402 var arc = Math.atan2(x-lat,y-lon);
403 if( -1/8*PI<=arc && arc<=1/8*PI && !E) { E = img_s; total++;coord_E = coord;}
404 if( 1/8*PI<=arc && arc<=3/8*PI && !NE) { NE = img_s; total++;coord_NE = coord;}
405 if( 3/8*PI<=arc && arc<=5/8*PI && !N) { N = img_s; total++;coord_N = coord;}
406 if( 5/8*PI<=arc && arc<=7/8*PI && !NW) { NW = img_s; total++;coord_NW = coord;}
407 if( 7/8*PI<=arc || arc<=-7/8*PI && !W) { W = img_s; total++;coord_W = coord;}
408 if( -7/8*PI<=arc && arc<=-5/8*PI && !SW) { SW = img_s; total++;coord_SW = coord;}
409 if( -5/8*PI<=arc && arc<=-3/8*PI && !S) { S = img_s; total++;coord_S = coord;}
410 if( -3/8*PI<=arc && arc<=-1/8*PI && !SE) { SE = img_s; total++;coord_SE = coord;}
416 table = document.createElement('table');
417 table.setAttribute('style',"background-color:#f3f3f3;border-left: 1px solid white; border-top:1px solid white;border-bottom: 1px solid #E3E3E3;border-right: 1px solid #E3E3E3;");
418 var tbody = table.appendChild(document.createElement('tbody'));
419 var tr = tbody.appendChild(document.createElement('tr'));
420 tr.appendChild(this.compassCell(NW,'NW',coord_NW));
421 tr.appendChild(this.compassCell(N,'N',coord_N));
422 tr.appendChild(this.compassCell(NE,'NE',coord_NE));
423 tr = tbody.appendChild(document.createElement('tr'));
424 tr.appendChild(this.compassCell(W,'W',coord_W));
425 var td = tr.appendChild(document.createElement('td'));
426 td.setAttribute('style',"height:75px;width:75px;");
428 if(photo_data.owner) {
429 html = '<a href="http://www.flickr.com/photos/'+photo_data.owner+'/'+photo_data.id+'/#in/nearby" title="'+photo_data.title+'">';
431 html += '<img src="'+CENTER+'" style="margin:0;"'+
432 (photo_data.title?('alt="'+photo_data.title+'"'):'')
434 if(photo_data.owner) {
438 tr.appendChild(this.compassCell(E,'E',coord_E));
439 tr = tbody.appendChild(document.createElement('tr'));
440 tr.appendChild(this.compassCell(SW,'SW',coord_SW));
441 tr.appendChild(this.compassCell(S,'S',coord_S));
442 tr.appendChild(this.compassCell(SE,'SE',coord_SE));
444 this.container.innerHTML = '';
445 document.getElementById('flickrphotocompass_wait').style.display='none';
446 this.container.style.width = "240px";
447 this.container.appendChild(table);
453 getPhotos: function(lat,lon,photo_data) {
454 this.coord = {lat:lat,lon:lon};
455 this.img_src = photo_data;
456 document.getElementById('flickrphotocompass_wait').style.display='';
457 var url = 'http://maps.yuan.cc/api.php?method=flickr.search.nearby&limit=50&lat=' +lat+ '&lon=' +lon;
458 if(this.only_user && this.nsid) url += '&flickr_id='+this.nsid;
459 var headers = { 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/Photo Compass', 'Accept': 'application/atom+xml,application/xml,text/xml' };
460 GM_xmlhttpRequest({method: 'GET',
463 onload: getObjectMethodClosure3(this,'photosResults',lat,lon,photo_data)
467 //======================================================================
470 window.addEventListener("load", function () {
473 // update automatically (http://userscripts.org/scripts/show/2296)
474 win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
477 var flickrgp = new flickrphotocompass();