Stig's Flickr Fixr

Show photographer's albums on photostream-pages, Increase display-size and quality of "old" uploads, Photographer's other photos by tag-links, Links to album-map and album-comments, Actually show a geotagged photo on the associated map, Top-pagers - And more to come?...

当前为 2017-07-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Stig's Flickr Fixr
  3. // @namespace dk.rockland.userscript.flickr.fixr
  4. // @description Show photographer's albums on photostream-pages, Increase display-size and quality of "old" uploads, Photographer's other photos by tag-links, Links to album-map and album-comments, Actually show a geotagged photo on the associated map, Top-pagers - And more to come?...
  5. // @author Stig Nygaard, http://www.rockland.dk, https://www.flickr.com/photos/stignygaard/
  6. // @homepageURL http://www.rockland.dk/userscript/flickr/fixr/
  7. // @supportURL https://www.flickr.com/groups/flickrhacks/discuss/72157655601688753/
  8. // @icon http://www.rockland.dk/img/fixr32.png
  9. // @icon64 http://www.rockland.dk/img/fixr64.png
  10. // @match https://*.flickr.com/*
  11. // @version 2017.07.31.0
  12. // @grant none
  13. // @run-at document-start
  14. // @noframes
  15. // ==/UserScript==
  16.  
  17. // CHANGELOG - The most important updates/versions:
  18. var changelog = [
  19. {version: '2017.07.31.0', description: 'New feature: Adding a Google Maps link on geotagged photos. Also: Removing unused code. Development code now in GitHub repository: https://github.com/StigNygaard/Stigs_Flickr_Fixr'},
  20. {version: '2016.08.04.0', description: '"Scale icon" now in color to signal if down-scale necessary to align with size of notes-area. If Orange, click it to downscale/align image.'},
  21. {version: '2016.06.12.3', description: 'An "un-scale button" to align image-size with (native) notes (on photo-pages, but not in lightbox mode).'},
  22. {version: '2016.06.07.1', description: 'Quickly disabling the script\'s notes-feature, because OFFICIAL NATIVE NOTES-SUPPORT IS BACK ON FLICKR !!! :-) :-)'},
  23. {version: '2016.03.11.1', description: 'A link to "recent uploads page" added on the Explore page. Ctrl-click fix for opening tabs in background on search pages (Firefox-only problem?).'},
  24. {version: '2016.02.09.0', description: 'New feature: Link to Explore Calendar added to Explore page (To the right for now, but might move it to top-menu later?).'},
  25. {version: '2016.02.06.2', description: 'New feature: Top-pagers! Hover the mouse in the center just above photostreams to show a pagination-bar.'},
  26. {version: '2016.02.05.1', description: 'Adding a little "bling" to the album-column.'},
  27. {version: '2016.01.30.0', description: 'Killing the terrible annoying sign-up box that keeps popping up if you are *not* logged in on Flickr. Also fixes for and fine-tuning of the notes-support.'},
  28. {version: '2016.01.24.3', description: 'New feature: Updating notes on photos! Besides displaying, you can now also Create, Edit and Delete notes (in a "hacky" and slightly restricted but generally usable way)'},
  29. {version: '2015.12.05.2', description: 'Photo-notes support now includes displaying formatting and active links.'},
  30. {version: '2015.12.03.2', description: 'New feature: Basic "beta" support for the good old photo-notes (read-only, no formatting/links).'},
  31. {version: '2015.11.28.1', description: 'New feature: Album-headers are now updated with links to album-map and album-comments.'},
  32. {version: '2015.08.26.4', description: 'Initial release version. Photo scale/replace, album column and tag-feature.'}
  33. ];
  34.  
  35. var DEBUG = false;
  36. function log(s) {
  37. if (DEBUG && window.console) {
  38. window.console.log(s);
  39. }
  40. }
  41. if (DEBUG) {
  42. if ('loading' === document.readyState) {
  43. log("This userscript is running at document-start time.");
  44. } else {
  45. log("This userscript is running with document.readyState: " + document.readyState);
  46. }
  47. window.addEventListener('DOMContentLoaded', function(){log('(onDOMContentLoaded)');}, false);
  48. window.addEventListener('focus', function(){log('(onfocus)');}, false);
  49. window.addEventListener('load', function(){log('(onload)');}, false);
  50. window.addEventListener('pageshow', function(){log('(onpageshow)');}, false);
  51. window.addEventListener('resize', function(){log('(onresize)');}, false);
  52. window.addEventListener('hashchange', function(){log('(onhashchange)');}, false);
  53. window.addEventListener('blur', function(){log('(onblur)');}, false);
  54. }
  55.  
  56.  
  57. // FIXR page-tracker
  58. var fixr = fixr || {
  59. context: {
  60. pageType: '',
  61. pageSubType: '',
  62. userId: '',
  63. photographerId: '', // value might be delayed (If uninitialized, try call initPhotographerId())
  64. photographerIcon: '',
  65. photographerAlias: '', // (pathalias) bonus-info sometimes initialized (from url) when initializing photoId or albumId
  66. photographerName: '',
  67. photoId: '',
  68. albumId: '',
  69. groupId: '',
  70. galleryId: ''
  71. },
  72. content: null,
  73. pageactionsCount: 0,
  74. timerResizeActionDelayed: 0,
  75. onPageHandlers: [],
  76. onResizeHandlers: [],
  77. onFocusHandlers: [],
  78. runningDirty: function() { // In-development and extra experiments enabled?
  79. return (DEBUG && (fixr.context.userId==='10259776@N00'));
  80. },
  81. timer: {
  82. _test: 0 // TODO
  83. },
  84. clock: {
  85. _d: null,
  86. _pst: null, // Pacific Standard Time
  87. _explore: null,
  88. tick: function () {
  89. this._d = new Date();
  90. this._pst = new Date(this._d);
  91. this._pst.setHours(this._d.getHours() - 8); // PST = UTC-08
  92. this._explore = new Date(this._d);
  93. this._explore.setHours(this._d.getHours() - 28); // Explore beat, yesterday UTC-4
  94. // this._y.setDate(this._y.getDate() - 1);
  95. return this._pst;
  96. },
  97. pst: function () { // yyyy-mm-dd tt:mm PST
  98. return (this._pst || this.tick()).toISOString().substring(0,16).replace('T',' ')+' PST';
  99. },
  100. explore: function () { // yyyy-mm-dd tt:mm Explore beat!
  101. if (this._explore===null) {
  102. this.tick();
  103. }
  104. return this._explore.toISOString().substring(0,16).replace('T',' ')+' Explore beat!';
  105. }
  106. },
  107. initUserId: function () {
  108. if (window.auth && window.auth.user && window.auth.user.nsid) {
  109. fixr.context.userId = window.auth.user.nsid;
  110. return true;
  111. }
  112. return false;
  113. },
  114. initPhotographerName: function () {
  115. if (fixr.content.querySelector('a.owner-name')) {
  116. fixr.context.photographerName = fixr.content.querySelector('a.owner-name').textContent;
  117. return true;
  118. }
  119. return false;
  120. },
  121. initPhotographerId: function () { // photographer/attribution id
  122. var elem;
  123. if (document.querySelector('div.photostream-page-view')) {
  124. // photostream
  125. elem = document.querySelector('div.photostream-page-view div.fluid-photostream-coverphoto-view div.avatar.person');
  126. } else if (document.querySelector('div.photo-page-scrappy-view')) {
  127. // photopage
  128. elem = document.querySelector('div.photo-page-scrappy-view div.sub-photo-view div.avatar.person');
  129. } else if (document.querySelector('div.photo-page-lightbox-scrappy-view')) {
  130. // photopage lightbox
  131. elem = document.querySelector('div.photo-page-lightbox-scrappy-view div.photo-well-view div.photo-attribution div.avatar.person');
  132. } else if (document.querySelector('div.album-page-view')) {
  133. // album page
  134. elem = document.querySelector('div.album-page-view div.album-container div.album-header-view div.album-attribution div.avatar.person');
  135. } else {
  136. log('we do not look for photographerId on this page');
  137. return true;
  138. }
  139. // album oversigt
  140. // etc...
  141. // men minus f.eks. favorites oversigt!
  142. if (!elem) {
  143. log('fixr.initPhotographerId() - Attribution elem NOT found - returning false');
  144. return false;
  145. } // re-run a little later???
  146. log('fixr.initPhotographerId() - Attribution elem found');
  147. // (div.avatar.person).style.backgroundImage=url(https://s.yimg.com/pw/images/buddyicon07_r.png#44504567@N00)
  148. // .style.backgroundImage=url(//c4.staticflickr.com/8/7355/buddyicons/10259776@N00_r.jpg?1372021232#10259776@N00)
  149. if (elem.style.backgroundImage) {
  150. log('fixr.initPhotographerId() - elem has style.backgroundImage "' + elem.style.backgroundImage + '", now looking for the attribution id...');
  151. var pattern = /url[^#\?]+(\/\/[^#\?]+\.com\/[^#\?]+\/buddyicon[^\?\#]+)[^#]*#(\d+\@N\d{2})/i;
  152. // var pattern = /\/buddyicons\/(\d+\@N\d{2})\D+/i;
  153. var result = elem.style.backgroundImage.match(pattern);
  154. if (result) {
  155. log('fixr.initPhotographerId() - Attribution pattern match found: ' + result[0]);
  156. log('fixr.initPhotographerId() - the attribution icon is ' + result[1]);
  157. log('fixr.initPhotographerId() - the attribution id is ' + result[2]);
  158. fixr.context.photographerIcon = result[1];
  159. fixr.context.photographerId = result[2];
  160. } else {
  161. log('fixr.initPhotographerId() - attribution pattern match not found');
  162. return false;
  163. }
  164. } else {
  165. log('fixr.initPhotographerId() - elem.style.backgroundImage not found');
  166. return false;
  167. }
  168. log('fixr.initPhotographerId() - returning true...');
  169. return true;
  170. },
  171. initPhotoId: function () { // Photo Id
  172. // *flickr.com/photos/user/PId/*
  173. var pattern = /^\/photos\/([^\/]+)\/([\d]{2,})/i;
  174. var result = window.location.pathname.match(pattern);
  175. if (result) {
  176. log('url match med photoId=' + result[2]);
  177. log('url match med photographerAlias=' + result[1]);
  178. fixr.context.photoId = result[2];
  179. fixr.context.photographerAlias = result[1];
  180. return true;
  181. } else {
  182. log('*** initPhotoId() returnerer false! reg-pattern fandt ikke match i pathname='+window.location.pathname);
  183. }
  184. return false;
  185. },
  186. initAlbumId: function () {
  187. // *flickr.com/photos/user/albums/AId/*
  188. // *flickr.com/photos/user/sets/AId/*
  189. var pattern = /^\/photos\/([^\/]+)\/albums\/([\d]{2,})/i;
  190. var result = window.location.pathname.match(pattern);
  191. if (!result) {
  192. pattern = /^\/photos\/([^\/]+)\/sets\/([\d]{2,})/i;
  193. result = window.location.pathname.match(pattern);
  194. }
  195. if (result) {
  196. log('url match med albumId=' + result[2]);
  197. log('url match med photographerAlias=' + result[1]);
  198. fixr.context.albumId = result[2];
  199. fixr.context.photographerAlias = result[1];
  200. return true;
  201. }
  202. return false;
  203. },
  204. pageActions: function () {
  205. fixr.clock.tick();
  206. if (fixr.content) {
  207. log('fixr.pageActions() has started with fixr.content defined');
  208. } else {
  209. log('fixr.pageActions() was called, but fixr.content NOT defined');
  210. return;
  211. }
  212. fixr.pageactionsCount++;
  213. for (var p in fixr.context) { // reset context on new page
  214. if (fixr.context.hasOwnProperty(p)) {
  215. fixr.context[p] = '';
  216. }
  217. }
  218. if (fixr.content.querySelector('div.photostream-page-view')) {
  219. if (fixr.content.querySelector('div.slideshow-view')) {
  220. fixr.context.pageType = 'PHOTOSTREAM SLIDESHOW';
  221. } else {
  222. fixr.context.pageType = 'PHOTOSTREAM';
  223. }
  224. } else if (fixr.content.querySelector('div.photo-page-scrappy-view')) {
  225. fixr.context.pageType = 'PHOTOPAGE';
  226. if (fixr.content.querySelector('div.vr-overlay-view') && fixr.content.querySelector('div.vr-overlay-view').hasChildNodes()) {
  227. fixr.context.pageSubType = 'VR'; // maybe I can find a better way to detect, not sure how reliable this is?
  228. } else if (fixr.content.querySelector('div.videoplayer')) {
  229. fixr.context.pageSubType='VIDEO';
  230. } else {
  231. fixr.context.pageSubType='PHOTO';
  232. }
  233. } else if (fixr.content.querySelector('div.photo-page-lightbox-scrappy-view')) {
  234. fixr.context.pageType = 'PHOTOPAGE LIGHTBOX';
  235. if (fixr.content.querySelector('div.vr-overlay-view') && fixr.content.querySelector('div.vr-overlay-view').hasChildNodes()) {
  236. fixr.context.pageSubType='VR'; // VR-mode currently not supported in lightbox?
  237. } else if (fixr.content.querySelector('div.videoplayer')) {
  238. fixr.context.pageSubType='VIDEO';
  239. } else {
  240. fixr.context.pageSubType='PHOTO';
  241. }
  242. } else if (fixr.content.querySelector('div.albums-list-page-view')) {
  243. fixr.context.pageType = 'ALBUMSLIST';
  244. } else if (fixr.content.querySelector('div.album-page-view')) {
  245. if (fixr.content.querySelector('div.slideshow-view')) {
  246. fixr.context.pageType = 'ALBUM SLIDESHOW';
  247. } else {
  248. fixr.context.pageType = 'ALBUM';
  249. }
  250. } else if (fixr.content.querySelector('div.cameraroll-page-view')) {
  251. fixr.context.pageType = 'CAMERAROLL';
  252. } else if (fixr.content.querySelector('div.explore-page-view')) {
  253. fixr.context.pageType = 'EXPLORE';
  254. } else if (fixr.content.querySelector('div.favorites-page-view')) {
  255. if (fixr.content.querySelector('div.slideshow-view')) {
  256. fixr.context.pageType = 'FAVORITES SLIDESHOW';
  257. } else {
  258. fixr.context.pageType = 'FAVORITES';
  259. }
  260. } else if (fixr.content.querySelector('div.groups-list-view')) {
  261. fixr.context.pageType = 'GROUPSLIST'; // personal grouplist
  262. } else if (fixr.content.querySelector('div#activityFeed')) { // id=main i stedet for id=fixr.content
  263. fixr.context.pageType = 'ACTIVITYFEED'; // aka. front page -> UPDATES ?
  264. } else if (fixr.content.querySelector('div#allsizes-photo')) {
  265. fixr.context.pageType = 'SIZES'; // View all sizes - page
  266. } else {
  267. // fixr.context.pageType = ''; // unknown
  268. }
  269.  
  270. log('fixr.context.pageType = ' + fixr.context.pageType);
  271. log('fixr.context.pageSubType = '+fixr.context.pageSubType);
  272. if (fixr.initUserId()) {
  273. log('fixr.initUserId() returned with succes: '+fixr.context.userId);
  274. } else {
  275. log('fixr.initUserId() returned FALSE!');
  276. }
  277. if (fixr.initPhotographerId()) {
  278. log('fixr.initPhotographerId() returned true in first try...');
  279. } else {
  280. log('fixr.initPhotographerId() returned false - re-running delayed...');
  281. setTimeout(fixr.initPhotographerId, 1800);
  282. }
  283. if (fixr.initPhotoId()) {
  284. log('fixr.initPhotoId() returned true in first try...');
  285. } else {
  286. log('fixr.initPhotoId() returned false - re-running delayed...');
  287. setTimeout(fixr.initPhotoId, 1500);
  288. }
  289. if (fixr.initAlbumId()) {
  290. log('fixr.initAlbumId() returned true in first try...');
  291. }
  292. if (fixr.initPhotographerName()) {
  293. log('fixr.initPhotographerName() returned true in first try...');
  294. } else {
  295. setTimeout(fixr.initPhotographerName, 1500);
  296. }
  297.  
  298. // Now run the page handlers....
  299. if (fixr.onPageHandlers && fixr.onPageHandlers !== null && fixr.onPageHandlers.length) {
  300. log('We have ' + fixr.onPageHandlers.length + ' onPage handlers starting now...');
  301. for (var f = 0; f < fixr.onPageHandlers.length; f++) {
  302. fixr.onPageHandlers[f]();
  303. }
  304. }
  305. },
  306. setupContent: function () {
  307. if (document.getElementById('content')) {
  308. fixr.content = document.getElementById('content');
  309. } else if (document.getElementById('main')) {
  310. fixr.content = document.getElementById('main'); // frontpage
  311. }
  312. if (fixr.content && fixr.content.id) {
  313. log('fixr.content.id = ' + fixr.content.id);
  314. } else {
  315. log('content or main element NOT found!');
  316. }
  317. },
  318. runPageActionsIfMissed: function () {
  319. if (fixr.pageactionsCount === 0) {
  320. log('Vi kører fixr.pageActions() på bagkant via onload...');
  321. fixr.setupContent();
  322. if (fixr.content === null) {
  323. log('Vi kan IKKE køre fixr.pageActions() på bagkant, da fixr.content ikke er defineret');
  324. return;
  325. }
  326. fixr.pageActions();
  327. } else {
  328. log('ej nødvendigt at køre fixr.pageActions() på bagkant i dette tilfælde...');
  329. }
  330. },
  331. runDelayedPageActionsIfMissed: function () {
  332. setTimeout(fixr.runPageActionsIfMissed, 2000);
  333. },
  334. resizeActions: function () {
  335. if (fixr.onResizeHandlers && fixr.onResizeHandlers !== null && fixr.onResizeHandlers.length) {
  336. for (var f = 0; f < fixr.onResizeHandlers.length; f++) {
  337. fixr.onResizeHandlers[f]();
  338. }
  339. }
  340. },
  341. resizeActionsDelayed: function () { // or "preburner"
  342. clearTimeout(fixr.timerResizeActionDelayed);
  343. fixr.timerResizeActionDelayed = setTimeout(fixr.resizeActions, 250);
  344. },
  345. focusActions: function () {
  346. if (fixr.onFocusHandlers && fixr.onFocusHandlers !== null && fixr.onFocusHandlers.length) {
  347. for (var f = 0; f < fixr.onFocusHandlers.length; f++) {
  348. fixr.onFocusHandlers[f]();
  349. }
  350. }
  351. },
  352. setupObserver: function () {
  353. log('fixr.setupObserve INITIALIZATION START');
  354. fixr.setupContent();
  355. if (fixr.content === null) {
  356. log('Init fails because content not defined');
  357. return;
  358. }
  359. // create an observer instance
  360. var observer = new MutationObserver(function (mutations) {
  361. log('NEW PAGE MUTATION!');
  362. //mutations.forEach(function(mutation) {
  363. // log('MO: '+mutation.type); // might check for specific type of "mutations" (MutationRecord)
  364. //});
  365. fixr.pageActions();
  366. }); // MutationObserver end
  367. // configuration of the observer:
  368. var config = {attributes: false, childList: true, subtree: false, characterData: false};
  369. observer.observe(fixr.content, config);
  370. log('fixr.setupObserve INITIALIZATION DONE');
  371. },
  372. init: function (onPageHandlerArray, onResizeHandlerArray, onFocusHandlerArray) {
  373. // General page-change observer setup:
  374. window.addEventListener('DOMContentLoaded', fixr.setupObserver, false); // Page on DOMContentLoaded
  375. window.addEventListener('load', fixr.runDelayedPageActionsIfMissed, false); // Page on load
  376. window.addEventListener('resize', fixr.resizeActionsDelayed, false); // også på resize
  377. window.addEventListener('focus', fixr.focusActions, false);
  378. if (onPageHandlerArray && onPageHandlerArray !== null && onPageHandlerArray.length) {
  379. fixr.onPageHandlers = onPageHandlerArray; // Replace by adding with a one-by-one by "helper" for flexibility?
  380. }
  381. if (onResizeHandlerArray && onResizeHandlerArray !== null && onResizeHandlerArray.length) {
  382. fixr.onResizeHandlers = onResizeHandlerArray; // Replace by adding with a one-by-one by "helper" for flexibility?
  383. }
  384. if (onFocusHandlerArray && onFocusHandlerArray !== null && onFocusHandlerArray.length) {
  385. fixr.onFocusHandlers = onFocusHandlerArray;
  386. }
  387. }
  388. };
  389. // FIXR page-tracker end
  390.  
  391.  
  392. var _timerMaplink = 0;
  393. function updateMapLink() {
  394. if (fixr.context.pageType !== 'PHOTOPAGE') {
  395. return; // exit if not photopage
  396. }
  397. log('updateMapLink() running at readystate=' + document.readyState + ' and with photoId=' + fixr.context.photoId);
  398. if (fixr.context.photoId) {
  399. var maplink = fixr.content.querySelector('a.static-maps');
  400. if (maplink) {
  401. if (maplink.getAttribute('href') && (maplink.getAttribute('href').indexOf('map/?') > 0) && (maplink.getAttribute('href').indexOf('&photo=') === -1)) {
  402. maplink.setAttribute('href', maplink.getAttribute('href') + '&photo=' + fixr.context.photoId);
  403. log('link is updated by updateMapLink() at readystate=' + document.readyState);
  404. try {
  405. var lat = maplink.getAttribute('href').match(/Lat=(\-?[\d\.]+)/i)[1];
  406. var lon = maplink.getAttribute('href').match(/Lon=(\-?[\d\.]+)/i)[1];
  407. fixr.content.querySelector('li.c-charm-item-location').insertAdjacentHTML('beforeend', '<div class="location-data-container"><a href="https://www.google.com/maps/search/?api=1&amp;query=' + lat + ',' + lon + '">Open location on Google Maps</a></div>');
  408. }
  409. catch (e) {
  410. log('Failed creating Google Maps link: ' + e);
  411. }
  412. } else {
  413. log('link NOT updated by updateMapLink(). Invalid element or already updated. readystate=' + document.readyState);
  414. }
  415. } else {
  416. log('NO maplink found at readystate=' + document.readyState + '. Re-try later?');
  417. }
  418. } else {
  419. log('NO photoId found at readystate=' + document.readyState);
  420. }
  421. }
  422. function updateMapLinkDelayed() {
  423. if (fixr.context.pageType !== 'PHOTOPAGE') {
  424. return;
  425. } // exit if not photopage
  426. log('updateMapLinkDelayed() running... with pageType=' + fixr.context.pageType);
  427. //clearTimeout(_timerMaplink);
  428. _timerMaplink = setTimeout(updateMapLink, 2000); // make maplink work better on photopage
  429. }
  430.  
  431. var album = { // cache to avoid repeating requests
  432. albumId: '',
  433. commentCount: 0
  434. };
  435. function updateAlbumCommentCount() {
  436. var _reqAlbumComments = null;
  437. if (window.XMLHttpRequest) {
  438. _reqAlbumComments = new XMLHttpRequest();
  439. if (typeof _reqAlbumComments.overrideMimeType !== 'undefined') {
  440. _reqAlbumComments.overrideMimeType('text/html');
  441. }
  442.  
  443. _reqAlbumComments.onreadystatechange = function () {
  444. if (_reqAlbumComments.readyState === 4 && _reqAlbumComments.status === 200) {
  445. log('_reqAlbumComments returned status=' + _reqAlbumComments.status);
  446. var doc = document.implementation.createHTMLDocument("sizeDoc");
  447. doc.documentElement.innerHTML = _reqAlbumComments.responseText;
  448. album.albumId = fixr.context.albumId;
  449. album.commentCount = -1;
  450. var e = doc.body.querySelectorAll('span.LinksNew b.Here');
  451. if (e && e.length === 1) {
  452. var n = parseInt(e[0].textContent, 10);
  453. if (isNaN(n)) {
  454. album.commentCount = 0;
  455. } else {
  456. album.commentCount = n;
  457. }
  458. } else {
  459. album.commentCount = -1;
  460. log('b.Here??? ');
  461. }
  462. if (document.getElementById('albumCommentCount')) {
  463. if (album.commentCount === -1) {
  464. document.getElementById('albumCommentCount').innerHTML = '?';
  465. } else {
  466. document.getElementById('albumCommentCount').innerHTML = '' + album.commentCount;
  467. }
  468. } else {
  469. log('albumCommentCount element not found');
  470. }
  471. } else {
  472. // wait for the call to complete
  473. }
  474. };
  475.  
  476. if (fixr.context.albumId === album.albumId && fixr.context.albumId !== '' && album.commentCount !== -1) {
  477. log('Usinging CACHED album count!...');
  478. document.getElementById('albumCommentCount').innerHTML = '' + album.commentCount;
  479. } else if (fixr.context.albumId !== '') {
  480. var url = 'https://www.flickr.com/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/albums/' + fixr.context.albumId + '/comments/';
  481. _reqAlbumComments.open('GET', url, true);
  482. _reqAlbumComments.send(null);
  483. } else {
  484. log('albumId not initialized');
  485. }
  486. } else {
  487. log('understøtter ikke XMLHttpRequest');
  488. }
  489. }
  490.  
  491. var albums = { // cache albums to avoid repeating requests
  492. ownerId: '',
  493. html: '',
  494. count: 0
  495. };
  496. function getAlbumlist() {
  497. var _reqAlbumlist = null;
  498. if (window.XMLHttpRequest) {
  499. _reqAlbumlist = new XMLHttpRequest();
  500. if (typeof _reqAlbumlist.overrideMimeType !== 'undefined') {
  501. _reqAlbumlist.overrideMimeType('text/html');
  502. }
  503.  
  504. _reqAlbumlist.onreadystatechange = function () {
  505. if (_reqAlbumlist.readyState === 4 && _reqAlbumlist.status === 200) {
  506. log('_reqAlbumlist returned status=' + _reqAlbumlist.status); // + ', \ntext:\n' + _reqAlbumlist.responseText);
  507. var doc = document.implementation.createHTMLDocument("sizeDoc");
  508. doc.documentElement.innerHTML = _reqAlbumlist.responseText;
  509.  
  510. albums.ownerId = fixr.context.photographerId;
  511. albums.html = '';
  512. albums.count = 0;
  513. var e = doc.body.querySelectorAll('div.photo-list-album-view');
  514. var imgPattern = /url\([\'\"]*([^\)\'\"]+)(\.[jpgtifn]{3,4})[\'\"]*\)/i;
  515. if (e && e.length > 0) {
  516. albums.count = e.length;
  517. for (var i = 0; i < Math.min(10, e.length); i++) {
  518. var imgUrl = '';
  519. //log(e[i].outerHTML);
  520. //log('A7 (' + i + ') : ' + e[i].style.backgroundImage);
  521. // var result = e[i].style.backgroundImage.match(imgPattern); // strangely not working in Chrome
  522. var result = (e[i].outerHTML).match(imgPattern); // quick work-around for above (works for now)
  523. if (result) {
  524. // imgUrl = result[1].replace(/_[a-z]$/, '') + '_s' + result[2];
  525. imgUrl = result[1].replace(/_[a-z]$/, '') + '_q' + result[2];
  526. log('imgUrl=' + imgUrl);
  527. } else {
  528. log('No match on imgPattern');
  529. }
  530. var a = e[i].querySelector('a[href][title]'); // sub-element
  531. if (a && a !== null) {
  532. log('Album title: ' + a.title);
  533. log('Album url: ' + a.getAttribute('href'));
  534. albums.html += '<div><a href="//www.flickr.com' + a.getAttribute('href') + '"><img src="' + imgUrl + '" class="asquare" alt="" /><div style="margin:0 0 .8em 0">' + a.title + '</div></a></div>';
  535. } else {
  536. log('a element not found?');
  537. }
  538. }
  539. } else if (e) {
  540. if (doc.body.querySelector('h3')) {
  541. albums.html = '<div style="margin:0 0 .8em 0">'+doc.body.querySelector('h3').textContent+'</div>';
  542. }
  543. } else {
  544. log('(e UNdefined) Problem reading albums or no albums??? : ' + _reqAlbumlist.responseText );
  545. }
  546. if (document.getElementById('albumTeaser')) {
  547. document.getElementById('albumTeaser').innerHTML = '<div style="margin:0 0 .8em 0">Albums</div>' + albums.html + '<div><i><a href="/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/albums/">' + (albums.count > 10 ? 'More albums...' : (albums.count === 0 ? 'No albums found...' : '')) + '</a></i></div>';
  548. } else {
  549. log('albumTeaser NOT FOUND!?!');
  550. }
  551. } else {
  552. // wait for the call to complete
  553. }
  554. };
  555.  
  556. if (fixr.context.photographerId === albums.ownerId && fixr.context.photographerId !== '') {
  557. log('Using CACHED albumlist!...');
  558. document.getElementById('albumTeaser').innerHTML = '<div style="margin:0 0 .8em 0">Albums</div>' + albums.html + '<div><i><a href="/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/albums/">' + (albums.count > 10 ? 'More albums...' : (albums.count === 0 ? 'No albums found...' : '')) + '</a></i></div>';
  559. } else if (fixr.context.photographerId) {
  560. var url = 'https://www.flickr.com/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/albums';
  561. _reqAlbumlist.open('GET', url, true);
  562. _reqAlbumlist.send(null);
  563. } else {
  564. log('Attribution user (photographer) not found');
  565. }
  566. } else {
  567. log('understøtter ikke XMLHttpRequest');
  568. }
  569. }
  570. function albumTeaser() {
  571. if (fixr.context.pageType !== 'PHOTOSTREAM') {
  572. return; // exit if not photostream
  573. }
  574. log('albumTeaser() running');
  575. var dpc = document.querySelector('div.photolist-container');
  576. if (!dpc) {
  577. return;
  578. }
  579. // to-do: check om personlig photostream?
  580. // to-do: check padding-right er mindst 130px?
  581. log('AlbumTeaser found div.photolist-container');
  582. if (!document.getElementById('albumTeaser')) {
  583. dpc.style.position = "relative";
  584. dpc.insertAdjacentHTML('afterbegin', '<div id="albumTeaser" style="border:none;margin:0;padding:0;position:absolute;top:0;right:10px;width:100px"></div>');
  585. }
  586. if (document.getElementById('albumTeaser')) {
  587. getAlbumlist(); // også check på fixr.context.photographerId ?
  588. }
  589. }
  590. var _timerAlbumTeaserDelayed;
  591. function albumTeaserDelayed() {
  592. if (fixr.context.pageType !== 'PHOTOSTREAM') {
  593. return; // exit if not photostream
  594. }
  595. log('albumTeaserDelayed() running...');
  596. clearTimeout(_timerAlbumTeaserDelayed);
  597. _timerAlbumTeaserDelayed = setTimeout(albumTeaser, 1500);
  598. }
  599.  
  600. function exploreCalendar() {
  601. if (fixr.context.pageType !== 'EXPLORE') {
  602. return; // exit if not explore/interestingness
  603. }
  604. log('exploreCalendar() running');
  605. var dtr = document.querySelector('div.title-row');
  606. if (!dtr) {
  607. return;
  608. }
  609. log('exploreCalendar found div.photo-list-view');
  610. if (!document.getElementById('exploreCalendar')) {
  611. dtr.style.position = "relative";
  612. var exploreMonth = fixr.clock.explore().substring(0,7).replace('-','/');
  613. dtr.insertAdjacentHTML('afterbegin', '<div id="exploreCalendar" style="border:none;margin:0;padding:0;position:absolute;top:38px;right:-120px;width:100px"><div style="margin:0 0 .8em 0">Explore more...</div><a title="Explore Calendar" href="https://www.flickr.com/explore/interesting/' + exploreMonth + '/"><img src="https://c2.staticflickr.com/2/1701/24895062996_78719dec15_o.jpg" class="asquare" style="width:75px;height:59px" alt="" /><div style="margin:0 0 .8em 0">Explore Calendar</div></a><a title="If you are an adventurer and want to explore something different than everybody else..." href="https://www.flickr.com/search/?text=&view_all=1&media=photos&content_type=1&dimension_search_mode=min&height=640&width=640&safe_search=2&sort=date-posted-desc&min_upload_date='+(Math.floor(Date.now()/1000)-7200)+'"><img src="https://c2.staticflickr.com/2/1617/25534100345_b4a3fe78f1_o.jpg" class="asquare" style="width:75px;height:59px" alt="" /><div style="margin:0 0 .8em 0">Fresh uploads</div></a></div>');
  614. log('San Francisco UTC-8: ' + fixr.clock.pst());
  615. log('Explore Beat (Yesterday, UTC-4): ' + fixr.clock.explore());
  616. if (document.querySelector('div.title-row h3')) {
  617. document.querySelector('div.title-row h3').title = fixr.clock.explore() + ' - ' + fixr.clock.pst();
  618. }
  619. }
  620. }
  621. var _timerExploreCalendarDelayed;
  622. function exploreCalendarDelayed() {
  623. if (fixr.context.pageType !== 'EXPLORE') {
  624. return; // exit if not explore/interestingness
  625. }
  626. log('albumTeaserDelayed() running...');
  627. clearTimeout(_timerExploreCalendarDelayed);
  628. _timerExploreCalendarDelayed = setTimeout(exploreCalendar, 1500);
  629. }
  630.  
  631. function ctrlClick(e) {
  632. var elem, evt = e ? e : event;
  633. if (evt.srcElement) elem = evt.srcElement;
  634. else if (evt.target) elem = evt.target;
  635. if (evt.ctrlKey) {
  636. log('Ctrl clicked. Further scripted click-event handling canceled. Allow the default ctrl-click handling in my browser.');
  637. evt.stopPropagation();
  638. }
  639. }
  640. function ctrlClicking() {
  641. // if (navigator.userAgent.search(/gecko\/20/i)>-1) { // Firefox/gecko-only ctrl click tab fix
  642. var plv = document.querySelectorAll('div.photo-list-view');
  643. for (var i = 0; i < plv.length; i++) {
  644. log('ctrlClicking(): plv['+i+'] found!');
  645. // Allow me to open tabs in background by ctrl-click in Firefox:
  646. plv[i].parentNode.addEventListener('click', ctrlClick, true);
  647. }
  648. // }
  649. }
  650. var _timerCtrlClicking;
  651. function ctrlClickingDelayed() {
  652. log('ctrlClickingDelayed() running...');
  653. clearTimeout(_timerCtrlClicking);
  654. _timerCtrlClicking = setTimeout(ctrlClicking, 1500);
  655. }
  656.  
  657. var scaler = {
  658. photoId: '',
  659. photoOrientation: '',
  660. mf: null, // document.querySelector('img.main-photo') for (re-)re-scale
  661. lrf: null, // document.querySelector('img.low-res-photo') for (re-)re-scale
  662. maxSizeUrl: '',
  663. orgUrl: '',
  664. hasOriginal: false,
  665. scaleToWidth: 0,
  666. scaleToHeight: 0,
  667. postAction: function() {
  668. log('scaler.postAction'); // dummy-function to be replaced
  669. },
  670. run: function () {
  671. if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
  672. return; // exit if not photopage or lightbox
  673. }
  674. if (fixr.context.pageSubType !== 'PHOTO') {
  675. log('Exiting scaler because fixr.context.pageSubType='+fixr.context.pageSubType);
  676. return; // exit if subtype VR or VIDEO
  677. }
  678. log('scaler.run() running...');
  679. // var that = this;
  680. var unscale = function () {
  681. log('Unscale button clicked!...');
  682. // sizes (and position?) from div.photo-notes-scrappy-view
  683. var dims = document.querySelector('div.photo-notes-scrappy-view');
  684. scaler.mf.width = parseInt(dims.style.width,10);
  685. scaler.mf.height = parseInt(dims.style.height,10);
  686. // unscale/rest, and...
  687. var trash = document.querySelector('div.unscaleBtn');
  688. if (trash && trash.parentNode) {
  689. trash.removeEventListener('click',unscale);
  690. trash.parentNode.removeChild(trash);
  691. }
  692. };
  693. var addUnscaleBtn = function() {
  694. if (fixr.context.pageType !== 'PHOTOPAGE') {
  695. return; // exit if not photopage
  696. }
  697. /*
  698. if (!notes.photo.allowNotes) {
  699. log('Notes not supported on this photo');
  700. return;
  701. }
  702. */
  703. if (!document.querySelector('.show-add-tags')) {
  704. log('Adding notes (and tagging) apparently not allowed/possible'); // photographer doesn't allow, user not logged in, or...?
  705. // return;
  706. }
  707. log('scaler.addUnscaleBtn() running');
  708. var panel = document.querySelector('div.photo-well-media-scrappy-view');
  709. var notesview = document.querySelector('div.photo-notes-scrappy-view');
  710. if (panel && !panel.querySelector('div.unscaleBtn')) {
  711. log('scaler.addUnscaleBtn: adding option to div.height-controller');
  712. panel.insertAdjacentHTML('afterbegin', '<div class="unscaleBtn" style="position:absolute;right:20px;top:15px;font-size:16px;margin-right:16px;color:#FFF;z-index:3000"><img id="unscaleBtnId" src="https://farm9.staticflickr.com/8566/28150041264_a8b591c2a6_o.png" alt="Un-scale" title="This photo has been up-scaled by Stig\'s Flickr Fixr. Click here to be sure image-size is aligned with notes area" /></div>');
  713. log ('scaler.addUnscaleBtn: adding click event listner on div.unscaleBtn');
  714. panel.querySelector('div.unscaleBtn').addEventListener('click',unscale, false);
  715. } else {
  716. log('scaler.addUnscaleBtn: div.height-controller not found OR unscaleBtn already defined');
  717. }
  718. var unscaleBtnElem = document.getElementById('unscaleBtnId');
  719. if (unscaleBtnElem && parseInt(notesview.style.width,10)) {
  720. if (scaler.mf.width === parseInt(notesview.style.width, 10)) { // Green icon
  721. unscaleBtnElem.title = "This photo has been up-scaled by Stig\'s Flickr Fixr. It appears Flickr was able to align the notes-area with scaled photo. You should be able to view and create notes correctly scaled and aligned on the upscaled photo.";
  722. unscaleBtnElem.src = 'https://farm9.staticflickr.com/8879/28767704565_17560d791f_o.png';
  723. } else { // Orange icon/button
  724. unscaleBtnElem.title = "This photo has been up-scaled by Stig\'s Flickr Fixr. It appears the notes-area is UNALIGNED with the upscaled image. Please click here to align image-size to the notes-area before studying or creating notes on this image.";
  725. unscaleBtnElem.src = 'https://farm9.staticflickr.com/8687/28690535161_19b3a34578_o.png';
  726. }
  727. }
  728. };
  729. var scale = function () { // Do the actual scaling
  730. if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
  731. return;
  732. } // exit if not photopage or lightbox
  733. log('scaler.scale() running... (scale to:' + scaler.scaleToWidth + 'x' + scaler.scaleToHeight + ')');
  734. scaler.mf = document.querySelector('img.main-photo'); // for en sikkerheds skyld
  735. scaler.lrf = document.querySelector('img.low-res-photo'); // for en sikkerheds skyld
  736. if (scaler.mf && scaler.mf !== null && scaler.lrf && scaler.lrf !== null && scaler.scaleToWidth > 0 && scaler.scaleToHeight > 0) {
  737. log('[scaler] do scaling WORK. Height from ' + scaler.mf.height + ' to ' + scaler.scaleToHeight);
  738. scaler.mf.height = scaler.scaleToHeight;
  739. log('[scaler] do scaling WORK. Width from ' + scaler.mf.width + ' to ' + scaler.scaleToWidth);
  740. scaler.mf.width = scaler.scaleToWidth;
  741. scaler.lrf.height = scaler.mf.height;
  742. scaler.lrf.width = scaler.mf.width;
  743. }
  744. addUnscaleBtn();
  745. scaler.postAction('notes on scaled photo');
  746. };
  747. var replace = function () { // and (re-)scale?
  748. if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
  749. return; // exit if not photopage or lightbox
  750. }
  751. log('[scaler] scaler.run.replace() running...');
  752. scaler.mf = document.querySelector('img.main-photo'); // for en sikkerheds skyld
  753. if (scaler.mf && scaler.mf !== null && scaler.maxSizeUrl !== '') {
  754. if (scaler.mf.height>=640 || scaler.mf.width>=640) { // dirty hack to work-around a bug
  755. scaler.mf.src = scaler.maxSizeUrl; // Replace! only if original (maxSizeUrl should be orgUrl)
  756. } else {
  757. log('[scaler] Second thoughts. Do not replace this photo with original because unlikely needed here (bug work-around for small screens).');
  758. }
  759. scale();
  760. }
  761. };
  762. var getSizes = function () {
  763. log('[scaler] scaler.run.getSizes() running...');
  764. var _reqAllSizes = null;
  765. if (window.XMLHttpRequest) {
  766. _reqAllSizes = new XMLHttpRequest();
  767. if (typeof _reqAllSizes.overrideMimeType !== 'undefined') {
  768. _reqAllSizes.overrideMimeType('text/html');
  769. }
  770. _reqAllSizes.onreadystatechange = function () {
  771. if (_reqAllSizes.readyState === 4 && _reqAllSizes.status === 200) {
  772. log('[scaler] _reqAllSizes returned status=' + _reqAllSizes.status); // + ', \ntext:\n' + _reqAllSizes.responseText);
  773. var doc = document.implementation.createHTMLDocument("sizeDoc");
  774. doc.documentElement.innerHTML = _reqAllSizes.responseText;
  775.  
  776. var sizelist = doc.body.querySelectorAll('ol.sizes-list li ol li');
  777. var largest = null;
  778. var largesttext = '';
  779. while(!largest && sizelist.length>0) {
  780. if (sizelist[sizelist.length-1].textContent.replace(/\s+/g,'')==='') {
  781. sizelist.pop(); // remove last
  782. } else {
  783. log('[scaler] Found LARGEST size: '+sizelist[sizelist.length-1].textContent.replace(/\s+/g,''));
  784. largest = sizelist[sizelist.length-1];
  785. largesttext = largest.textContent.replace(/\s+/g,'');
  786. }
  787. }
  788. if (largest.querySelector('a')) {
  789. // list has link to _PAGE_ for showing largest image, thus it cannot be the original we already see ON the page!
  790. log ('[scaler] Sizes-page/o has link to _PAGE_ for showing largest image, thus it cannot be the largest/original we already see ON the page!');
  791. scaler.orgUrl = '';
  792. scaler.maxSizeUrl = '';
  793. scaler.hasOriginal = false;
  794. } else if (doc.body.querySelector('div#allsizes-photo>img')) {
  795. scaler.orgUrl = doc.body.querySelector('div#allsizes-photo>img').src;
  796. scaler.hasOriginal = true;
  797. scaler.maxSizeUrl = doc.body.querySelector('div#allsizes-photo>img').src;
  798. log('[scaler] Largest/original image: ' + scaler.maxSizeUrl);
  799. } else {
  800. log('[scaler] UNEXPECTED situation. Assuming NO original available');
  801. scaler.orgUrl = '';
  802. scaler.maxSizeUrl = '';
  803. scaler.hasOriginal = false;
  804. }
  805. var r = /\((\d+)x(\d+)\)$/;
  806. var res = largesttext.match(r);
  807. if (res !== null) {
  808. if (scaler.photoOrientation === 'h' && parseInt(res[1],10)<parseInt(res[2],10)) {
  809. log('[scaler] Photo has been rotated from vertical to horizontal - Should NOT use the original here!');
  810. scaler.orgUrl = '';
  811. scaler.maxSizeUrl = '';
  812. scaler.hasOriginal = false;
  813. } else if (scaler.photoOrientation === 'v' && parseInt(res[1],10)>parseInt(res[2],10)) {
  814. log('[scaler] Photo has been rotated from horizontal to vertical - Should NOT use the original here!');
  815. scaler.orgUrl = '';
  816. scaler.maxSizeUrl = '';
  817. scaler.hasOriginal = false;
  818. }
  819. } else {
  820. log('[scaler] No match???');
  821. }
  822. if (scaler.hasOriginal) {
  823. log('[scaler] Scale and replace using Original found from XMLHttpRequest');
  824. // do some caching here?...
  825. replace();
  826. }
  827. } else {
  828. // wait for the call to complete
  829. }
  830. };
  831. var url = 'https://www.flickr.com/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/' + fixr.context.photoId + '/sizes/o';
  832. _reqAllSizes.open('GET', url, true);
  833. _reqAllSizes.send(null);
  834. } else {
  835. log('[scaler] understøtter ikke XMLHttpRequest');
  836. }
  837. };
  838. if (scaler.photoId === '') {
  839. scaler.photoId = fixr.context.photoId;
  840. } else if (scaler.photoId !== fixr.context.photoId) {
  841. scaler.photoId = fixr.context.photoId;
  842. scaler.photoOrientation = '';
  843. scaler.mf = null;
  844. scaler.lrf = null;
  845. scaler.maxSizeUrl = '';
  846. scaler.orgUrl = '';
  847. scaler.hasOriginal = false;
  848. scaler.scaleToWidth = 0;
  849. scaler.scaleToHeight = 0;
  850. }
  851. var roomHeight = 0;
  852. var roomWidth = 0;
  853. var roomPaddingHeight = 0;
  854. var roomPaddingWidth = 0;
  855.  
  856. // Fortsæt kun hvis PhotoId!!!?
  857.  
  858. var dpev = document.querySelector('div.photo-engagement-view');
  859. var pwv = document.querySelector('div.photo-well-view');
  860. if (pwv) {
  861. log('[scaler] height-controller: height=' + pwv.clientHeight + ' (padding=70?), width=' + pwv.clientWidth + ' (padding=80?).'); // hc.style.padding: 20px 40px 50px
  862. if (roomHeight === 0) {
  863. roomHeight = pwv.clientHeight;
  864. }
  865. if (roomWidth === 0) {
  866. roomWidth = pwv.clientWidth;
  867. }
  868. roomPaddingHeight += (parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-bottom'), 10));
  869. roomPaddingWidth += (parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-right'), 10));
  870. }
  871. var hc = document.querySelector('div.height-controller');
  872. if (hc) {
  873. log('[scaler] height-controller: height=' + hc.clientHeight + ' (padding=70?), width=' + hc.clientWidth + ' (padding=80?).'); // hc.style.padding: 20px 40px 50px
  874. if (roomHeight === 0) {
  875. roomHeight = hc.clientHeight;
  876. }
  877. if (roomWidth === 0) {
  878. roomWidth = hc.clientWidth;
  879. }
  880. roomPaddingHeight += (parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-bottom'), 10));
  881. roomPaddingWidth += (parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-right'), 10));
  882. }
  883. var pwmsv = document.querySelector('div.photo-well-media-scrappy-view');
  884. if (pwmsv) {
  885. log('[scaler] div.photo-well-media-scrappy-view: height=' + pwmsv.clientHeight + ' (padding=70?), width=' + pwmsv.clientWidth + ' (padding=80?).'); // pwmsv.style.padding: 20px 40px 50px
  886. if (roomHeight === 0) {
  887. roomHeight = pwmsv.clientHeight;
  888. }
  889. if (roomWidth === 0) {
  890. roomWidth = pwmsv.clientWidth;
  891. }
  892. roomPaddingHeight += (parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-bottom'), 10));
  893. roomPaddingWidth += (parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-right'), 10));
  894. }
  895. scaler.mf = document.querySelector('img.main-photo');
  896. scaler.lrf = document.querySelector('img.low-res-photo');
  897. // var zl = document.querySelector('img.zoom-large'); // currently not used
  898. // var zs = document.querySelector('img.zoom-small'); // currently not used
  899. if (scaler.mf) {
  900. log('[scaler] main-photo: h=' + scaler.mf.height + ', w=' + scaler.mf.width + '. - Room: (h=' + (roomHeight - roomPaddingHeight) + ',w=' + (roomWidth - roomPaddingWidth) + ')');
  901. if (scaler.mf.width>scaler.mf.height) {
  902. scaler.photoOrientation = 'h'; // horisontal
  903. } else {
  904. scaler.photoOrientation = 'v'; // vertical
  905. }
  906. if (roomPaddingWidth === 0) { // hack
  907. roomPaddingWidth = 120;
  908. log('[scaler] roomPaddingWidth=120 hack used');
  909. }
  910. if (((roomHeight - roomPaddingHeight) > scaler.mf.height + 5) && ((roomWidth - roomPaddingWidth) > scaler.mf.width + 5)) {
  911. log('[scaler] ALLRIGHT - WE ARE READY FOR SCALING!...');
  912. if (((roomHeight - roomPaddingHeight) / scaler.mf.height) < ((roomWidth - roomPaddingWidth) / scaler.mf.width)) {
  913. scaler.scaleToWidth = Math.floor(scaler.mf.width * ((roomHeight - roomPaddingHeight) / scaler.mf.height));
  914. scaler.scaleToHeight = roomHeight - roomPaddingHeight;
  915. } else {
  916. scaler.scaleToHeight = Math.floor(scaler.mf.height * ((roomWidth - roomPaddingWidth) / scaler.mf.width));
  917. scaler.scaleToWidth = roomWidth - roomPaddingWidth;
  918. }
  919. log('[scaler] now calling scale()... [' + scaler.scaleToWidth + ', ' + scaler.scaleToWidth + ']');
  920. scale();
  921. log('[scaler] ...AND CONTINUE LOOKING FOR ORIGINAL...');
  922. if (dpev && scaler.photoOrientation==='h' && document.querySelector('ul.sizes')) { // if (document.querySelector('ul.sizes')) -> PHOTOPAGE in normal mode (if vertical (bigger) risk for rotated, which are better handled by getSizes())
  923. var org = document.querySelector('ul.sizes li.Original a.download-image-size');
  924. if (org) { // quick access når vi bladrer?
  925. scaler.hasOriginal = true; // ??? kun hvis original
  926. scaler.maxSizeUrl = (org.href).replace(/^https\:/i, '').replace(/_d\./i, '.');
  927. // ... do some scaling here?...
  928. replace();
  929. } else {
  930. // vi kan finde original "inline"
  931. var target = document.querySelector('div.photo-engagement-view');
  932. // if(!target) return; ???
  933. if (target) {
  934. var observer = new MutationObserver(function (mutations) {
  935. mutations.forEach(function (mutation) {
  936. log('[scaler] MO size: ' + mutation.type); // might check for specific "mutations"?
  937. });
  938. var org = document.querySelector('ul.sizes li.Original a.download-image-size');
  939. if (org) {
  940. scaler.hasOriginal = true; // ??? kun hvis original
  941. scaler.maxSizeUrl = (org.href).replace(/^https\:/i, '').replace(/_d\./i, '.');
  942. log('[scaler] Original photo found, now replacing');
  943. // ... do some scaling here?...
  944. replace();
  945. } else {
  946. log('[scaler] Original photo not available for download on this photographer. Re-scale just in case...');
  947. scale(); // ???
  948. }
  949. observer.disconnect();
  950. });
  951. // configuration of the observer:
  952. var config = {attributes: false, childList: true, subtree: false, characterData: false};
  953. observer.observe(target, config);
  954. }
  955. }
  956. } else { // PHOTOPAGE (likely) in LIGHTBOX mode
  957. getSizes(); // resize (& replace) from/when size-list
  958. }
  959. } else {
  960. log('[scaler] Scaling NOT relevant');
  961. }
  962. scaler.postAction('notes on unscaled photo'); // look for notes (not (yet?) scaled)
  963. }
  964. }
  965. };
  966.  
  967. function insertStyle() {
  968. if (!document.getElementById('fixrStyle')) {
  969. var style = document.createElement('style');
  970. style.type = 'text/css';
  971. style.id = 'fixrStyle';
  972. style.innerHTML = 'ul.tags-list>li.tag>a.fixrTag,ul.tags-list>li.autotag>a.fixrTag{display:none;} ul.tags-list>li.tag:hover>a.fixrTag,ul.tags-list>li.autotag:hover>a.fixrTag{display:inline;} ' +
  973. '.album-map-icon{background:url("https://c2.staticflickr.com/6/5654/23426346485_334afa6e8f_o_d.png") no-repeat;height:21px;width:24px;top:6px;left:3px} .album-comments-icon{background:url("https://s.yimg.com/uy/build/images/icons-1x-s2fb29ad15b.png") -32px -460px no-repeat;height:21px;width:24px;top:6px;left:3px} ' +
  974. '.unscaleBtn:hover{cursor:pointer} ' +
  975. 'img.asquare {width:75px;height:75px;border:none;margin:0;padding:0;transition:all 0.3s ease} a:hover>img.asquare{transform:scale(1.3)} ' +
  976. '.signup-footer, .signup-footer-view{display:none} ' +
  977. '#topPaginationContainer{width:250px;height:40px;margin:0 auto;position:absolute;top:0;left:0;right:0;border:none} #topPagination{width:720px;margin:0;position:absolute;top:0;left:-235px;text-align:center;z-index:10;display:none;border:none;padding:10px 0 10px 0;overflow:hidden} .album-toolbar-content #topPagination{top:-16px} .group-pool-subheader-view #topPagination{top:-7px} .title-row #topPagination{width:830px;left:-290px;top:-12px} #topPaginationContainer:hover #topPagination{display:block} ';
  978. document.getElementsByTagName('head')[0].appendChild(style);
  979. log('fixrStyle has been ADDED');
  980. } else {
  981. log('fixrStyle was already present');
  982. }
  983. }
  984.  
  985. function topPagination() {
  986. log('topPagination()');
  987. var bottomPagination = document.querySelector('.pagination-view');
  988. if (!bottomPagination) {
  989. bottomPagination = document.querySelector('.explore-pagination');
  990. }
  991. if (bottomPagination && !document.getElementById('topPagination')) {
  992. if (bottomPagination.childElementCount>0) {
  993. var topPagination = bottomPagination.cloneNode(true);
  994. topPagination.id = 'topPagination';
  995. var topPaginationContainer = document.createElement('div');
  996. topPaginationContainer.id = 'topPaginationContainer';
  997. topPaginationContainer.appendChild(topPagination);
  998. var topbar = document.querySelector('.fluid-magic-tools-view');
  999. if (!topbar) topbar = document.querySelector('.album-toolbar-content');
  1000. if (!topbar) topbar = document.querySelector('.group-pool-subheader-view');
  1001. if (!topbar) topbar = document.querySelector('.title-row');
  1002. if (topbar) {
  1003. log('topPagination: root found, inserting container');
  1004. topbar.appendChild(topPaginationContainer);
  1005. }
  1006. }
  1007. }
  1008. }
  1009. function albumExtras() { // links to album's map and comments
  1010. if (fixr.context.pageType !== 'ALBUM') {
  1011. return; // exit if not albumpage
  1012. }
  1013. if (fixr.context.albumId) {
  1014. log('albumsExtra() med album=' + fixr.context.albumId);
  1015. } else {
  1016. log('Exit albumsExtra(). Mangler albumId');
  1017. return;
  1018. }
  1019. var elist = document.querySelector('div.album-engagement-view');
  1020. if (elist && !document.getElementById('albumCommentCount')) {
  1021. // map-link:
  1022. var mapdiv = document.createElement('div');
  1023. mapdiv.className = 'create-book-container';
  1024. mapdiv.title = 'Album on map';
  1025. mapdiv.style.textAlign = 'center';
  1026. mapdiv.innerHTML = '<a href="/photos/' + fixr.context.photographerAlias + '/albums/' + fixr.context.albumId + '/map/" style="font-size:14px;color:#FFF;"><span title="Album on map" class="album-map-icon"></span></a>';
  1027. elist.appendChild(mapdiv);
  1028. // comments-link:
  1029. var comurl = '/photos/' + fixr.context.photographerAlias + '/albums/' + fixr.context.albumId + '/comments/';
  1030. var cmdiv = document.createElement('div');
  1031. cmdiv.className = 'create-book-container';
  1032. cmdiv.title = 'Comments';
  1033. cmdiv.style.textAlign = 'center';
  1034. cmdiv.innerHTML = '<a href="' + comurl + '" style="font-size:14px;color:#FFF;"><span title="Album comments" class="album-comments-icon" id="albumCommentCount"></span></a>';
  1035. elist.appendChild(cmdiv);
  1036. updateAlbumCommentCount();
  1037. }
  1038. }
  1039. function updateTags() {
  1040. if (fixr.context.pageType !== 'PHOTOPAGE') {
  1041. return; // exit if not photopage
  1042. }
  1043. if (fixr.context.photographerAlias==='') {
  1044. fixr.initPhotoId();
  1045. }
  1046. if (fixr.context.photographerId==='') {
  1047. fixr.initPhotographerId();
  1048. }
  1049. if (fixr.context.photographerName==='') {
  1050. fixr.initPhotographerName();
  1051. }
  1052. log('updateTags() med photographerAlias='+fixr.context.photographerAlias+', photographerId='+fixr.context.photographerId+' og photographerName='+fixr.context.photographerName);
  1053. if (document.querySelector('ul.tags-list')) {
  1054. var tags = document.querySelectorAll('ul.tags-list>li');
  1055. if (tags && tags !== null && tags.length > 0) {
  1056. for (var i = 0; i < tags.length; i++) {
  1057. var atag = tags[i].querySelector('a[title][href*="/photos/tags/"],a[title][href*="?tags="],a[title][href*="?q="]');
  1058. if (atag) {
  1059. var realtag = (atag.href.match(/((\/tags\/)|(\?tags\=)|(\?q\=))([\S]+)$/i))[5];
  1060. if (!(tags[i].querySelector('a.fixrTag'))) {
  1061. var icon = fixr.context.photographerIcon.match(/^([^_]+)(_\w)?\.[jpgntif]{3,4}$/)[1] + '' + fixr.context.photographerIcon.match(/^[^_]+(_\w)?(\.[jpgntif]{3,4})$/)[2]; // do we know for sure it is square?
  1062. tags[i].insertAdjacentHTML('afterbegin', '<a class="fixrTag" href="/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/tags/' + realtag + '/" title="' + atag.title + ' by ' + fixr.context.photographerName + '"><img src="' + icon + '" style="width:1em;height:1em;margin:0;padding:0;position:relative;top:3px" alt="*" /></a>');
  1063. }
  1064. }
  1065. }
  1066. } else {
  1067. log('no tags defined (yet?)');
  1068. }
  1069. } else {
  1070. log('taglist container not found');
  1071. }
  1072. }
  1073. function updateTagsDelayed() {
  1074. log('updateTagsDelayed() running... with pageType=' + fixr.context.pageType);
  1075. //clearTimeout(_timerMaplink);
  1076. if (fixr.context.pageType === 'PHOTOPAGE') {
  1077. setTimeout(updateTags, 2000);
  1078. setTimeout(updateTags, 3500); // Twice. Those tags are sometimes a bit slow emerging
  1079. }
  1080. }
  1081.  
  1082. function shootingSpaceballs() {
  1083. // Enable image context-menu on "View sizes" page by removing overlaying div.
  1084. // This is *not* meant as a tool for unauthorized copying and distribution of other peoples photos.
  1085. // Please respect image ownership and copyrights!
  1086. if (fixr.context.pageType === 'SIZES') {
  1087. var trash = document.querySelector('div.spaceball');
  1088. while (trash && trash.parentNode) {
  1089. trash.parentNode.removeChild(trash);
  1090. trash = document.querySelector('div.spaceball');
  1091. }
  1092. }
  1093. }
  1094.  
  1095. if (window.location.href.indexOf('flickr.com\/services\/api\/explore\/')>-1) {
  1096. // We are on Flickr API Explorer (WAS used for note handling before Flickr returned native note-support) and outside "normal" flickr page flow. fixr wont do here...
  1097. } else {
  1098. // FIXR fixr.init([onPageHandlers], [onResizeHandlers], [onFocusHandlers])
  1099. fixr.init([scaler.run, insertStyle, ctrlClicking, albumExtras, topPagination, shootingSpaceballs, ctrlClickingDelayed, exploreCalendarDelayed, albumTeaserDelayed, updateMapLinkDelayed, updateTagsDelayed], [scaler.run], []);
  1100. }