Stig's Flickr Fixr

Updates your Flickr-experience. Show photographer's albums on photostream-pages, Increase display-size and quality of "old" photos, Photographer's other photos by tag-links, A fix to actually show a geotagged photo on the linked map - - - And maybe more to come later...

当前为 2015-08-29 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Stig's Flickr Fixr
// @namespace   dk.rockland.userscript.flickr.fixr
// @description Updates your Flickr-experience. Show photographer's albums on photostream-pages, Increase display-size and quality of "old" photos, Photographer's other photos by tag-links, A fix to actually show a geotagged photo on the linked map - - - And maybe more to come later...
// @author      Stig Nygaard, http://www.rockland.dk, https://www.flickr.com/photos/stignygaard/
// @homepageURL http://www.rockland.dk/userscript/flickr/fixr/
// @supportURL  http://www.rockland.dk/userscript/flickr/fixr/#support
// @icon        http://www.rockland.dk/img/fixr32.png
// @icon64      http://www.rockland.dk/img/fixr64.png
// @include     https://www.flickr.com/*
// @include     https://flickr.com/*
// @match       https://*.flickr.com/*
// @version     2015.08.29.0
// @grant       none
// @run-at      document-start
// ==/UserScript==

var DEBUG = false;
function log(s) {
  if (DEBUG && window.console) { window.console.log(s); }
}
if (DEBUG) {
  if ('loading' === document.readyState) {
    log("This userscript is running at document-start time.");
  } else {
    log("This userscript is running with document.readyState: " + document.readyState);
  }
  window.addEventListener('DOMContentLoaded', function () {log('(onDOMContentLoaded)'); }, false);
  window.addEventListener('focus', function () {log('(onfocus)'); }, false);
  window.addEventListener('load', function () {log('(onload)'); }, false);
  window.addEventListener('pageshow', function () {log('(onpageshow)'); }, false);
  window.addEventListener('resize', function () {log('(onresize)'); }, false);
  window.addEventListener('hashchange', function () {log('(onhashchange)'); }, false);
}

// FIXR page-tracker start
var fixr = {
  context: {
    pageType: '',
    userId: '',
    photographerId: '', // value might be delayed (If uninitialized, try call initPhotographerId())
    photographerIcon: '',
    photographerAlias: '', // (pathalias) bonus-info sometimes initialized (from url) when initializing photoId
    photographerName: '',
    photoId: '',
    albumId: '',
    groupId: '',
    galleryId: ''
  },
  content: null,
  pageactionsCount: 0,
  timerResizeActionDelayed: 0,
  onPageHandlers: [],
  onResizeHandlers: [],
  initPhotographerId: function () { // photographer/attribution id
    var elem;
    if (document.querySelector('div.photostream-page-view')) {
      // photostream
      elem = document.querySelector('div.photostream-page-view div.fluid-photostream-coverphoto-view div.avatar.person');
    } else if (document.querySelector('div.photo-page-scrappy-view')) {
      // photopage
      elem = document.querySelector('div.photo-page-scrappy-view div.sub-photo-view div.avatar.person');
    } else if (document.querySelector('div.photo-page-lightbox-scrappy-view')) {
      // photopage lightbox
      elem = document.querySelector('div.photo-page-lightbox-scrappy-view div.photo-well-view div.photo-attribution div.avatar.person');
    } else if (document.querySelector('div.album-page-view')) {
      // album page
      elem = document.querySelector('div.album-page-view div.album-container div.album-header-view div.album-attribution div.avatar.person');
    } else {
      log('we do not look for photographerId on this page');
      return true;
    }
    // album oversigt
    // etc...
    // men minus f.eks. favorites oversigt!
    if (!elem) {
      log('fixr.initPhotographerId() - Attribution elem NOT found - returning false');
      return false;
    } // re-run a little later???
    log('fixr.initPhotographerId() - Attribution elem found');
    // (div.avatar.person).style.backgroundImage=url(https://s.yimg.com/pw/images/buddyicon07_r.png#44504567@N00)
    //                    .style.backgroundImage=url(//c4.staticflickr.com/8/7355/buddyicons/10259776@N00_r.jpg?1372021232#10259776@N00)
    if (elem.style.backgroundImage) {
      log('fixr.initPhotographerId() - elem has style.backgroundImage "' + elem.style.backgroundImage + '", now looking for the attribution id...');
      var pattern = /url[^#\?]+(\/\/[^#\?]+\.com\/[^#\?]+\/buddyicon[^\?\#]+)[^#]*#(\d+\@N\d{2})/i;
      // var pattern = /\/buddyicons\/(\d+\@N\d{2})\D+/i;
      var result = elem.style.backgroundImage.match(pattern);
      if (result) {
        log('fixr.initPhotographerId() - Attribution pattern match found: ' + result[0]);
        log('fixr.initPhotographerId() - the attribution icon is ' + result[1]);
        log('fixr.initPhotographerId() - the attribution id is ' + result[2]);
        fixr.context.photographerIcon = result[1];
        fixr.context.photographerId = result[2];
      } else {
        log('fixr.initPhotographerId() - attribution pattern match not found');
        return false;
      }
    } else {
      log('fixr.initPhotographerId() - elem.style.backgroundImage not found');
      return false;
    }
    log('fixr.initPhotographerId() - returning true...');
    return true;
  },
  initPhotoId: function () { // Photo Id
    //  *flickr.com/photos/user/PId/*
    var pattern = /^\/photos\/([^\/]+)\/([\d]{2,})/i;
    var result = window.location.pathname.match(pattern);
    if (result) {
      log('url match med photoId=' + result[2]);
      log('url match med photographerAlias=' + result[1]);
      fixr.context.photoId = result[2];
      fixr.context.photographerAlias = result[1];
      return true;
    }
    return false;
  },
  pageActions: function () {
    if (fixr.content) {
      log('fixr.pageActions() has started with fixr.content defined');
    } else {
      log('fixr.pageActions() was called, but fixr.content NOT defined');
      return;
    }
    fixr.pageactionsCount++;
    for (var p in fixr.context) {  // reset context on new page
      fixr.context[p] = ''; // filter ?
    }
    if (fixr.content.querySelector('div.photostream-page-view')) {
      if (fixr.content.querySelector('div.slideshow-view')) {
        fixr.context.pageType = 'PHOTOSTREAM SLIDESHOW';
      } else {
        fixr.context.pageType = 'PHOTOSTREAM';
      }
    } else if (fixr.content.querySelector('div.photo-page-scrappy-view')) {
      fixr.context.pageType = 'PHOTOPAGE';
    } else if (fixr.content.querySelector('div.photo-page-lightbox-scrappy-view')) {
      fixr.context.pageType = 'PHOTOPAGE LIGHTBOX';
    } else if (fixr.content.querySelector('div.albums-list-page-view')) {
      fixr.context.pageType = 'ALBUMSLIST';
    } else if (fixr.content.querySelector('div.album-page-view')) {
      if (fixr.content.querySelector('div.slideshow-view')) {
        fixr.context.pageType = 'ALBUM SLIDESHOW';
      } else {
        fixr.context.pageType = 'ALBUM';
      }
    } else if (fixr.content.querySelector('div.cameraroll-page-view')) {
      fixr.context.pageType = 'CAMERAROLL';
    } else if (fixr.content.querySelector('div.explore-page-view')) {
      fixr.context.pageType = 'EXPLORE';
    } else if (fixr.content.querySelector('div.favorites-page-view')) {
      if (fixr.content.querySelector('div.slideshow-view')) {
        fixr.context.pageType = 'FAVORITES SLIDESHOW';
      } else {
        fixr.context.pageType = 'FAVORITES';
      }
    } else if (fixr.content.querySelector('div.groups-list-view')) {
      fixr.context.pageType = 'GROUPSLIST'; // personal grouplist
    } else if (fixr.content.querySelector('div#activityFeed')) { // id=main i stedet for id=fixr.content
      fixr.context.pageType = 'ACTIVITYFEED'; // aka. front page
    } else {
      // fixr.context.pageType = ''; // unknown
    }

    log('fixr.context.pageType = ' + fixr.context.pageType);
    if (fixr.initPhotographerId()) {
      log('fixr.initPhotographerId() returned true');
    } else {
      log('fixr.initPhotographerId() returned false - re-running delayed...');
      setTimeout(fixr.initPhotographerId, 2000);
    }
    if (fixr.initPhotoId()) {
      log('fixr.initPhotoId() returned true');
    } else {
      log('fixr.initPhotoId() returned false');
    }
    if (fixr.content.querySelector('a.owner-name')) {
      fixr.context.photographerName = fixr.content.querySelector('a.owner-name').textContent;
    }

    // Now run the page handlers....
    if (fixr.onPageHandlers && fixr.onPageHandlers !== null && fixr.onPageHandlers.length) {
      log('We have ' + fixr.onPageHandlers.length + ' onPage handlers starting now...');
      for (var f = 0; f < fixr.onPageHandlers.length; f++) {
        fixr.onPageHandlers[f]();
      }
    }
  },
  setupContent: function () {
    if (document.getElementById('content')) {
      fixr.content = document.getElementById('content');
    } else if (document.getElementById('main')) {
      fixr.content = document.getElementById('main');    // frontpage
    }
    if (fixr.content && fixr.content.id) {
      log('fixr.content.id = ' + fixr.content.id);
    } else {
      log('content or main element NOT found!');
    }
  },
  runPageActionsIfMissed: function () {
    if (fixr.pageactionsCount === 0) {
      log('Vi kører fixr.pageActions() på bagkant via onload...');
      fixr.setupContent();
      if (fixr.content === null) {
        log('Vi kan IKKE køre fixr.pageActions() på bagkant, da fixr.content ikke er defineret');
        return;
      }
      fixr.pageActions();
    } else {
      log('ej nødvendigt at køre fixr.pageActions() på bagkant i dette tilfælde...');
    }
  },
  runDelayedPageActionsIfMissed: function () {
    setTimeout(fixr.runPageActionsIfMissed, 2000);
  },
  resizeActions: function () {
    if (fixr.onResizeHandlers && fixr.onResizeHandlers !== null && fixr.onResizeHandlers.length) {
      for (var f = 0; f < fixr.onResizeHandlers.length; f++) {
        fixr.onResizeHandlers[f]();
      }
    }
  },
  resizeActionsDelayed: function () { // or "preburner"
    clearTimeout(fixr.timerResizeActionDelayed);
    fixr.timerResizeActionDelayed = setTimeout(fixr.resizeActions, 250);
  },
  setupObserver: function () {
    log('fixr.setupObserve INITIALIZATION START');
    fixr.setupContent();
    if (fixr.content === null) {
      log('Init fails because content not defined');
      return;
    }
    // create an observer instance
    var observer = new MutationObserver(function (mutations) {
      log('NEW PAGE MUTATION!');
      //mutations.forEach(function(mutation) {
      //  log('MO: '+mutation.type); // might check for specific type of "mutations" (MutationRecord)
      //});
      fixr.pageActions();
    }); // MutationObserver end
    // configuration of the observer:
    var config = {attributes: false, childList: true, subtree: false, characterData: false};
    observer.observe(fixr.content, config);
    log('fixr.setupObserve INITIALIZATION DONE');
  },
  init: function (onPageHandlerArray, onResizeHandlerArray) {
    // General page-change observer setup:
    window.addEventListener('DOMContentLoaded', fixr.setupObserver, false); // Page on DOMContentLoaded
    window.addEventListener('load', fixr.runDelayedPageActionsIfMissed, false); // Page on load
    window.addEventListener('resize', fixr.resizeActionsDelayed, false); // også på resize
    if (onPageHandlerArray && onPageHandlerArray !== null && onPageHandlerArray.length) {
      fixr.onPageHandlers = onPageHandlerArray; // Replace by adding with a one-by-one by "helper" for flexibility?
    }
    if (onResizeHandlerArray && onResizeHandlerArray !== null && onResizeHandlerArray.length) {
      fixr.onResizeHandlers = onResizeHandlerArray; // Replace by adding with a one-by-one by "helper" for flexibility?
    }
  }
};
// FIXR page-tracker end


var _timerMaplink = 0;
function updateMapLink() {
  if (fixr.context.pageType !== 'PHOTOPAGE') {
    return; // exit if not photopage
  }
  log('updateMapLink() running at readystate=' + document.readyState + ' and with photoId=' + fixr.context.photoId);
  if (fixr.context.photoId) {
    var maplink = fixr.content.querySelector('a.static-maps');
    if (maplink) {
      if (maplink.getAttribute('href') && (maplink.getAttribute('href').indexOf('map/?') > 0) && (maplink.getAttribute('href').indexOf('&photo=') === -1)) {
        maplink.setAttribute('href', maplink.getAttribute('href') + '&photo=' + fixr.context.photoId);
        log('link is updated by updateMapLink() at readystate=' + document.readyState);
      } else {
        log('link NOT updated by updateMapLink(). Invalid element or already updated. readystate=' + document.readyState);
      }
    } else {
      log('NO maplink found at readystate=' + document.readyState + '. Re-try later?');
    }
  } else {
    log('NO photoId found at readystate=' + document.readyState);
  }
}
function updateMapLinkDelayed() {
  if (fixr.context.pageType !== 'PHOTOPAGE') {
    return;
  } // exit if not photopage
  log('updateMapLinkDelayed() running... with pageType=' + fixr.context.pageType);
  //clearTimeout(_timerMaplink);
  _timerMaplink = setTimeout(updateMapLink, 2000); // make maplink work better on photopage
}

var albums = { // cache albums to avoid repeating requests
  ownerId: '',
  html: '',
  count: 0
};
function getAlbumlist() {
  var _reqAlbumlist = null;
  if (window.XMLHttpRequest) {
    _reqAlbumlist = new XMLHttpRequest();
    if (typeof _reqAlbumlist.overrideMimeType !== 'undefined') {
      _reqAlbumlist.overrideMimeType('text/html');
    }

    _reqAlbumlist.onreadystatechange = function () {
      if (_reqAlbumlist.readyState === 4 && _reqAlbumlist.status === 200) {
        log('_reqAlbumlist returned status=' + _reqAlbumlist.status); // + ', \ntext:\n' + _reqAlbumlist.responseText);
        var doc = document.implementation.createHTMLDocument("sizeDoc");
        doc.documentElement.innerHTML = _reqAlbumlist.responseText;

        albums.ownerId = fixr.context.photographerId;
        albums.html = '';
        albums.count = 0;
        var e = doc.body.querySelectorAll('div.photo-list-album-view');
        var imgPattern = /url\([\'\"]*([^\)\'\"]+)(\.[jpgtifn]{3,4})[\'\"]*\)/i;
        if (e && e.length > 0) {
          albums.count = e.length;
          for (var i = 0; i < Math.min(10, e.length); i++) {
            var imgUrl = '';
            log(e[i].outerHTML);
            log('A7 (' + i + ') : '+e[i].style.backgroundImage);
            // var result = e[i].style.backgroundImage.match(imgPattern); // strangely not working in Chrome
            var result = (e[i].outerHTML).match(imgPattern); // quick work-around for above (works for now)
            if (result) {
              imgUrl = result[1].replace(/_[a-z]$/, '') + '_s' + result[2];
              log('imgUrl=' + imgUrl);
            } else {
              log('No match on imgPattern');
            }
            var a = e[i].querySelector('a[href][title]'); // sub-element
            if (a && a!==null) {
              log('Album title: ' + a.title);
              log('Album url: ' + a.getAttribute('href'));
              albums.html += '<div><a href="//www.flickr.com' + a.getAttribute('href') + '"><img src="' + imgUrl + '" alt="" /><div style="margin:0 0 .8em 0">' + a.title + '</div></a></div>';
            } else {
              log('a element not found?');
            }
          }
        }
        if (document.getElementById('albumTeaser')) {
          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>';
        } else {
          log('albumTeaser NOT FOUND!?!');
        }
      } else {
        // wait for the call to complete
      }
    };

    if (fixr.context.photographerId === albums.ownerId && fixr.context.photographerId !== '') {
      log('Usinging CACHED albumlist!...');
      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>';
    } else if (fixr.context.photographerId) {
      var url = 'https://www.flickr.com/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/albums';
      _reqAlbumlist.open('GET', url, true);
      _reqAlbumlist.send(null);
    } else {
      log('Attribution user (photographer) not found');
    }
  } else {
    log('understøtter ikke XMLHttpRequest');
  }
}
function albumTeaser() {
  if (fixr.context.pageType !== 'PHOTOSTREAM') {
    return; // exit if not photostream
  }
  log('albumTeaser() running');
  var dpc = document.querySelector('div.photolist-container');
  if (!dpc) {
    return;
  }
  // to-do: check om personlig photostream?
  // to-do: check padding-right er mindst 130px?
  log('AlbumTeaser found div.photolist-container');
  if (!document.getElementById('albumTeaser')) {
    dpc.style.position = "relative";
    dpc.insertAdjacentHTML('afterbegin', '<div id="albumTeaser" style="border:none;margin:0;padding:0;position:absolute;top:0;right:10px;width:100px"></div>');
  }
  if (document.getElementById('albumTeaser')) {
    getAlbumlist();  // også check på fixr.context.photographerId ?
  }
}
var _timerAlbumTeaserDelayed;
function albumTeaserDelayed() {
  if (fixr.context.pageType !== 'PHOTOSTREAM') {
    return; // exit if not photostream
  }
  log('albumTeaserDelayed() running...');
  clearTimeout(_timerAlbumTeaserDelayed);
  _timerAlbumTeaserDelayed = setTimeout(albumTeaser, 1500);
}

function getUserId() { // Id of logged-in user
  return null; // to-do
}

var scaler = {
  photoId: '',
  mf: null,   // document.querySelector('img.main-photo') for (re-)re-scale
  lrf: null,  // document.querySelector('img.low-res-photo') for (re-)re-scale
  maxSizeUrl: '',
  hasOriginal: false,
  scaleToWidth: 0,
  scaleToHeight: 0,
  run: function () {
    if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
      return; // exit if not photopage or lightbox
    }
    log('scaler.run() running...');
    // var that = this;
    var scale = function () {
      if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
        return;
      } // exit if not photopage or lightbox
      log('scaler.scale() running... (scale to:' + scaler.scaleToWidth + 'x' + scaler.scaleToHeight + ')');
      scaler.mf = document.querySelector('img.main-photo');  // for en sikkerheds skyld
      scaler.lrf = document.querySelector('img.low-res-photo');  // for en sikkerheds skyld
      if (scaler.mf && scaler.mf !== null && scaler.lrf && scaler.lrf !== null && scaler.scaleToWidth > 0 && scaler.scaleToHeight > 0) {
        log('[scaler] do scaling WORK. Height from ' + scaler.mf.height + ' to ' + scaler.scaleToHeight);
        scaler.mf.height = scaler.scaleToHeight;
        log('[scaler] do scaling WORK. Width from ' + scaler.mf.width + ' to ' + scaler.scaleToWidth);
        scaler.mf.width = scaler.scaleToWidth;
        scaler.lrf.height = scaler.mf.height;
        scaler.lrf.width = scaler.mf.width;
      }
    };
    var replace = function () { // and (re-)scale?
      if (fixr.context.pageType !== 'PHOTOPAGE' && fixr.context.pageType !== 'PHOTOPAGE LIGHTBOX') {
        return; // exit if not photopage or lightbox
      }
      log('scaler.run.replace() running...');
      scaler.mf = document.querySelector('img.main-photo');  // for en sikkerheds skyld
      if (scaler.mf && scaler.mf !== null) {
        scaler.mf.src = scaler.maxSizeUrl; // only if original
        scale();
      }
    };
    var getSizes = function () {
      log('scaler.run.getSizes() running...');
      var _reqAllSizes = null;
      if (window.XMLHttpRequest) {
        _reqAllSizes = new XMLHttpRequest();
        if (typeof _reqAllSizes.overrideMimeType !== 'undefined') {
          _reqAllSizes.overrideMimeType('text/html');
        }
        _reqAllSizes.onreadystatechange = function () {
          if (_reqAllSizes.readyState === 4 && _reqAllSizes.status === 200) {
            log('[scaler] _reqAllSizes returned status=' + _reqAllSizes.status); // + ', \ntext:\n' + _reqAllSizes.responseText);
            var doc = document.implementation.createHTMLDocument("sizeDoc");
            doc.documentElement.innerHTML = _reqAllSizes.responseText;
            if (doc.body.querySelector('div#allsizes-photo>img')) {
              scaler.maxSizeUrl = doc.body.querySelector('div#allsizes-photo>img').src;
              log('[scaler] Largest image size: ' + scaler.maxSizeUrl);
            }
            var e = doc.body.querySelectorAll('ol.sizes-list li ol li');
            if (e && e.length > 0) {
              var s = e[e.length - 1].textContent.replace(/\s{2,}/g, ' ');
              if (s.indexOf('Original') > -1) {
                scaler.hasOriginal = true;
                log('[scaler] ' + s);
                replace();
              } else {
                log('[scaler] Bruger tillader ikke adgang til original');
              }
              // udtræk evt sizes fra s?
            }
          } else {
            // wait for the call to complete
          }
        };
        var url = 'https://www.flickr.com/photos/' + (fixr.context.photographerAlias !== '' ? fixr.context.photographerAlias : fixr.context.photographerId) + '/' + fixr.context.photoId + '/sizes/o';
        _reqAllSizes.open('GET', url, true);
        _reqAllSizes.send(null);
      } else {
        log('[scaler] understøtter ikke XMLHttpRequest');
      }
    };
    if (scaler.photoId === '') {
      scaler.photoId = fixr.context.photoId;
    } else if (scaler.photoId !== fixr.context.photoId) {
      scaler.photoId = fixr.context.photoId;
      scaler.mf = null;
      scaler.lrf = null;
      scaler.maxSizeUrl = '';
      scaler.hasOriginal = false;
      scaler.scaleToWidth = 0;
      scaler.scaleToHeight = 0;
    }
    var roomHeight = 0;
    var roomWidth = 0;
    var roomPaddingHeight = 0;
    var roomPaddingWidth = 0;

    // Fortsæt kun hvis PhotoId!!!?

    var dpev = document.querySelector('div.photo-engagement-view');
    var pwv = document.querySelector('div.photo-well-view');
    if (pwv) {
      log('[scaler] height-controller: height=' + pwv.clientHeight + ' (padding=70?), width=' + pwv.clientWidth + ' (padding=80?).'); // hc.style.padding: 20px 40px 50px
      if (roomHeight === 0) {
        roomHeight = pwv.clientHeight;
      }
      if (roomWidth === 0) {
        roomWidth = pwv.clientWidth;
      }
      roomPaddingHeight += (parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-bottom'), 10));
      roomPaddingWidth += (parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(pwv, null).getPropertyValue('padding-right'), 10));
    }
    var hc = document.querySelector('div.height-controller');
    if (hc) {
      log('[scaler] height-controller: height=' + hc.clientHeight + ' (padding=70?), width=' + hc.clientWidth + ' (padding=80?).'); // hc.style.padding: 20px 40px 50px
      if (roomHeight === 0) {
        roomHeight = hc.clientHeight;
      }
      if (roomWidth === 0) {
        roomWidth = hc.clientWidth;
      }
      roomPaddingHeight += (parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-bottom'), 10));
      roomPaddingWidth += (parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(hc, null).getPropertyValue('padding-right'), 10));
    }
    var pwmsv = document.querySelector('div.photo-well-media-scrappy-view');
    if (pwmsv) {
      log('[scaler] div.photo-well-media-scrappy-view: height=' + pwmsv.clientHeight + ' (padding=70?), width=' + pwmsv.clientWidth + ' (padding=80?).'); // pwmsv.style.padding: 20px 40px 50px
      if (roomHeight === 0) {
        roomHeight = pwmsv.clientHeight;
      }
      if (roomWidth === 0) {
        roomWidth = pwmsv.clientWidth;
      }
      roomPaddingHeight += (parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-top'), 10) + parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-bottom'), 10));
      roomPaddingWidth += (parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-left'), 10) + parseInt(window.getComputedStyle(pwmsv, null).getPropertyValue('padding-right'), 10));
    }
    scaler.mf = document.querySelector('img.main-photo');
    scaler.lrf = document.querySelector('img.low-res-photo');
    // var zl = document.querySelector('img.zoom-large'); // currently not used
    // var zs = document.querySelector('img.zoom-small'); // currently not used
    if (scaler.mf) {
      log('[scaler] main-photo: h=' + scaler.mf.height + ', w=' + scaler.mf.width + '.  -  Room: (h=' + (roomHeight - roomPaddingHeight) + ',w=' + (roomWidth - roomPaddingWidth) + ')');
      if (roomPaddingWidth === 0) { // hack
        roomPaddingWidth = 120;
        log('[scaler] roomPaddingWidth=120 hack used');
      }
      if (((roomHeight - roomPaddingHeight) > scaler.mf.height + 5) && ((roomWidth - roomPaddingWidth) > scaler.mf.width + 5)) {
        log('[scaler] ALLRIGHT - WE ARE READY FOR SCALING!...');
        if (((roomHeight - roomPaddingHeight) / scaler.mf.height) < ((roomWidth - roomPaddingWidth) / scaler.mf.width)) {
          scaler.scaleToWidth = Math.floor(scaler.mf.width * ((roomHeight - roomPaddingHeight) / scaler.mf.height));
          scaler.scaleToHeight = roomHeight - roomPaddingHeight;
        } else {
          scaler.scaleToHeight = Math.floor(scaler.mf.height * ((roomWidth - roomPaddingWidth) / scaler.mf.width));
          scaler.scaleToWidth = roomWidth - roomPaddingWidth;
        }
        log('[scaler] now calling scale()... [' + scaler.scaleToWidth + ', ' + scaler.scaleToWidth + ']');
        scale();
        log('[scaler] ...AND CONTINUE LOOKING FOR ORIGINAL...');
        if (dpev) { // if (document.querySelector('ul.sizes'))
          var org = document.querySelector('ul.sizes li.Original a.download-image-size');
          if (org) { // når vi bladrer?
            scaler.hasOriginal = true; // ??? kun hvis original
            scaler.maxSizeUrl = (org.href).replace(/^https\:/i, '').replace(/_d\./i, '.');
            replace();
          } else {
            // vi kan finde original "inline"
            var target = document.querySelector('div.photo-engagement-view');
            // if(!target) return; ???
            if (target) {
              var observer = new MutationObserver(function (mutations) {
                mutations.forEach(function (mutation) {
                  log('[scaler] MO size: ' + mutation.type); // might check for specific "mutations"?
                });
                var org = document.querySelector('ul.sizes li.Original a.download-image-size');
                if (org) {
                  scaler.hasOriginal = true; // ??? kun hvis original
                  scaler.maxSizeUrl = (org.href).replace(/^https\:/i, '').replace(/_d\./i, '.');
                  replace();
                } else {
                  log('Original photo not available for download on this photographer');
                }
                observer.disconnect();
              });
              // configuration of the observer:
              var config = {attributes: false, childList: true, subtree: false, characterData: false};
              observer.observe(target, config);
            }
          }
        } else {
          getSizes(); // resize (& replace) from/when size-list
        }
      }
    }
  }
};

function insertStyle() {
  log('tagStyle()');
  if (!document.getElementById('fixrStyle')) {
    var style = document.createElement('style');
    style.type = 'text/css';
    style.id = 'fixrStyle';
    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;}';
    document.getElementsByTagName('head')[0].appendChild(style);
    /*
     if(!(style.sheet||{}).insertRule) {
     (style.styleSheet || style.sheet).addRule(selector, declarations);
     } else {
     style.sheet.insertRule(selector+"{"+declarations+"}",0);
     }
     */
    log('fixrStyle has been ADDED');
  } else {
    log('fixrStyle was already present');
  }
}
function updateTags() {
  if (fixr.context.pageType !== 'PHOTOPAGE') {
    return; // exit if not photopage
  }
  log('updateTags()');
  if (document.querySelector('ul.tags-list')) {
    var tags = document.querySelectorAll('ul.tags-list>li');
    if (tags && tags !== null && tags.length > 0) {
      for (var i = 0; i < tags.length; i++) {
        var atag = tags[i].querySelector('a[title][href*="?tags="],a[title][href*="?q="]');
        if (atag) {
          var realtag = (atag.href.match(/\?(tags|q)\=([\S]+)$/i))[2];
          if (!(tags[i].querySelector('a.fixrTag'))) {
            //log('updateTags() '+i+' fixr.context.photographerIcon: '+fixr.context.photographerIcon);
            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?
            //log('updateTags() '+i+' icon: '+icon); //
            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>');
          }
        }
      }
    } else {
      log('no tags defined (yet?)');
    }
  } else {
    log('taglist container not found');
  }
}
function updateTagsDelayed() {
  if (fixr.context.pageType !== 'PHOTOPAGE') {
    return; // exit if not photopage
  }
  log('updateTagsDelayed() running... with pageType=' + fixr.context.pageType);
  //clearTimeout(_timerMaplink);
  if (fixr.context.pageType === 'PHOTOPAGE') {
    setTimeout(updateTags, 2500);
  }
}

// FIXR fixr.init(onPageHandlers, onResizeHandlers)
fixr.init([scaler.run, insertStyle, albumTeaserDelayed, updateMapLinkDelayed, updateTagsDelayed], [scaler.run]);



/* OLD STUFF...


// Call Flickr REST API to get available photo sizes - Method currently NOT used:
function wsGetSizes(photoId) {
  var _reqGetSizes = null;
  if (window.XMLHttpRequest) {
    _reqGetSizes = new XMLHttpRequest();
    if ( typeof _reqGetSizes.overrideMimeType !== 'undefined') {
      _reqGetSizes.overrideMimeType('application/json');
    }
    _reqGetSizes.onreadystatechange = function() {
      if (_reqGetSizes.readyState === 4 && _reqGetSizes.status === 200) {
        // do something with the results
        // var myObj = eval ( _reqGetSizes.responseText );
        log('webservice photos.getSizes returned status=' + _reqGetSizes.status + ', text: ' + _reqGetSizes.responseText);
        var obj = JSON.parse(_reqGetSizes.responseText);
        if (obj.stat === "ok") {
          log("ok");
          if (obj.sizes.candownload==1) {
            log("can download");
            var array = obj.sizes.size;
            if (array && array.length>0) {
              log("array length="+array.length);
              var elem = array[array.length-1];
              if (elem) {
                log("last elem is: "+elem.label+" with source="+elem.source);
                if (elem.label==="Original" && elem.source && elem.source.length>0) {
                  // make sure photoId matches source
                  photoOrg(elem.source);
                  log("Original from webservice was used");
                }
              }
            }
          } else {
            log('Originals not available on user');
          }
        }
        // Hvis sizeList && original tilgængelig
        //   photoOrg(url); // Update image now!!!
        // ellers hvis sizelist
        //   log('Originals not available on user');
        // ellers hvis sizelist
        //   log('Error fetching original');
      } else {
        // wait for the call to complete
      }
    };

    _reqGetSizes.open('GET', 'https://api.flickr.com/services/rest/?method=flickr.photos.getSizes&api_key=9b8140dc97b93a5c80751a9dad552bd4&photo_id=' + photoId + '&format=json&nojsoncallback=1', true);
    _reqGetSizes.send(null);

  } else {
    log('understøtter ikke XMLHttpRequest');
  }
}


// Call Flickr REST API to get albums - Method currently NOT used:
function wsGetAlbums() {
  var _reqGetAlbums = null;
  if (window.XMLHttpRequest) {
    _reqGetAlbums = new XMLHttpRequest();
    if ( typeof _reqGetAlbums.overrideMimeType != 'undefined') {
      _reqGetAlbums.overrideMimeType('application/json');
    }
    _reqGetAlbums.onreadystatechange = function() {
      if (_reqGetAlbums.readyState == 4 && _reqGetAlbums.status == 200) {
        log('Webservice photosets.getList returned status=' + _reqGetAlbums.status + _reqGetAlbums.responseText);
        var obj = JSON.parse(_reqGetAlbums.responseText);
        if (obj && obj.stat == "ok") {
          log("ok");
          albums.ownerId = fixr.context.photographerId;
          albums.set = [];
          albums.html = '';
          albums.pathalias = '';
          if (obj.photosets) {
            if(parseInt(obj.photosets.total,10)===0) {
              // keep empty
            } else if (obj.photosets.photoset) {
              albums.set = obj.photosets.photoset;
              var elem;
              for(var i=0; i<obj.photosets.photoset.length; i++) {
                elem = obj.photosets.photoset[i];  // should loop through multiple
                log("elem is: "+elem.id+" with title="+elem.title._content);
                if (elem.primary_photo_extras && elem.primary_photo_extras.url_sq && elem.primary_photo_extras.url_sq.length>0) {
                  log('photoset ikon url = ' + elem.primary_photo_extras.url_sq);
                  albums.html += '<div><a href="//www.flickr.com/photos/' + elem.primary_photo_extras.pathalias + '/sets/' + elem.id + '"><img src="' + elem.primary_photo_extras.url_sq +'" alt="" /><div style="margin:0 0 .8em 0">' + elem.title._content + '</div></a></div>';
                }
              }
              albums.pathalias = elem.primary_photo_extras.pathalias;
            } else {
              log('why are we here?');
            }
          }
        } else {
          // error parse
        }
        document.getElementById('albumTeaser').innerHTML = '<div style="margin:0 0 .8em 0">Albums</div>'+albums.html+'<div><i><a href="/photos/'+albums.pathalias+'/albums/">More albums...</a></i></div>';
      } else {
        // wait for the call to complete
      }
    };
    if (fixr.context.photographerId === albums.ownerId && fixr.context.photographerId!='') {
      // use cached
      document.getElementById('albumTeaser').innerHTML = '<div style="margin:0 0 .8em 0">Albums</div>'+albums.html+'<div><i><a href="/photos/'+albums.pathalias+'/albums/">More albums...</a></i></div>';
      log('Using CACHED albumlist!');
    } else if (fixr.context.photographerId) {
      _reqGetAlbums.open('GET', 'https://api.flickr.com/services/rest/?method=flickr.photosets.getList&api_key=9b8140dc97b93a5c80751a9dad552bd4&user_id=' + fixr.context.photographerId + '&page=1&per_page=10&primary_photo_extras=geo%2C+path_alias%2C+url_sq&format=json&nojsoncallback=1', true);
      _reqGetAlbums.send(null);
    } else {
      log('Attribution user (photographer) not found');
    }
  } else {
    log('Understøtter ikke XMLHttpRequest');
  }
}
*/