rendered paste body// ==UserScript==
// @name Flickr AllSizes+
// @description Access all sizes for a Flickr photo. Copy the code, download the image, etc.
// @author Premasagar Rose (http://premasagar.com/contact/)
// @namespace http://premasagar.com
// @identifier http://premasagar.com/dev/gm/flickrallsizesplus.user.js
// @version 1.115
// @date 2007-01-23
//
// @include http://www.flickr.com/photo_zoom.gne*
// @include http://flickr.com/photo_zoom.gne*
// @include http://www.flickr.com/photos/*/*
// @include http://flickr.com/photos/*/*
//
// @exclude http://*flickr.com/photos/organize/*
// @exclude http://*flickr.com/photos/friends/*
// @exclude http://*flickr.com/photos/tags/*
//
// @exclude http://*flickr.com/photos/*/sets*
// @exclude http://*flickr.com/photos/*/friends*
// @exclude http://*flickr.com/photos/*/archives*
// @exclude http://*flickr.com/photos/*/tags*
// @exclude http://*flickr.com/photos/*/alltags*
// @exclude http://*flickr.com/photos/*/multitags*
// @exclude http://*flickr.com/photos/*/map*
// @exclude http://*flickr.com/photos/*/favorites*
// @exclude http://*flickr.com/photos/*/popular*
// @exclude http://*flickr.com/photos/*/with*
// ==/UserScript==
/*
INFO
====
Before installing this script, you'll need the Firefox browser (http://www.mozilla.org/firefox/) and the Greasemonkey extension (http://greasemonkey.mozdev.org)
Discuss this script / report bugs / request features:
http://www.flickr.com/groups/flickrhacks/discuss/72157594303798688/
Download the latest version:
http://premasagar.com/dev/gm/flickrallsizesplus.user.js
Released under the GPL license:
http://www.gnu.org/copyleft/gpl.html
SUMMARY
=======
This script makes it easier to access all the sizes available for a photo, including the original size on non-Pro accounts.
You can access the code for re-posting photos on Flickr discussion threads and other websites, as well as download images and more.
To read the full documentation, click the "AllSizes" button on a photo's photopage and click on the 'Documentation' link.
If you improve the script, please let me know...
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
(function() {
// USERSCRIPT INFORMATION
var UserScript = {
id: 'flickrallsizesplus',
title: 'Flickr AllSizes+',
header: 'allSizes+',
version: 1.115,
date: new Date(2007, 0, 23),
author: 'Premasagar',
// Hours till next update check
updateInterval: 24,
// Api url to check for updates
checkUpdateUrl: 'http://premasagar.com/api/checkupdates/',
// Url for script discussion thread
metaUrl: 'http://www.flickr.com/groups/flickrhacks/discuss/72157594303798688/',
// Function to check for script updates
checkForUpdates: function(){
// Does user want to check for updates?
if (!Settings.getValue('checkforUpdates'))
{ return; }
// Determine last time script was checked for updates
var lastCheck = GM_getValue('lastUpdateCheck');
lastCheck = (typeof lastCheck != 'undefined') ? parseInt(lastCheck) : this.date.getTime();
// Get the current time
var timeNow = new Date().getTime();
// Guard against weird stuff, like user changing system clock to the future
if (lastCheck > timeNow)
{ lastCheck = timeNow; }
// Is it time to check for updates? If not, return
if (timeNow < (lastCheck + (this.updateInterval * 60 * 60 * 1000)))
{ return; }
// Update the lastUpdateCheck local variable
GM_setValue('lastUpdateCheck', timeNow.toString());
// +-+-+-+-+-+-+-+-+
// Api url for the update check
var url = this.checkUpdateUrl + '?id=' + this.id + '&version=' + this.version + '&noCache=' + timeNow;
var that = this;
// Callback function for the AJAX request
var callback = function(response){
// Bad response
if (!response) { return; }
else if (response.responseText == '') { return; }
// Parse the response
var parser = new DOMParser();
var dom = parser.parseFromString(response.responseText, "application/xml");
var rsp = dom.getElementsByTagName('rsp')[0];
// Our request failed! Return.
if (rsp.getAttribute('stat') != 'ok') { return; }
// Get userscript details
var userscript = rsp.getElementsByTagName('userscript')[0];
var v = userscript.getAttribute('version');
var downloadUrl = userscript.getElementsByTagName('url')[0].textContent;
var metaUrl = userscript.getElementsByTagName('url')[0].textContent;
var changelog = userscript.getElementsByTagName('changelog')[0].textContent;
// If there's no version update, then return
if (v == that.version)
{ return; }
// There's an update! Create a pop-up to tell the user
var popUp = new PopUp('Update Available');
popUp.main.className = '';
var div = popUp.main.appendChild(cE('div'));
div.className = 'indented';
var innerHTML = '<p><strong>Script:</strong> ' + UserScript.title + '</p>';
innerHTML += '<p>Version ' + v + ' is now available.</p>';
innerHTML += '<p><strong><a style="font-size:1.4em;" href="' + downloadUrl + '" title="Install new version of this script">» Install it!</a></strong></p>';
if (changelog != '')
{
innerHTML += '<h3>New Features</h3>';
innerHTML += '<p>' + changelog + '</p>';
}
div.innerHTML = innerHTML;
popUp.open();
};
// Make the AJAX request
ajaxRequest(url, callback);
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Check that latest version of Greasemonkey is installed
if (!GM_xmlhttpRequest) {
if (window.confirm('You do not have the latest version of Greasemonkey installed.\nWould you like to get it now?'))
{ window.location.href = 'http://greasemonkey.mozdev.org'; }
return;
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Initialise script for essential functions
initScript();
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// FLICKR REFERENCE OBJECT
var Flickr = {
// Urls
imgRoot: 'http://static.flickr.com/',
siteRoot: 'http://www.flickr.com/',
// Flickr Regular Expressions
regex: {
photoSrc:
/^(http:\/\/(farm\d{0,3}\.)?static\.flickr\.com\/(\d+)\/(\d+)_(\w+?)((_[stmb])?\.jpg|_o\.(jpg|gif|png))).*$/,
photoPageUrl:
/^((http:\/\/(www\.)?flickr\.com)?\/photos\/([\w@_-]+)\/(\d+))(\/.*)?$/,
allSizesPageUrl: /^http:\/\/(www\.)?flickr\.com\/photo_zoom\.gne\?id=(\d+)&size=(sq?|[tmlo])$/,
buddyiconSrc:
/^(http:\/\/((farm\d{0,3}\.)?static.flickr.com\/(\d+)\/buddyicons\/([\w@_-]+)\.jpg(\?\d+)?|(www\.)?flickr\.com\/images\/buddyicon\.jpg\?([\w@_-]+)))$/,
nsid:
/^\d{8,12}@N\d{0,3}$/
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// PHOTO OBJECT
function Photo(id, secret, server){
this.id = id;
this.secret = secret;
this.server = server;
this.init.init(this);
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// STATIC FUNCTIONS ON PHOTO OBJECT
Object.extend(Photo, {
// Create Photo object from an image src
fromSrc: function(src){
// Get parameters: id, secret, server, file extension for original size
var params = src.replace(Flickr.regex.photoSrc, '$4,$5,$3,$8').split(",");
// Create new Photo object
var photo = new this(params[0], params[1], params[2]);
// If the image is the original size, then set the original size file extension
if (params[3] != '')
{ photo.sizes.o.extension = '.' + params[3]; }
return photo;
},
// Create Photo object from an image element
fromImg: function(img){
// Create Photo object from the image src
var photo = this.fromSrc(img.src);
// Get the size suffix - e.g. '_s', '_t'
var suffix = img.src.replace(Flickr.regex.photoSrc, '$6').slice(0,2);
// For medium size
if (suffix.slice(0,1) != '_')
{ suffix = ''; }
// Determine which image size this is
var size = $A(photo.sizes).getBy('suffix', suffix);
if (size)
{
// Set the dimensions of this size and smaller sizes
photo.sizes[size.id].setDimensions(img.width, img.height);
photo.sizes.setDimensions();
}
return photo;
}
});
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// PHOTO OBJECT PROTOTYPE
Photo.prototype = {
// Init Object, for storing functions required at object initialisation
init: new Init(),
title: null,
owner: null,
// Get photo title. Add username to title, if user has requested it.
getTitle: function(){
// Check title of page each time, in case owner/user changes it
this.title = Page.getCurrentPage().getTitle();
// We don't yet know the title...
if (!this.title) { return null; }
// Replace blank titles with the user's setting for blank titles.
var title = (this.title.length == 1 && this.title.charCodeAt(0) == 160) ? '' : this.title;
if (title == '')
{ title = Settings.getValue('untitledTitle'); }
// Check if we have the owner's username
if (!this.owner) { return title; }
if (!this.owner.username) { return title; }
// Check the user's settings for adding the username to the title
if ((this.isUser && Settings.getValue('addUsernameWhenYou')) || (!this.isUser && Settings.getValue('addUsernameToTitle')) )
{ title += Settings.getValue('usernameFormat').replace(/\[user\]/g, this.owner.username); }
// Convert any special characters to their HTML entities (e.g. &, <, ")
return convertSpecialChars(title);
},
// Get the url of the photopage for this photo
getPhotopageUrl: function(){
// If we don't know the owner, then use the generic url
if (!this.owner)
{ return Flickr.siteRoot + 'photo.gne?id=' + this.id; }
// If we know the owner, then use the specific url
else
{ return this.owner.getPhotosUrl() + this.id + '/'; }
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// PERSON OBJECT
function Person(userUrl){
this.userUrl = userUrl;
// Check if the userUrl is also the nsid
if (userUrl.match(Flickr.regex.nsid))
{ this.nsid = this.userUrl; }
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// PERSON PROTOTYPE
Person.prototype = {
nsid: null,
username: null,
// Url for person's photostream
getPhotosUrl: function(){
var userUrl = (this.userUrl) ? this.userUrl : this.nsid;
return (userUrl) ? Flickr.siteRoot + 'photos/' + userUrl + '/' : null;
},
// Url for person's profile
getProfileUrl: function(){
var userUrl = (this.userUrl) ? this.userUrl : this.nsid;
return (userUrl) ? Flickr.siteRoot + 'people/' + userUrl + '/' : null;
},
// Url to send a FlickrMail
getSendmailUrl: function(){
return (this.nsid) ? Flickr.siteRoot + 'messages_write.gne?to=' + this.nsid : null;
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// STATIC FUNCTIONS ON PERSON OBJECT
Object.extend(Person, {
getNsidFromBuddyiconSrc: function(src){
var nsid = src.replace(Flickr.regex.buddyiconSrc, '$5');
if (nsid == '')
{ nsid = src.replace(Flickr.regex.buddyiconSrc, '$8'); }
return (nsid != '') ? nsid : null;
},
// Create a Person object by supplying the photopage url
fromPhotopageUrl: function(url){
var userUrl = url.replace(Flickr.regex.photoPageUrl, '$4');
return new this(userUrl);
},
// Create a Person object by supplying their buddyicon image src
fromBuddyiconSrc: function(src){
var nsid = Person.getNsidFromBuddyiconSrc(src);
if (!nsid) { return null; }
var person = new this(nsid);
person.nsid = nsid;
return person;
}
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// PHOTO LICENCE OBJECT
function License(id, name, url){
this.id = id;
this.name = name;
this.url = url;
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// PHOTO LICENCE PROTOTYPE
License.prototype = {
// Get the icon to display for this license
getIcon: function(){
if (this.id == 0)
{ return icon = cE('span', '\u00a9'); } // copyright symbol
else if (this.id < Photo.licenses.length)
{
var icon = cE('img');
icon.src = EncodedImages.creativeCommonsIcon;
return icon;
}
else
{ return null; }
},
// Get an HTML anchor element to display the license icon and a link for further info
getAnchor: function(){
var a = cE('a');
a.href = this.url;
a.appendChild(this.getIcon());
a.appendChild(cTN(' ' + this.name));
return a;
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// EXTEND PHOTO OBJECT WITH STATIC LICENSE OBJECTS
// (not to Photo prototype, because a photo only has one license at a time)
Object.extend(Photo, {
licenses: [
new License(0, 'All Rights Reserved', 'http://www.iusmentis.com/copyright/allrightsreserved/'),
new License(1, 'Attribution-NonCommercial-ShareAlike', 'http://creativecommons.org/licenses/by-nc-sa/2.0/'),
new License(2, 'Attribution-NonCommercial', 'http://creativecommons.org/licenses/by-nc/2.0/'),
new License(3, 'Attribution-NonCommercial-NoDerivs', 'http://creativecommons.org/licenses/by-nc-nd/2.0/'),
new License(4, 'Attribution', 'http://creativecommons.org/licenses/by/2.0/'),
new License(5, 'Attribution-ShareAlike', 'http://creativecommons.org/licenses/by-sa/2.0/'),
new License(6, 'Attribution-NoDerivs', 'http://creativecommons.org/licenses/by-nd/2.0/')
]
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// SIZE OBJECT
function Size(initObj){
Object.extend(this, initObj);
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// SIZE OBJECT PROTOTYPE
Size.prototype = {
extension:'.jpg',
width: null,
height: null,
// Check if this size exists for this photo
exists: function(){
// All sizes except large always exist
if (this.id != 'l')
{ return true; }
// LARGE SIZES
// Get original size
var o = this.photo.sizes.o;
// If original has incomplete dimensions, check if large size has dimensions
if (!o.width || !o.height)
{ return (this.width && this.height) ? true : null; }
// Check original size dimensions
return (o.width > 1280 || o.height > 1280) ? true : false;
},
// Check if this size has a known image src
isKnownSrc: function(){
return (this.exists() && this.extension) ? true : false;
},
// Check if this size has known dimensions
isKnownSize: function(){
return (this.width && this.height) ? true : false;
},
// Check if this size has a known src and dimensions
isComplete: function(){
// Check if original size rotation is known
var knownRotation = true;
if (typeof this.rotated != 'undefined')
{ knownRotation = (this.rotated !== null); }
return (this.isKnownSrc() && this.isKnownSize() && knownRotation) ? true : false;
},
// Get an array of the image dimensions
getDimensions: function(){
return [this.width, this.height];
},
// Set the dimensions for this size
// Optional args: width & height. If not supplied, size is calculated from larger sizes
setDimensions: function(){
// If width and height are supplied...
if (arguments.length > 0)
{
this.width = arguments[0];
if (arguments.length > 1)
{ this.height = arguments[1]; }
return this.getDimensions();
}
// If width & height not supplied...
// Get the largest complete size, as a comparison
var largest = this.photo.sizes.getLargestKnownSize();
if (!largest) { return false; }
// If the largest size is this size, then return
else if (largest.max == this.max)
{ return false; }
// Check if the original was rotated by the owner
if (largest.id == 'o' && this.photo.sizes.o.rotated)
{
// Copy object so that we can temporarily change its properties
largest = Object.extend({}, largest);
var temp = largest.width;
largest.width = largest.height;
largest.height = temp;
}
// If the largest size is smaller than this size
if (largest.max < this.max)
{
// If the largest size is smaller than its max dimensions, then this has the same size
if (largest.width < largest.max && largest.height < largest.max)
{ return this.setDimensions(largest.width, largest.height); }
else
{ return false; }
}
// If this is the large size, then special rules apply
else if (largest.id == 'o' && this.id == 'l' && largest.width <= 1280 && largest.height <= 1280)
{ return false; }
// -- Calculate dimensions for this size
// If the comparison size dimensions are no bigger than this size's maximum
if (largest.width <= this.max && largest.height <= this.max)
{ return this.setDimensions(largest.width, largest.height); }
// Else
var longerSide = Math.max(largest.width, largest.height);
var newWidth = Math.round(this.max * (largest.width/longerSide));
var newHeight = Math.round(this.max * (largest.height/longerSide));
return this.setDimensions(newWidth, newHeight);
},
// Get the image src for this size
// Optional arg: forDownload [boolean], default: false (returns src for the image download version)
getSrc: function(){
// If essential info is not known, then return null
if (!this.extension) { return null; }
// Check forDownload flag
if (arguments.length >0)
{ var suffix = (arguments[0]) ? this.suffix + '_d' : this.suffix; }
else
{ var suffix = this.suffix; }
return Flickr.imgRoot + this.photo.server + '/' + this.photo.id + '_' + this.photo.secret + suffix + this.extension;
},
// Get an image element for this size
getImg: function(){
// Get the image src
var src = this.getSrc();
if (!src) { return null; }
// Create a new image element and set attributes
var img = Object.extend(cE('img'), {
src: src,
alt: this.photo.getTitle(),
title: this.photo.getTitle()
});
if (this.width) { img.width = this.width; }
if (this.height) { img.height = this.height; }
return img;
},
// Get HTML tag for the image element
getImgHTML: function(){
// Get the image src
var src = this.getSrc();
if (!src) { return null; }
// Get attributes for tag
var width = (this.width) ? ' width="' + this.width + '"' : '';
var height = (this.height) ? ' height="' + this.height + '"' : '';
var title = ' title="' + this.photo.getTitle() + '"';
var alt = ' alt="' + this.photo.getTitle() + '"';
return '<img src="' + src + '"' + title + alt + width + height + ' />';
},
// Get an image element, within an anchor element for this size
getImgAnchor: function(){
var href = this.photo.getPhotopageUrl();
var img = this.getImg();
if (!href || !img) { return null; }
var a = cE('a');
a.href = href;
return a.appendChild(img);
},
// Get HTML tags for image within an anchor
getImgAnchorHTML: function(){
var href = this.photo.getPhotopageUrl();
var imgHTML = this.getImgHTML();
if (!href || !imgHTML) { return null; }
return '<a href="' + href + '" title="' + this.photo.getTitle() +'">' + imgHTML + '</a>';
},
// Get BB Code for image within an anchor
getImgAnchorBBCode: function(){
// Get the image src
var src = this.getSrc();
var href = this.photo.getPhotopageUrl();
if (!href || !src) { return null; }
return '[url=' + href + '][img]' + src + '[/img][/url]';
},
// Get the url for the AllSizes page for this size
getAllSizesUrl: function(){
return Flickr.siteRoot + 'photo_zoom.gne?id=' + this.photo.id + '&size=' + this.id;
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Add Sizes object to Photo prototype
Object.extend(Photo.prototype, {
sizes: {
// Specific Size Objects as properties of the Sizes Object
sq:new Size({id:'sq',label:'Square', suffix:'_s', max:75, width:75, height:75, setDimensions:function(){return true;}}),
t: new Size({id:'t', label:'Thumbnail', suffix:'_t', max:100}),
s: new Size({id:'s', label:'Small', suffix:'_m', max:240}),
m: new Size({id:'m', label:'Medium', suffix:'', max:500}),
l: new Size({id:'l', label:'Large', suffix:'_b', max:1024}),
o: new Size({id:'o', label:'Original', suffix:'_o', max:Infinity, extension:null, rotated:null}),
// Original sizes have unlimited length. Their file extension may be png, gif or jpg, & they may be rotated
// Methods of the Sizes object
// Return array of srcs known to exist
getKnownSrcs: function(){
return $A(this).getBy('isKnownSrc', true, true);
},
// Return array of known sizes
getKnownSizes: function(){
return $A(this).getBy('isKnownSize', true, true);
},
// Return array of sizes that are complete
getComplete: function(){
return $A(this).getBy('isComplete', true, true);
},
getLargestKnownSrc: function(){
var knownSrcs = this.getKnownSrcs();
return (knownSrcs) ? knownSrcs[knownSrcs.length-1] : null;
},
getLargestKnownSize: function(){
var knownSizes = this.getKnownSizes();
return (knownSizes) ? knownSizes[knownSizes.length-1] : null;
},
getLargestComplete: function(){
var complete = this.getComplete();
return (complete) ? complete[complete.length-1] : null;
},
// SetDimensions for each size smaller than the largest known sizes
setDimensions: function(){
var sizes = $A(this);
for (var i=0; i<sizes.length; i++)
{ sizes[i].setDimensions(); }
}
}
});
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Add photo property to each size on initialisation of a photo object
Photo.prototype.init.register(function(){
var sizes = $A(this.sizes);
for (var i=0; i < sizes.length; i++)
{ sizes[i].photo = this; }
});
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// ADDITIONAL SIZES METHODS FOR ALLSIZES SCRIPT (kept separate for portability)
// PHOTO SIZES OBJECT
Object.extend(Photo.prototype.sizes, {
// Get size and extension of original size
getAllSizes: function(callback){
// Make objects available for innerCallback
var that = this;
var thisFunc = arguments.callee;
// If original size is already known, then return it
if (this.o.isComplete())
{ callback(this.o); return; }
// Create array for multiple callbacks
if (typeof thisFunc.callbacks == 'undefined')
{ thisFunc.callbacks = []; }
// Add callback to array
thisFunc.callbacks.push(callback);
// Function to call all callacks, upon response
function callbackAll(size){
// Check if user rotated the original photo
if(that.m.isKnownSize()){
// Determine if medium and original are landscape aspect
var isLandscapeM = ((that.m.width / that.m.height) >= 1);
var isLandscapeO = ((size.width / size.height) >= 1);
// If they are not the same aspect, then o has been rotated
that.o.rotated = (isLandscapeM != isLandscapeO) ? true : false;
}
// Extend Photo Size object with new-found properties
Object.extend(that[size.id], size);
that.setDimensions();
while (thisFunc.callbacks.length > 0)
{
var callback = thisFunc.callbacks.shift();
callback(that.o);
}
}
// innerCallback for processing responses
function innerCallback(size){
switch (size){
case false:
that.getOriginalViaDownload(callbackAll);
break;
case null:
break;
default:
if (size.id != 'o')
{ that.getOriginalViaDownload(callbackAll); }
else
{ callbackAll(size); }
break;
}
}
// For pre-existing buttons, try the AllSizes page over HTTP
if (AllSizes.buttonExistedBeforeGM)
{ this.getLargestViaHttp(innerCallback); }
// For created buttons, try the API
else
{ this.getLargestViaApi(innerCallback); }
},
getLargestViaApi: function(callback){
var onload = function(rsp) {
if (!rsp)
{ callback(false); return; }
var largest = rsp.sizes.size[rsp.sizes.size.length-1];
var size = {
id: largest.source.slice(-5,-4),
extension: largest.source.slice(-4),
width: largest.width,
height: largest.height
};
callback(size);
};
Api.callMethod('photos.getSizes', {photo_id: this.o.photo.id}, onload);
},
getLargestViaHttp: function(callback){
var url = 'http://www.flickr.com/photo_zoom.gne?id=' + this.o.photo.id + '&size=o';
var onload = function(response) {
if (!response)
{ callback(false); return; }
var size = {};
var html = cE('Code');
html.innerHTML = response.responseText;
var spans = html.getElementsByTagName('span');
for (var i=spans.length-1; i>=0; i--)
{
if (spans[i].className == 'Dimensions')
{
var dims = spans[i].firstChild.nodeValue.slice(1,-1).split(' x ');
size.width = dims[0];
size.height = dims[1];
break;
}
}
var images = html.getElementsByTagName('img');
for (var i=0; i < images.length; i++)
{
var suffix = images[i].src.replace(Flickr.regex.photoSrc, '$6');
if (suffix.length <= 6)
{
size.extension = suffix.slice(-4);
size.id = (suffix.slice(0,2) == '_o') ? 'o' : 'l';
callback(size);
return;
}
}
return false;
};
ajaxRequest(url, onload);
},
// Returns width, height & extension for original size
getOriginalViaDownload: function(callback){
var o = this.o;
var thisFunc = arguments.callee;
// File extension possibilities
var extensions = ['.jpg', '.png', '.gif'];
// Current extension to test
var extId = (arguments.length > 1) ? arguments[1] : 0;
if (extId >= extensions.length)
{ callback(false); return; }
// Unavailable image properties (will be downloaded if wrong extension used)
var unavail = { width: 500, height: 375, extension: '.gif' };
// Set image src for the test extension
var src = Flickr.imgRoot + o.photo.server + '/' + o.photo.id + '_' + o.photo.secret + o.suffix + extensions[extId];
// Whether to download image node (default) or headers
var viaNode = (arguments.length > 2) ? arguments[2] : true;
if (viaNode)
{
var img = createImg(src);
window.setTimeout(function(){ checkDimensions(img, evaluateImg); }, 10);
}
else
{ evaluateHeaders(src, callback); }
// +-+-+-+-+
function createImg(src){
var img = cE('img');
img.style.display = 'none';
document.body.appendChild(img);
img.src = src;
return img;
}
function destroyImg(img){
img.parentNode.removeChild(img);
img.src = '';
img = null;
}
function checkDimensions(img){
if (img.width == 0)
{
window.setTimeout(function(){ checkDimensions(img); }, 200);
return;
}
var size = { width:img.width, height:img.height };
destroyImg(img);
evaluateImg(size);
}
function evaluateImg(size){
// If size is same as unavailable image
if (size.width == unavail.width && size.height == unavail.height)
{
// If we haven't tried all extensions, then try again
if (extId < extensions.length-1)
{ thisFunc.call(o.photo.sizes, callback, extId+1); }
// Otherwise, size is same as unavail image and extension is unknown
else
{ thisFunc.call(o.photo.sizes, callback, 0, false); }
}
// Success! Return size object
else
{
size.id = o.id;
size.extension = extensions[extId];
callback(size);
}
}
// Get headers for image - only called if original has same size as unavailable image
function evaluateHeaders(src, callback){
var onload = function(response) {
// In case of error in getting AJAX response
if (response === false)
{ callback(false); return; }
// Get the mime-type
var mime = response.responseHeaders.match(/Content-Type:\simage\/(jpe?g|png|gif)/gi);
if (!mime)
{ callback(false); return; }
// Get the file extension
var extension = '.' + mime[0].slice(mime[0].lastIndexOf('/')+1);
if (extension == '.jpeg')
{ extension = '.jpg'; }
// If unsuccessful at first attempt
if (extension == unavail.extension && extId == 0)
{ thisFunc.call(o.photo.sizes, callback, extId+1, false); }
// Success!
else
{
var size = {
extension: extension,
width: unavail.width,
height: unavail.height
};
callback(size);
}
};
ajaxRequest(src, onload);
}
},
popUp: function(){
return this[this.popUp.selectedSize].popUp();
}
});
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Photo.prototype.sizes.popUp.selectedSize = Settings.getValue('defaultSize');
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// SIZE PROTOTYPE
Object.extend(Size.prototype, {
getCode: function(){
var codeType = GM_getValue('codeType');
return (codeType == 'bbCode') ? this.getImgAnchorBBCode() : this.getImgAnchorHTML();
},
download: function(){
var that = this;
function callback(o){
if (that.id == 'l' && !that.exists())
{ that = that.photo.sizes.o; }
window.location.href = that.getSrc(true);
EventLogger.keysDown = '';
}
this.photo.sizes.getAllSizes(callback);
},
copyToClipboard: function(){
var that = this;
function callback(o){
if (that.id == 'l' && !that.exists())
{ that = that.photo.sizes.o; }
copyToClipboard(that.getCode());
}
this.photo.sizes.getAllSizes(callback);
},
view: function(){
var that = this;
function callback(o){
if (that.id == 'l' && !that.exists())
{ that = that.photo.sizes.o; }
window.location.href = that.getSrc();
}
this.photo.sizes.getAllSizes(callback);
},
popUp: function(){
// Check if popUp was already created
var popUp = PopUp.getById('Code');
// Update the selected size property
var sizesObj = this.photo.sizes;
sizesObj.popUp.selectedSize = this.id;
// If popUp not yet created
if (!popUp)
{
popUp = new PopUp('Code');
// Shortcut icons
var icons = popUp.main.appendChild(cE('span'));
icons.className = 'popUpIcons';
// Download button
var download = icons.appendChild(cE('img'));
download.src = EncodedImages.save;
download.alt = 'Download Image';
download.title = 'Download Image';
download.addEventListener('click', function(){
sizesObj[sizesObj.popUp.selectedSize].download();
}, false);
// Copy button
var copy = icons.appendChild(cE('img'));
copy.src = EncodedImages.copy;
copy.alt = 'Copy Code to Clipboard';
copy.title = 'Copy Code to Clipboard';
copy.addEventListener('click', function(){
sizesObj[sizesObj.popUp.selectedSize].copyToClipboard();
}, false);
// View button
var view = icons.appendChild(cE('a'));
var img = view.appendChild(cE('img'));
img.src = EncodedImages.view;
img.alt = 'View Image';
img.title = 'View Image';
view.addEventListener('mouseover', function(e){
e.currentTarget.href = sizesObj[sizesObj.popUp.selectedSize].getSrc();
}, false);
// BBCode/HTML button
var code = icons.appendChild(cE('img'));
var codeType = GM_getValue('codeType');
if (codeType == 'bbCode')
{
code.src = EncodedImages.html;
code.alt = 'to HTML';
}
else
{
code.src = EncodedImages.bbCode;
code.alt = 'to BB Code';
}
code.title = code.alt;
code.addEventListener('click', function(e){
// Change alt and title of button
if (e.currentTarget.alt == 'to BB Code')
{
e.currentTarget.alt = 'to HTML';
e.currentTarget.src = EncodedImages.html;
GM_setValue('codeType', 'bbCode');
}
else
{
e.currentTarget.alt = 'to BB Code';
e.currentTarget.src = EncodedImages.bbCode;
GM_setValue('codeType', 'html');
}
e.currentTarget.title = e.currentTarget.alt;
// Update textarea
popUp.updateTextarea();
}, false);
// AllSizes button
var img = cE('img');
img.alt = 'AllSizes Page';
img.src = EncodedImages.allsizesIcon;
if (AllSizes.buttonExistedBeforeGM)
{
var allSizes = icons.appendChild(cE('a'));
allSizes.appendChild(img);
allSizes.addEventListener('mouseover', function(e){
e.currentTarget.href = sizesObj[sizesObj.popUp.selectedSize].getAllSizesUrl();
}, false);
}
else
{
img.alt += ' Not Available for this Photo';
img.className = 'choiceDisabled';
var allSizes = img;
}
img.title = img.alt;
icons.appendChild(allSizes);
// Size Menu
var sizeMenu = popUp.main.appendChild(cE('p'));
sizeMenu.className = 'popUpMenu';
// Function to open popUp for clicked link
var onclickSizeMenuLink = function(e){
var id = e.currentTarget.getAttribute('sizeId');
sizesObj[id].popUp();
};
// Go through each size, adding to the menu
var sizes = $A(this.photo.sizes);
for (var i=0; i<sizes.length; i++)
{
if (sizes[i].exists() === false)
{ continue; }
var a = sizeMenu.appendChild(cE('a', sizes[i].label));
a.title = sizes[i].label + ' size';
a.setAttribute('sizeId' , sizes[i].id);
a.className = (sizes[i].id == this.id) ? 'navCurrent' : '';
// Onclick handler for sizesMenu
a.addEventListener('click', onclickSizeMenuLink, false);
if (i < sizes.length -1)
{
var divider = sizeMenu.appendChild(cE('span', ' | '));
divider.className = 'divider';
}
}
popUp.sizeMenu = sizeMenu;
// Add textarea
popUp.ta = popUp.addTextarea();
// Function to update the textarea
popUp.updateTextarea = function(){
var notYetMsg = "Hold on, I'm comin'...";
var size = sizesObj[sizesObj.popUp.selectedSize];
if (!size.isComplete())
{ this.ta.value = notYetMsg; }
else
{ this.ta.value = size.getCode(); }
};
// Add CSS styles to anchor links in sizesMenu
popUp.updateSizeMenu = function(){
var a = this.sizeMenu.getElementsByTagName('a');
for(var i=0; i<a.length; i++)
{ a[i].className = (a[i].getAttribute('sizeId') == sizesObj.popUp.selectedSize) ? 'navCurrent' : ''; }
}
// Add license
popUp.main.appendChild(cE('h3', 'License'));
var license = popUp.main.appendChild(cE('p'));
license.appendChild(this.photo.license.getAnchor());
// Permission
popUp.main.appendChild(cE('h3', 'Permission'));
// Sendmail Link
var sendmail = popUp.main.appendChild(cE('p', "Contact the owner if you don't have permission to use this photo:"));
var ul = sendmail.appendChild(cE('ul'));
var sendmailLink = ul.appendChild(cE('li')).appendChild(cE('a', 'Send a FlickrMail'));
sendmailLink.href = this.photo.owner.getSendmailUrl();
// Comment Link - first check if comments are enabled for this photo
var commentDiv = document.getElementById('DiscussPhoto');
if (commentDiv.getElementsByTagName('textarea').length > 0)
{
var commentLink = ul.appendChild(cE('li')).appendChild(cE('a', 'Add a Comment'));
commentLink.href = '#DiscussPhoto';
commentLink.addEventListener('click', function(e){
popUp.close();
window.setTimeout(function(){
var commentDiv = document.getElementById('DiscussPhoto');
var ta = commentDiv.getElementsByTagName('textarea')[0];
// Focus the textarea element
ta.focus();
// Move cursor to start (other GM scripts may have added text)
if (ta.selectionStart)
{
ta.selectionStart = 0;
ta.selectionEnd = 0;
}
}, 5);
}, false);
}
// Get original sizes
if (!sizesObj.o.isComplete())
{
// If successful, the original size object is returned
function callback(o){
if (o) {
// If large size doesn't exist
if (!o.photo.sizes.l.exists()) {
// Remove anchor & divider from size menu
for (var i=0; i<sizeMenu.childNodes.length; i++)
{
var a = sizeMenu.childNodes[i];
if (a.getAttribute('sizeId') == 'l')
{
sizeMenu.removeChild(a.nextSibling);
sizeMenu.removeChild(a);
break;
}
}
// If Large size is selected, then move to original
if (o.photo.sizes.popUp.selectedSize == 'l')
{ o.photo.sizes.popUp.selectedSize = 'o'; }
}
// Refresh popUp
popUp.updateTextarea();
popUp.updateSizeMenu();
}
}
sizesObj.getAllSizes(callback);
}
}
// Update the textarea
popUp.updateTextarea();
popUp.updateSizeMenu();
// Open popUp and return
return popUp.open();
}
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// PopUp OBJECT
// Usage: var p = new PopUp(); p.open();
// Optional arg: node to insert popUp before.
function PopUp(){
var popUp = Object.extend(cE('div'), this);
// Get popUp id
if (arguments.length > 0)
{ popUp.id = 'PopUp_' + arguments[0]; }
// Initialise popUp
popUp.init();
return popUp;
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
PopUp.prototype = {
init: function(insertNode){
var that = this;
this.className = 'PopUp';
// Get node to insert into document
var defaultInsertNode = getElementsByCssClass('div', 'photoImgDiv')[0];
var insertNode = (arguments.length > 1) ? arguments[1] : defaultInsertNode;
// Close Button
var closeBtn = this.appendChild(cE('a'));
closeBtn.title = 'Close';
closeBtn.className = 'closeBtn';
var closeBtnImg = closeBtn.appendChild(cE('img'));
closeBtnImg.src = EncodedImages.closeWindow;
closeBtnImg.alt = 'Close';
closeBtn.addEventListener('click', function(){
that.close();
}, true);
// H1 Header
var headerText = UserScript.header.replace(/^(.[^A-Z]*)([A-Z].*)$/, '$1~$2').split("~");
if (headerText.length > 0) {
this.header = this.appendChild(cE('h1'));
var strong = this.header.appendChild(cE('strong'));
var pinkText = strong.appendChild(cE('span', headerText[0]));
pinkText.className = 'flickrPink';
}
if (headerText.length > 1) {
var blueText = strong.appendChild(cE('span', headerText[1]));
blueText.className = 'flickrBlue';
}
// H2 Title
if (typeof this.id != 'undefined')
{ this.appendChild(cE('h2', this.id.slice('PopUp_'.length))); }
// Main div
this.main = this.appendChild(cE('div'));
this.main.className = 'popUpMain';
// Menu
this.menu = this.appendChild(PopUp.getMenu(this.id.slice('PopUp_'.length)));
// Add this popUp to PopUp inventory
PopUp.inventory.push(this);
// Insert PopUp styles into stylesheet
PopUp.insertStyles();
// Insert popUp div into document
insertNode.parentNode.insertBefore(this, insertNode);
}, // end init
// Create Textarea
addTextarea: function(){
ta = this.main.appendChild(cE('textarea'));
ta.value = (arguments.length > 0) ? arguments[0] : '';
ta.wrap = 'virtual';
ta.addEventListener('focus', function(){ this.select(); }, true);
return ta;
},
open: function(){
// Close other popUps
for (var i=0; i<PopUp.inventory.length; i++)
{ PopUp.inventory[i].close(); }
this.style.display = 'block';
return this;
},
close: function(){
this.style.display = 'none';
return this;
},
remove: function(){
this.parentNode.removeChild(this);
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Extend PopUp Object
Object.extend(PopUp, {
inventory: [],
getById: function(id){
return this.inventory.getById('PopUp_' + id);
},
menu: [],
addToMenu: function(){
for (var i=0; i<arguments.length; i++)
{ this.menu.push(arguments[i]); }
},
getMenu: function(id){
var that = PopUp;
var menuDiv = cE('div');
menuDiv.className = 'popUpMenu popUpFooter';
for (var i=0; i<that.menu.length; i++)
{
// Create anchor link
var a = menuDiv.appendChild(cE('a', that.menu[i].id));
a.title = that.menu[i].id;
// Add CSS class to anchor link
a.className = (that.menu[i].id == id) ? 'navCurrent' : '';
// add onclick listener to anchor
var openPopUp = function(e){
var id = e.currentTarget.title;
var popUp = PopUp.getById(id);
if (!popUp)
{ popUp = that.menu.getById(id).constructor(); }
popUp.open();
}
a.addEventListener('click', openPopUp, false);
// Add divider
if (i < that.menu.length -1)
{
var divider = menuDiv.appendChild(cE('span', ' | '));
divider.className = 'divider';
}
}
return menuDiv;
},
// Insert styles into stylesheet (once per script execution)
insertStyles: function(){
// Check if already inserted
if (typeof arguments.callee.inserted != 'undefined')
{ return; }
insertStyles(this.styles);
arguments.callee.inserted = true;
},
// CSS Styles for PopUp
styles: [
// MAIN STYLE
'.PopUp { position:absolute; background-color:#edf3f7; width:470px; padding:1em 15px 1.4em; z-index:99999; display:none; font-size:0.9em; border-left:1px solid #e0e7f0; border-top:1px solid #e0e7f0; border-right:1px solid #d3dae3; border-bottom:1px solid #d3dae3; color:#666; }',
// MAIN ELEMENTS
'.PopUp h1, .PopUp h2, .PopUp h3 { font-weight:bold; margin:0; color:#b0b7c0; }',
'.PopUp h1 { font-size: 1.1em; padding:0; line-height:1.1em; }',
'.PopUp h2 { font-size:1.5em; padding:1em 0 0; border-top:1px dotted #dce3ec; margin-bottom:0.5em; }',
'.PopUp h3 { font-size:1.1em; padding:1.5em 0 0; }',
'.PopUp p { margin:0.2em 0 0.5em; padding:0; }',
'.PopUp img { margin-bottom:-2px; }',
'.PopUp a, .PopUp a:link, .PopUp a:active, .PopUp a:visited { cursor:pointer; color:' +flickrBlue+ '; text-decoration:none; background-color:transparent; }',
'.PopUp a:hover { color:white; background-color:' +flickrBlue+ '; }',
'.PopUp a.navCurrent { color:' +flickrPink+ '; }',
'.PopUp a.navCurrent:hover { color:' +flickrPink+ '; background-color:transparent; cursor:default; }',
// LISTS
'.PopUp ul { padding:0; margin:0.4em 0 0.5em 1.6em; list-style-type:circle; }',
'.PopUp li { padding:0; margin:0.1em 0; }',
// FORMS
'.PopUp textarea, .PopUp input, .PopUp select { border-left:1px solid #b3bac3; border-top:1px solid #b3bac3; border-right:1px solid #d0d7e0; border-bottom:1px solid #d0d7e0; }',
'.PopUp textarea { width:100%; height:7em; margin-top:0.5em; padding:5px; background-color:#fff; }',
'.PopUp label { display:block; font-size:0.9em; }',
'.PopUp input[type="text"]:focus, .PopUp textarea:focus, .PopUp select:focus { background-color:#ffffd3; }',
'.PopUp input[type="button"] { margin:1em 0.5em 0 0; }',
'.PopUp option { border-bottom:1px dotted #dce3ec; }',
'.PopUp form p { clear:both; margin-top:0.8em; }',
'.PopUp form div.settingsGroup { clear:both; margin-top:1.5em; }',
'.PopUp form p.formButtons { padding-left:12em; }',
'.PopUp form div.settingsGroup p, .PopUp form div.settingsGroup h5, .PopUp form div.settingsGroup ul { clear:none; padding:0; margin:0 1em 0.6em 12em; }',
'.PopUp form div.settingsGroup h4 { clear:none; padding:0; margin:0 0 0.6em 11em; }',
'.PopUp form div.settingsGroup ul { padding-left:3.5em; }',
'.PopUp form div.settingsGroup p.miniGroup { float:left; }',
'.PopUp form div.settingsGroup h3 + p.miniGroup { margin-left:0; }',
'.PopUp form div.settingsGroup h3 { width:11em; text-align:right; padding:0; margin:0 1em 0 0; float:left; }',
// TABLES
'.PopUp table { border:none; }',
'.PopUp td { color:#666; padding-right:0.8em; border:none; }',
// CLASS SELECTORS
'.PopUp .flickrPink { color:' +flickrPink+ '; }',
'.PopUp .flickrBlue { color:' +flickrBlue+ '; }',
'.PopUp .indented { margin-left:2em; }',
'.PopUp .closeBtn { float:right; }',
'.PopUp .closeBtn img { margin:0; padding:0; width:13px; height:13px; border:none; background-color:#edf3f7; }',
'.PopUp .closeBtn img:hover { opacity:0.8; }',
'.PopUp .popUpMenu { font-size:0.9em; }',
'.PopUp .popUpMain { min-height:26em; max-height:26em; overflow:auto; text-align:justify; padding-right:15px; margin-right:-15px; }',
'.PopUp .popUpMain.fullLength { max-height:none; }',
'.PopUp .popUpFooter { border-top:1px dotted #dce3ec; padding-top:0.7em; margin-top:2em; }',
'.PopUp .divider { color:#999; font-size:0.9em; }',
// ICON BUTTONS
'.PopUp .popUpIcons { float:right; }',
'.PopUp .popUpIcons a, .PopUp .popUpIcons a:hover, .PopUp .popUpIcons a:active, .PopUp .popUpIcons a:visited { background-color:transparent; }',
'.PopUp .popUpIcons img { cursor:pointer; margin-left:0.5em; opacity:0.7; }',
'.PopUp .popUpIcons img:hover { opacity:1; }',
'.PopUp .popUpIcons img.choiceDisabled, .PopUp .popUpIcons img.choiceDisabled:hover { opacity:0.5; cursor:default; }'
],
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
var Page = {
photoPage: {
id: 'photoPage',
regex: Flickr.regex.photoPageUrl,
cache: {},
getPhotoId: function(){
return window.location.href.replace(this.regex, '$5');
},
getPhotoImg: function(){
var container = document.getElementById('photoImgDiv' + this.getPhotoId());
var photo = getFlickrImg('photo', container);
photo.src = photo.src.replace(Flickr.regex.photoSrc, '$1');
return photo;
},
getTitle: function(){
var titleDiv = document.getElementById('title_div' + this.getPhotoId());
// Find first text node child of title div and return contents
for (var i=0; i<titleDiv.childNodes.length; i++)
{
var node = titleDiv.childNodes[i];
if (node.nodeName == '#text')
{ return node.nodeValue; }
}
return false;
},
getOwner: function(){
var userUrl = window.location.href.replace(this.regex, '$4');
// Find widget div that contains owner info
var widgets = getElementsByCssClass('div', 'Widget');
for (var i=0; i<widgets.length; i++)
{
var widget = widgets[i];
var buddyicon = getFlickrImg('buddyicon', widget);
if (!buddyicon) { continue; }
var owner = new Person(userUrl);
owner.nsid = Person.getNsidFromBuddyiconSrc(buddyicon.src);
// Get username
var anchors = widget.getElementsByTagName('a');
for (var j=anchors.length-1; j>=0; j--)
{
if (anchors[j].title.indexOf('Link to ') !== -1)
{
owner.username = anchors[j].title.replace(/Link to (.*)'s? photos/, '$1');
break;
}
}
return owner;
}
return null;
},
getLicense: function(){
// Find span with class 'license' (only one on original Flickr page, but may be changed by other scripts)
var spans = getElementsByCssClass('span', 'license');
for (var i=0; i<spans.length; i++)
{
// Find childnode span containing collection of license info (only one on original Flickr page)
var innerSpans = spans[i].getElementsByTagName('span');
for (var j=0; j<innerSpans.length; j++)
{
// Find childnodes containing specific license info
var span = innerSpans[j];
for (var k=0; k<span.childNodes.length; k++)
{
var node = span.childNodes[k];
// Found a text node! Is it a copyright symbol?
if (node.nodeName == '#text')
{
for (var l=0; l<node.nodeValue.length; l++)
{
if (node.nodeValue.charCodeAt(l) == 169) // ý
{ return Photo.licenses[0]; }
}
}
// Then, is it Creative Commons?
// If this isn't an anchor element, then go to next childNode
if (node.nodeName.toLowerCase() != 'a')
{ continue; }
// See if it is info about a CC license
var license = Photo.licenses.getBy('url', node.href);
if (license) { return license; }
// If not, got through rest of childNodes
}
}
}
return null;
},
getPhoto: function(){
if (!this.cache.photo){
var photo = Photo.fromImg(this.getPhotoImg());
photo.title = this.getTitle();
photo.owner = this.getOwner();
photo.license = this.getLicense();
// Check if photo is owned by viewing user
var a = $A(document.getElementById('candy_nav_menu_search').getElementsByTagName('a')).getBy('title', 'Your Photos');
if (a && photo.owner.nsid)
{
var matchNsid = a.getAttribute('onclick').match(/_do_header_search\('(\d+@N00)'/);
var nsid = (matchNsid) ? matchNsid[1] : null;
photo.isUser = (nsid == photo.owner.nsid) ? true : false;
}
else
{ photo.isUser = null; }
this.cache.photo = photo;
}
return this.cache.photo;
},
init: function(){
// Add popUps to PopUp menu
PopUp.addToMenu(
{
id:'Code',
constructor:function(){
return Page.getCurrentPage().getPhoto().sizes.popUp();
}
},
{
id:'Settings',
constructor:Settings.popUp
},
{
id:'Shortcuts',
constructor:AllSizes.shortcuts
},
{
id:'Documentation',
constructor:AllSizes.documentation
},
{
id:'About',
constructor:AllSizes.about
}
);
return AllSizes.prepareButton();
}
},
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
allSizesPage: {
id: 'allSizesPage',
regex: Flickr.regex.allSizesPageUrl,
cache: {},
getPhotoId: function(){
return window.location.href.replace(this.regex, '$2');
},
getCurrentSize: function(){
return window.location.href.replace(this.regex, '$3');
},
getTitle: function(){
return new String(document.title.slice('Flickr Photo Download: '.length));
},
getOwner: function(){
var divs = getElementsByCssClass('div', 'Owner');
for (var i=0; i<divs.length; i++)
{
var div = divs[i];
var anchors = div.getElementsByTagName('a');
for (var j=anchors.length-1; j>=0; j--)
{
var a = anchors[j];
if (a.title.indexOf('Link to ') === -1)
{ continue; }
var userUrl = a.href.replace(/^.*\/([\w-_]*)\/$/, '$1');
var owner = new Person(userUrl);
// Get NSID
var buddyicon = getFlickrImg('buddyicon', div);
if (buddyicon)
{ owner.nsid = Person.getNsidFromBuddyiconSrc(buddyicon.src); }
owner.username = a.title.replace(/Link to (.*)'s? photos/, '$1');
return owner;
}
}
},
getPhotoImg: function(){
var photo = getFlickrImg('photo');
photo.src = photo.src.replace(Flickr.regex.photoSrc, '$1');
var dims = this.getDimensions();
photo.width = dims[0];
photo.height = dims[1];
return photo;
},
getDimensions: function(){
var elements = getElementsByCssClass('span', 'Dimensions');
// Cycle through each span found
for (var i=0; i<elements.length; i++)
{
// Find a sibling <strong> element. This is the current image size.
var el = elements[i];
if (el.parentNode.getElementsByTagName('strong').length > 0)
{
// If we have the right text node, then return array [width, height]
for (var j=0; j<el.childNodes.length; j++)
{
var tN = el.childNodes[j];
if (tN.nodeName == '#text' && tN.nodeValue.indexOf(' x ') !== -1)
{ return tN.nodeValue.slice(1, -1).split(' x '); }
}
}
}
},
getPhoto: function(){
if (!this.cache.photo){
var photo = Photo.fromImg(this.getPhotoImg());
photo.title = this.getTitle();
photo.owner = this.getOwner();
//photo.license = this.getLicense();
// Check if photo is owned by viewing user
var divs = getElementsByCssClass('div', 'Owner');
get_isUser:
for (var i=0; i<divs.length; i++)
{
var div = divs[i];
var anchors = div.getElementsByTagName('a');
for (var j=anchors.length-1; j>=0; j--)
{
var a = anchors[j];
for (var k=0; k<a.childNodes.length; k++)
{
var node = a.childNodes[k];
for (var l=0; l<node.childNodes.length; l++)
{
var tN = node.childNodes[l];
if (tN.nodeName != '#text')
{ continue; }
if (tN.nodeValue == 'You' || tN.nodeValue == photo.owner.username)
{
photo.isUser = (tN.nodeValue == 'You') ? true : false;
break get_isUser;
}
}
}
}
}
// Cache the photo for next time
this.cache.photo = photo;
}
return this.cache.photo;
},
// Change the HTML displayed for re-posting a photo
updateTextarea: function(){
var textareas = document.getElementsByTagName('textarea');
// Cycle through each textarea
// Other gm scripts may have added textareas, so we won't assume there's only one
for (var i=0; i<textareas.length; i++)
{
var ta = textareas[i];
// If there's no title attribute, then we're in the wrong textarea
if (ta.innerHTML.indexOf('title="Photo Sharing"') === -1)
{ continue; }
// Insert the HTML.
ta.value = this.getPhoto().sizes[this.getCurrentSize()].getCode();
return;
}
// If there's no textarea, then insert one!
if (textareas.length == 0)
{ this.addTextarea(); }
return true;
},
// Add a textarea box with the photo HTML, if not already displayed
addTextarea: function(){
// Get the p element with css class 'EndBar'
var elements = getElementsByCssClass('p', 'EndBar');
// If not found, return null
if (elements.length == 0)
{ return null; }
// Prepare the HTML to be inserted
var html = '<h3>To link to this photo on other websites you can either:</h3>';
html += '<p><strong>1.</strong> Copy and paste this HTML into your webpage:</p>';
html += '<p><textarea onFocus="this.select();" style="width: 520px; height:7em;"></textarea></p>';
html += '<p><strong>2.</strong> Grab the photo\'s URL:</p>';
html += '<p><input onFocus="this.select();" type="text" value="'+ this.getPhoto().sizes[this.getCurrentSize()].getSrc() +'" style="width: 520px;"></p>';
html += '<p><span style="background-color: #ffffcc"><strong>Remember!</strong></span> Flickr Terms of Service specify that if you post a Flickr photo on an external website, the photo must link back to its photo page. (So, use Option 1.)</p>';
// Create new node
var newNode = cE('div');
newNode.innerHTML = html;
// Add code to textarea
var ta = newNode.getElementsByTagName('textarea')[0];
ta.value = this.getPhoto().sizes[this.getCurrentSize()].getCode();
// Insert into document
elements[0].parentNode.insertBefore(newNode, elements[0]);
return true;
},
init: function(){
return this.updateTextarea();
}
},
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Find the first page object that matches
getCurrentPage: function(){
var pages = $A(this);
for (var i=0; i<pages.length; i++)
{
if (!pages[i].regex) { continue; }
if (window.location.href.match(pages[i].regex))
{ return pages[i]; }
}
return null;
}
}; // end Page object
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// DO STUFF!
// What type of page are we on?
var thisPage = Page.getCurrentPage();
// Don't know? Then return...
if (!thisPage)
{ return; }
// Check for script updates
UserScript.checkForUpdates();
// Always show AllSizes button?
// GM_setValue('alwaysShowButton', true);
// Initialise page and return
return thisPage.init();
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// Initialise required functions
function initScript(){
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// modified from prototype.js - http://prototype.conio.net - MIT-style license
Object.extend = function(destination, source) {
for (property in source)
{ destination[property] = source[property]; }
return destination;
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Convert object to array. Optional arg: propsToInclude [function] = returns boolean match of type
$A = function(iterable) {
if (!iterable) { return []; }
if (iterable.toArray)
{ return iterable.toArray(); }
if (arguments.length > 1)
{ propsToInclude = arguments[1]; }
else
{ var propsToInclude = function(prop){ return typeof prop == 'object'; }; }
var results = [];
for (property in iterable)
{
if (propsToInclude(iterable[property]))
{ results.push(iterable[property]); }
}
return results;
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// OBJECT EXTENSIONS
Object.extend(Array.prototype, {
// Search objects within an array for a specified property-value or method-result
// optional arg: asArray [boolean] - to return an array of objects. Default: false
getBy: function(property, value){
if (arguments.length > 2)
{
if (arguments[2])
{
var asArray = true;
var returnArray = [];
}
}
if (typeof asArray == 'undefined')
{ var asArray = false; }
for (var i=0; i<this.length; i++)
{
if (typeof this[i] != 'object')
{ continue; }
switch (typeof this[i][property]){
case 'undefined':
break;
case 'function':
if (this[i][property]() == value)
{
if (asArray) { returnArray.push(this[i]); }
else { return this[i]; }
}
break;
default:
if (this[i][property] == value)
{
if (asArray) { returnArray.push(this[i]); }
else { return this[i]; }
}
break;
}
}
if (asArray)
{ return (returnArray.length > 0) ? returnArray : null; }
else
{ return null; }
},
getById: function(id){
return this.getBy('id', id);
}
});
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// DOM API SHORTCUT FUNCTIONS
// createElement - optional arg: text contents
cE = function(nodeName){
var node = document.createElement(nodeName);
if (arguments.length > 1)
{
var text = arguments[1];
if (typeof text == 'string')
{ node.appendChild(cTN(text)); }
}
return node;
};
// createTextNode
cTN = function(text){
return document.createTextNode(text);
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Get elements from the document with a specific cssClass
getElementsByCssClass = function(tagName, cssClass){
// Construct empty array to return
var returnArray = [];
// Get divs in the document
var elements = document.getElementsByTagName(tagName);
// Cycle through elements
for (var i=0; i<elements.length; i++)
{
// Find the element with the css class
if (elements[i].getAttribute('class') == cssClass)
{ returnArray.push(elements[i]); }
}
// Return array
return returnArray;
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// CSS STYLES PALETTE
flickrBlue = '#0063dc';
flickrPink = '#ff0084';
// Add styles to node. arg: styles = object containing properties to apply to node.style
applyStyles = function(node, styles){
return Object.extend(node.style, styles);
};
// Insert rules into stylesheet - supply either a single rule as a string or an array of strings
insertStyles = function(styles){
// If single string supplied, convert to array
if (typeof styles == 'string')
{ styles = [styles]; }
var style = document.getElementsByTagName('head')[0].appendChild(cE('style'));
style.type = 'text/css';
style.appendChild(cTN(styles.join(' ')));
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Make a new AJAX request via xmlHTTP
ajaxRequest = function(url, callback){
GM_xmlhttpRequest({
method: 'GET',
url: url,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3',
'Accept': 'application/atom+xml,application/xml,text/xml,text/html',
},
onload: callback,
onerror: function(){ callback(false); }
});
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Get a Flickr photo or buddyicon image from an element/document.
// Arg: imgType = 'photo' or 'buddyicon'. Optional args: Element in which image is contained
getFlickrImg = function(imgType){
var regex;
switch (imgType){
case 'photo':
regex = Flickr.regex.photoSrc;
break;
case 'buddyicon':
regex = Flickr.regex.buddyiconSrc;
break;
default:
return null;
}
// Containing element
var container = (arguments.length > 1) ? arguments[1] : document;
// Find images in the document
var images = container.getElementsByTagName('img');
// Find the image src of the photo
for (var i=0; i<images.length; i++)
{
var src = images[i].getAttribute('src');
if (src.match(regex))
{ return images[i]; }
}
// If not found, return null
return null;
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Convert special characters to their HTML entities
convertSpecialChars = function(str){
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
copyToClipboard = function(text){
try
{ unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(error)
{ /* User cancellation */ return false; }
var component = Components.classes["@mozilla.org/widget/clipboard;1"];
var clipInst = component.createInstance(Components.interfaces.nsIClipboard);
var component = Components.classes["@mozilla.org/widget/transferable;1"];
var trans = component.createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
var component = Components.classes["@mozilla.org/supports-string;1"];
var supportStr = component.createInstance(Components.interfaces.nsISupportsString);
supportStr.data = text;
trans.setTransferData("text/unicode", supportStr, text.length*2);
var clipboard = Components.interfaces.nsIClipboard;
clipInst.setData(trans, null, clipboard.kGlobalClipboard);
return text;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// INITIALISE OBJECTS
Init = function(){};
Init.prototype = Object.extend([], {
// Pass object as argument to function
init: function(obj){
// Call each function in the init array
for(var i=0; i<this.length; i++)
{ this[i].call(obj); }
// Delete init object
obj.init = null;
},
register: Array.prototype.push
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EventLogger = {
clickTimeout: 200, // milliseconds till click expires
clicks: 0,
keysDown: '',
specialKeys: ['', 'c', 'd', 'v'],
hotKeys: ['', 'sq', 't', 's', 'm', 'l', 'o'],
charToKey: function(char){
return String.fromCharCode(char).toLowerCase();
},
isHotKey: function(){
var ev = EventLogger;
for (var i=0; i < ev.hotKeys.length; i++){
for (var j=0; j < ev.specialKeys.length; j++){
if (ev.specialKeys[j] + ev.hotKeys[i] == ev.keysDown)
{ return [ev.specialKeys[j], ev.hotKeys[i]]; }
}
}
return ['',''];
},
handle: function(e){
switch(e.type){
case 'keydown':
var key = EventLogger.charToKey(e.which);
return EventLogger.addKey(key);
break;
case 'keyup':
var key = EventLogger.charToKey(e.which);
return EventLogger.removeKey(key);
break;
case 'click':
return EventLogger.addClick();
break;
default:
return false;
break;
}
},
addClick: function(){
EventLogger.clicks ++;
window.setTimeout(EventLogger.removeClick, EventLogger.clickTimeout);
return EventLogger.clicks;
},
removeClick: function(){
//if (EventLogger.clicks > 0) { EventLogger.clicks --; }
// Temporary hack to prevent lags activating single-click before double-click executed
if (EventLogger.clicks == 1) { EventLogger.clicks --; }
return EventLogger.clicks;
},
addKey: function(key){
var k = EventLogger.keysDown;
// Prevent duplicate entries from holding down key
if (k.length > 0)
{ if (k[k.length-1] == key) { return k; } }
EventLogger.keysDown += key;
return EventLogger.keysDown;
},
removeKey: function(key){
for (var i=0; i < EventLogger.keysDown.length; i++)
{
if (EventLogger.keysDown[i] == key)
{
var prefix = (i>0) ? EventLogger.keysDown.slice(0, i) : '';
var suffix = (i<EventLogger.keysDown.length) ? EventLogger.keysDown.slice(i+1) : '';
EventLogger.keysDown = prefix + suffix;
return EventLogger.keysDown;
}
}
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Track keydown & keyup events
window.addEventListener("keydown", EventLogger.handle, true);
window.addEventListener("keyup", EventLogger.handle, true);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
AllSizes = {
buttonExistedBeforeGM: true,
prepareButton: function(){
var button = document.getElementById('photo_gne_button_zoom');
if (!button)
{
// Add button if not already there?
if (GM_getValue('alwaysShowButton') === true)
{
button = this.newButton();
this.buttonExistedBeforeGM = false;
}
else
{ return false; }
}
// Remove default click handlers
else
{
button.setAttribute('onmouseup', '');
// Add onclick listener to AllSizes button
button.addEventListener("click", this.onclick, false);
}
return button;
},
// AllSizes button has been clicked!
onclick: function(e){
// Determine if any hotKey was pressed
var keys = EventLogger.isHotKey();
var specialKey = keys[0];
var sizeId = keys[1];
// If so, serve relevant size. If not, then default size
var photo = Page.getCurrentPage().getPhoto();
var size = (sizeId != '') ? photo.sizes[sizeId] : photo.sizes[Settings.getValue('defaultSize')];
// If large size doesn't exist, then show original size
if (size.id == 'l' && photo.sizes.l.exists() === false)
{ size = photo.sizes.o; }
// Log click and test if 1 or 2 clicks were made
switch (EventLogger.handle(e)){
// Single click: Wait for second click. If it doesn't come, display popUp
case 1:
// Check if special controls are pressed
switch (specialKey){
case 'c': // Copy HTML to clipboard
size.copyToClipboard();
break;
case 'd': // Download image
size.download();
break;
case 'v': // View image
size.view();
break;
default: // Show PopUp
window.setTimeout(function(){
if (EventLogger.clicks == 1)
{ size.popUp(); }
}, EventLogger.clickTimeout -1);
break;
}
break;
// Doubleclick: go to AllSizes page
case 2:
// For buttons added by GM script
if (e.currentTarget.className == 'photo_gne_button_zoom_GM')
{ AllSizes.unavailable(); EventLogger.clicks = 0; }
// For buttons that already existed
else
{ window.location.href = size.getAllSizesUrl(); }
break;
}
},
// No button present! Add one...
newButton: function(){
var buttonBar = document.getElementById('button_bar');
if (!buttonBar)
{ window.setTimeout(arguments.callee, 500); return false; }
var button = buttonBar.appendChild(cE('img'));
Object.extend(button, {
id: 'photo_gne_button_zoom',
className: 'photo_gne_button_zoom_GM',
src: EncodedImages.zoomGrey,
alt: 'All Sizes',
width: 49,
height: 24
});
// CSS Styles
applyStyles(button, {
pointer: 'cursor',
border: 'none'
});
// Change image src for different mouse event states
var mouseOut = function(e){
e.currentTarget.src = EncodedImages.zoomGrey;
};
var mouseOver = function(e){
e.currentTarget.src = EncodedImages.zoomColour;
};
var mouseDown = function(e){
e.currentTarget.src = EncodedImages.zoomColourDown;
};
// Event behaviours for image rollovers
button.addEventListener("mouseover", mouseOver, false);
button.addEventListener("mouseout", mouseOut, false);
button.addEventListener("mousedown", mouseDown, false);
button.addEventListener("mouseup", mouseOver, false);
// Add onclick listener to AllSizes button
button.addEventListener("click", this.onclick, false);
return button;
},
unavailable: function(){
// Check if popUp was already created
var popUp = PopUp.getById('Unavailable');
if (!popUp)
{
popUp = new PopUp('Unavailable');
popUp.main.className = '';
var p = popUp.main.appendChild(cE('p', 'Sorry... The All Sizes page for this photo is unavailable :o('));
p.className = 'indented';
}
return popUp.open();
},
shortcuts: function(){
// Check if popUp was already created
var popUp = PopUp.getById('Shortcuts');
if (!popUp)
{
popUp = new PopUp('Shortcuts');
var div, innerHTML;
div = popUp.main.appendChild(cE('div'));
div.style.cssFloat = 'left';
innerHTML = "<h3>Size Keys</h3>";
innerHTML += "<table>";
innerHTML += "<tr><td>s + q</td><td>Square</td></tr>";
innerHTML += "<tr><td>t</td><td>Thumbnail</td></tr>";
innerHTML += "<tr><td>s</td><td>Small</td></tr>";
innerHTML += "<tr><td>m</td><td>Medium</td></tr>";
innerHTML += "<tr><td>l</td><td>Large</td></tr>";
innerHTML += "<tr><td>o</td><td>Original</td></tr>";
div.innerHTML = innerHTML;
div = popUp.main.appendChild(cE('div'));
div.style.cssFloat = 'right';
innerHTML = "<h3>Actions</h3>";
innerHTML += "<table>";
innerHTML += "<tr><td><em>(size key)</em> + Click</td><td>Code Pop-up</td></tr>";
innerHTML += "<tr><td>d + <em>(size key)</em> + Click</td><td>Download image</td></tr>";
innerHTML += "<tr><td>c + <em>(size key)</em> + Click</td><td>Copy code to clipboard</td></tr>";
innerHTML += "<tr><td>v + <em>(size key)</em> + Click</td><td>View image</td></tr>";
innerHTML += "<tr><td><em>(size key)</em> + DoubleClick</td><td>All Sizes Page</td></tr>";
div.innerHTML = innerHTML;
div = popUp.main.appendChild(cE('div'));
div.style.clear = 'both';
innerHTML = "<h3>Explanation</h3>";
innerHTML += "<p>Here, 'Click' means to click the AllSizes button. If you don't hold down a size key when you click, the default size will be used (as set in the Settings panel).</p>";
innerHTML += "<p><em>Examples:</em> Hold down 's' and hold down 'q', then click the button, to show the Code panel for the square size. Hold down 'd' and click, to download the default size.</p>";
div.innerHTML = innerHTML;
}
return popUp.open();
},
about: function(){
// Check if popUp was already created
var popUp = PopUp.getById('About');
if (!popUp)
{
popUp = new PopUp('About');
var div = popUp.main.appendChild(cE('div'));
div.className = 'indented';
var innerHTML = '';
innerHTML += '<p><strong>Script:</strong> ' + UserScript.title + '</p>';
innerHTML += '<p><strong>Version:</strong> ' + UserScript.version + '</p>';
innerHTML += '<p><strong>License:</strong> <a href="http://www.gnu.org/copyleft/gpl.html" title="GNU General Public License">GPL</a></p>';
innerHTML += '<p><strong>Discuss:</strong> <a href="' + UserScript.metaUrl + '" title="Discussion thread in the FlickrHacks group">Feedback, bug reports, feature requests</a></p>';
innerHTML += '<p style="margin-top:2.5em;"><img src="' + EncodedImages.premasagarBuddyicon + '" alt=""/> by <strong> ' + UserScript.author + '</strong>';
innerHTML += '<ul>';
innerHTML += '<li><a href="http://www.flickr.com/photos/dharmasphere/" title="Photostream on Flickr">Photos</a></li>';
innerHTML += '<li><a href="http://premasagar.com" title="Premasagar.com">Portfolio</a></li>';
innerHTML += '<li><a href="http://www.dharmasphere.org" title="Dharmasphere">Collective Blog</a></li>';
innerHTML += '</ul></p>';
div.innerHTML = innerHTML;
}
return popUp.open();
},
documentation: function(){
// Check if popUp was already created
var popUp = PopUp.getById('Documentation');
if (!popUp)
{
popUp = new PopUp('Documentation');
var innerHTML = '';
innerHTML += '<p>This script makes it easier to access all the sizes available for a photo - including the original size on non-Pro accounts.</p>';
innerHTML += '<p>AllSizes+ lets you copy the code required to post photos on Flickr discussion threads and other websites, as well as download images and more.</p>';
innerHTML += "<h3>Where's the All Sizes Page Gone?</h3>";
innerHTML += "<p>To see the standard All Sizes page for a photo, just <em>double-click</em> the AllSizes button in the toolbar above, or click the AllSizes icon in the Code panel of this pop-up.</p>";
innerHTML += '<h3>Shortcuts</h3>';
innerHTML += "<p>The Shortcuts panel gives an overview of the different shortcut keys you can hold down when clicking the AllSizes button. You do not <em>need</em> to use any of them, as all the functionality is available by clicking on the different buttons in the pop-up window. But they might save you some time :o)</p>";
innerHTML += '<h3>Delay for Large & Original Sizes</h3>';
innerHTML += "<p>When you first click the AllSizes button on a photopage, information about the image sizes is gathered. Details about the medium and smaller sizes are available immediately, but there is a short delay before the large and original sizes are known. This should only be a couple of seconds when using a broadband internet connection.</p>";
innerHTML += '<h3>Large Size is Not Always Available</h3>';
innerHTML += "<p>The large size is only available for photos that have an original size larger than 1280 pixels on either side. If you select the large size on a photo that has no large size available, then you will be given the original size instead.</p>";
innerHTML += '<h3>Original Size on the All Sizes Page</h3>';
innerHTML += "<p>This script does not (currently) change the size options available on the All Sizes page. On that page, you will not see an option for the original size if the photographer is not a Pro user. However, where the original is no more than 1280 pixels long, the original size image <em>will</em> be shown, but labelled as 'Large' or something else.</p>";
innerHTML += "<p>The Code pop-up created by this script always labels the images as they actually are - the original size is labelled 'Original' and the large size is labelled 'Large'.</p>";
innerHTML += '<h3>BB Code & HTML</h3>';
innerHTML += "<p><a href='http://en.wikipedia.org/wiki/Bb_code' title='Read about BB Code on Wikipedia'>BB Code</a> is a simplified markup language that is similar to HTML and is used on many forum websites.</p>";
innerHTML += "<p>You can click the 'to BB Code' button to convert the HTML code to BB Code. If you click it a second time, it will change back to HTML.</p>";
innerHTML += "<p>The last code type you viewed is remembered by the script. It will be used by the 'Copy to Clipboard' function to determine if you want to copy HTML or BB Code.</p>";
innerHTML += '<h3>Copy to Clipboard</h3>';
innerHTML += "<p>When you choose to copy the code to clipboard, you may see a security pop-up from the browser asking to allow the action. You can choose to allow or deny it, and to remember your decision in future.</p>";
innerHTML += "<p>If you choose to always allow the action, then you will not be prompted again for <em>any</em> clipboard actions on Flickr.com, including any Greasemonkey scripts for Flickr that you have installed.</p>";
innerHTML += "<p>This is a slight security risk, because a malicious script could read the contents of your clipboard and send it to an external site. However, this probably won't happen, because any malicious behaviour would likely be reported by other users before you choose to install the malicious script.</p>";
innerHTML += "<p>You may want to install the <a href='https://addons.mozilla.org/firefox/852/' title='AllowClipboard Helper extension'>AllowClipboard Helper</a> browser extension, to help you monitor which websites are allowed to access your clipboard.</p>";
innerHTML += "<p>If you find that the Copy to Clipboard function doesn't seem to work, then try enabling this in your Firefox browser:</p>";
innerHTML += "<ol>";
innerHTML += "<li>Open a new tab and go to the address about:config</li>";
innerHTML += "<li>In the 'Filter' bar, type <strong>signed.applets.codebase_principal_support</strong></li>";
innerHTML += "<li>Right-click on the line of text that appears and choose <em>Toggle</em>, so that the value goes from <em>false</em> to <em>true</em>.</li>";
innerHTML += "</ol>";
innerHTML += '<h3>Auto-Updates</h3>';
innerHTML += "<p>By default, the script will automatically check for a newer version once a day (or less often if you don't visit Flickr). If a newer version is available, it will ask you if you want to install it. You can turn off auto-updates in the Settings panel.</p>";
innerHTML += '<h3>Flickr Terms for Posting Photos</h3>';
innerHTML += "<p>The Flickr <a href='http://www.flickr.com/terms.gne'>Terms of Service</a> require that any photo you post on another site must include a link back to the photo's Flickr photopage. You can do this by simply using the code in the Code panel.</p>";
innerHTML += "<p>Note that, for private photos (including those marked as 'Friends' or 'Family'), the photopage will not be viewable by the general public, even if a posted image of it can be seen.</p>";
innerHTML += '<h3>All Rights Reserved</h3>';
innerHTML += "<p>If a photo is marked "© All Rights Reserved", then you <strong>must</strong> have permission from the owner to use it. This is required by international law and is common courtesy.</p>";
innerHTML += "<p>You may be legally allowed to re-post a copyrighted photo without specific permission, if it constitutes '<a href='http://en.wikipedia.org/wiki/Copyright#Fair_use_and_fair_dealing' title='Wikipedia article on Copyright & Fair Use'>Fair Use</a>', such as review and critique. Fair Use laws are sometimes vague and vary from country to country. It's best to just ask the owner.</p>";
innerHTML += '<h3>Creative Commons</h3>';
innerHTML += "<p>If a photo has a <img src='" + EncodedImages.creativeCommonsIcon + "' alt='Creative Commons' /> Creative Commons license, then you need to read the specific license to determine if you are allowed to use it without any further permission from the owner.</p>";
innerHTML += "<p>In general, if you are using a Creative Commons photo in a non-commercial context and you do not alter the image and you are attributing the owner by linking to the photopage, then you should be fine. More relaxed conditions may apply, depending on the specific license.</p>";
innerHTML += "<p>It is good to let the owner know that you've used their photo, even if not required, because people like to hear how others have used their work.</p>";
innerHTML += '<h3>Further Information</h3>';
innerHTML += "<p>If you have any questions, bug reports or suggestions for improvement, please leave a post in the <a href='" + UserScript.metaUrl +"'>discussion thread</a> for this script.</p>";
// Add HTML to popUp
popUp.main.innerHTML = innerHTML;
}
return popUp.open();
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// FLICKR API
Api = {
key : 'f11432d99cdf97246d9fe401e524831e',
urlRoot: 'http://api.flickr.com/services/rest/',
// e.g. callMethod('photos.getSizes', function(){}, {photo_id:34343232})
callMethod: function(method, parameters, callback){
var format = (arguments > 3) ? arguments[3] : 'json';
var url = this.urlRoot + '?method=flickr.' +method+ '&api_key=' +this.key+ '&format=' +format;
// Add parameters to url
if (parameters)
{
for (param in parameters)
{ url += '&' + param + '=' + parameters[param]; }
}
var handler = function(response){
if (!response)
{ callback(false); return; }
function jsonFlickrApi(rsp)
{ return rsp; }
eval('var rsp = ' + response.responseText + ';');
if (rsp.stat != 'ok')
{ callback(false); }
else
{ callback(rsp); }
};
ajaxRequest(url, handler);
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// SCRIPT SETTINGS
// Don't change these settings. Instead, click the 'AllSizes' button and click the 'Settings' link.
function SettingsGroup(initObj){
Object.extend(this, initObj);
}
SettingsGroup.prototype = {
type: 'settingsGroup',
settings: [],
save: function(){
for(var i=0; i<this.settings.length; i++)
{ this.settings[i].save(); }
return this.getValue();
},
toDefault: function(){
for(var i=0; i<this.settings.length; i++)
{ this.settings[i].toDefault(); }
return this.getValue();
},
getValue: function(){
var values = [];
for(var i=0; i<this.settings.length; i++)
{ values.push(this.settings[i].getValue()); }
return values;
},
setValue: function(){
for(var i=0; i<this.settings.length; i++)
{ this.settings[i].setValue(); }
return this.getValue();
},
show: function(){
var node = document.getElementById('settings_' + this.id);
if (node)
{ node.style.display = 'block'; }
else
{ this.display = true; }
},
hide: function(){
var node = document.getElementById('settings_' + this.id);
if (node)
{ node.style.display = 'none'; }
else
{ this.display = false; }
},
getUserControl: function(){
var node = cE('div');
node.className = 'settingsGroup';
// Node id
node.id = 'settings_' + this.id;
// Add header
if (this.label)
{ var h3 = node.appendChild(cE('h3', this.label)); }
for(var i=0; i<this.settings.length; i++)
{
var subNode = this.settings[i].getUserControl();
if (i < this.settings.length-1)
{
if ((this.settings[i].type == 'radio' && this.settings[i+1].type == 'radio') || (this.settings[i].type == 'checkbox' && this.settings[i+1].type == 'checkbox'))
{ subNode.className = 'miniGroup'; }
}
node.appendChild(subNode);
}
// Display or hide
if (typeof this.display != 'undefined')
{ node.style.display = (this.display) ? 'block' : 'none'; }
// Return node, when given either html or a node
function toNode(x){
var node = cE('div');
if (typeof x == 'function') {
return x();
} else if (typeof x == 'string') {
node.innerHTML = x;
}
return node;
}
// Add prefix
if (typeof this.prefix != 'undefined')
{ node.insertBefore(toNode(this.prefix), node.firstChild); }
// Add suffix
if (typeof this.suffix != 'undefined')
{ node.appendChild(toNode(this.suffix)); }
return node;
},
controlToDefault: function(){
for(var i=0; i<this.settings.length; i++)
{ this.settings[i].controlToDefault(); }
}
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// Setting object
function Setting(initObj){
Object.extend(this, initObj);
}
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Setting.prototype = {
// Get value, or if non-existent, get defaultValue & update value
getValue: function(){
// Check GM value for this setting
var userSetting = GM_getValue(this.id);
// If not found, update GM setting with default value
if (typeof userSetting == 'undefined')
{ userSetting = this.toDefault(); }
return userSetting;
},
// Save settings to GM in browser
setValue: function(value){
GM_setValue(this.id, value);
return value;
},
save: function(){
if (typeof this.tempValue != 'undefined')
{
this.setValue(this.tempValue);
delete(this.tempValue);
}
return this.getValue();
},
toDefault: function(){
this.tempValue = this.defaultValue;
return this.save();
},
show: function(){
var node = document.getElementById('settings_' + this.id);
if (node)
{ node.parentNode.style.display = 'block'; }
else
{ this.display = true; }
},
hide: function(){
var node = document.getElementById('settings_' + this.id);
if (node)
{ node.parentNode.style.display = 'none'; }
else
{ this.display = false; }
},
getUserControl: function(){
var that = this;
switch (this.type){
case 'text':
var node = Object.extend(cE('input'), {
type: 'text',
defaultValue: this.getValue()
});
// Add onchange event listener
node.addEventListener('change', function(e){
that.tempValue = e.currentTarget.value;
}, false);
// Add controlToDefault function
this.controlToDefault = function(){
node.defaultValue = this.toDefault();
node.value = node.defaultValue;
};
break;
case 'checkbox':
var node = Object.extend(cE('input'), {
type:'checkbox',
defaultChecked: (this.getValue() === true || this.getValue() == 'true')
});
// Add onchange event listener
node.addEventListener('change', function(e){
that.tempValue = e.currentTarget.checked;
}, false);
// Add controlToDefault function
this.controlToDefault = function(){
node.defaultChecked = this.toDefault();
node.checked = node.defaultChecked;
};
break;
case 'radio':
var node = Object.extend(cE('input'), {
type:'radio',
name:this.name,
defaultChecked: (this.getValue() === true || this.getValue() == 'true')
});
// Add onchange event listener
node.addEventListener('change', function(e){
var els = e.currentTarget.form.elements;
for (var i=0; i<els.length; i++)
{
if (els[i].name == e.currentTarget.name)
{ Settings.getById(els[i].id.slice('settings_'.length)).tempValue = els[i].checked; }
}
//that.tempValue = e.currentTarget.checked;
}, false);
// Add controlToDefault function
this.controlToDefault = function(){
node.defaultChecked = this.toDefault();
node.checked = node.defaultChecked;
};
break;
case 'select':
var node = cE('select');
for (var i=0; i<this.options.length; i++)
{
var op = cE('option');
op.value = this.options[i].value;
op.text = this.options[i].label;
op.defaultSelected = (this.getValue() == op.value);
node.appendChild(op);
}
// Add controlToDefault function
this.controlToDefault = function(){
var defaultOption = this.toDefault();
for (var i=0; i<node.options.length; i++)
{
var op = node.options[i]
op.defaultSelected = (op.value == defaultOption);
if (op.defaultSelected)
{ node.selectedIndex = i; }
}
};
// Add onchange event listener
node.addEventListener('change', function(e){
that.tempValue = e.currentTarget.options[e.currentTarget.selectedIndex].value;
}, false);
break;
case 'textarea':
var node = Object.extend(cE('textarea'), {
defaultValue: this.getValue()
});
// Add onchange event listener
node.addEventListener('change', function(e){
that.tempValue = e.currentTarget.value;
}, false);
// Add controlToDefault function
this.controlToDefault = function(){
node.defaultValue = this.toDefault();
node.value = node.defaultValue;
};
break;
default:
return null;
}
// Display or hide
if (typeof this.display != 'undefined')
{ node.style.display = (this.display) ? 'block' : 'none'; }
// Show / Hide SettingsGroups
function showHideSettings(){
for (var i=0; i<that.showSettings.length; i++)
{ Settings.getById(that.showSettings[i]).show(); }
for (var i=0; i<that.hideSettings.length; i++)
{ Settings.getById(that.hideSettings[i]).hide(); }
}
if (typeof this.showSettings != 'undefined' && typeof this.hideSettings != 'undefined')
{
node.addEventListener('change', showHideSettings, false);
if (this.getValue() === true)
{ showHideSettings(); }
}
// Set node id & name
node.id = 'settings_' + this.id;
if (node.name != '')
{ node.name = 'settings_' + node.name; }
// Enable buttons onchange
node.addEventListener('change', function(e){
var s = document.getElementById('settings_saveBtn');
s.disabled = false;
s.className = 'Butt';
var d = document.getElementById('settings_defaultBtn');
d.disabled = false;
d.className = 'Butt';
}, false);
// Add a label
var label = cE('label', this.label);
label.htmlFor = node.id;
// Enclose in p element
var p = cE('p');
p.appendChild(label);
p.appendChild(node);
// Add suffix
if (typeof this.suffix != 'undefined')
{
var div = cE('div');
div.appendChild(p);
var suffix = div.appendChild(cE('p'));
suffix.innerHTML = this.suffix;
p = div;
}
return p;
}
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Settings array
Settings = [
new SettingsGroup({
id: 'general',
label: 'General Settings',
settings:
[
new Setting ({
id:'defaultSize',
label:'Default Size',
defaultValue:'s',
type:'select',
options:
[
{ value:'sq', label:'Square' },
{ value:'t', label:'Thumbnail' },
{ value:'s', label:'Small' },
{ value:'m', label:'Medium' },
{ value:'l', label:'Large' },
{ value:'o', label:'Original' }
]
}),
new Setting ({
id:'untitledTitle',
label: 'Title for Untitled Photos',
defaultValue:'Untitled',
type:'text'
}),
new Setting ({
id:'checkforUpdates',
label: 'Auto-Update Script',
defaultValue:true,
type:'checkbox'
})
]
}),
/* new SettingsGroup({
id: 'mode',
label: 'Mode',
settings:
[
new Setting ({
id:'basicMode',
label:'Basic',
defaultValue:true,
type:'radio',
name:'mode',
showSettings:['addUsername'],
hideSettings:['customCode']
}),
new Setting ({
id:'customMode',
label:'Custom',
defaultValue:false,
type:'radio',
name:'mode',
showSettings:['customCode'],
hideSettings:['addUsername']
})
]
}), */
new SettingsGroup({
id: 'addUsername',
label: 'Add Username to Title',
settings:
[
new Setting ({
id:'addUsernameWhenYou',
label: 'On Your Photos',
defaultValue:true,
type:'checkbox'
}),
new Setting ({
id:'addUsernameToTitle',
label: "On Others' Photos",
defaultValue:true,
type:'checkbox'
}),
new Setting ({
id:'usernameFormat',
label: "Format, where '[user]' = the username",
defaultValue:' (by [user])',
type:'text'
})
]
})/* ,
new SettingsGroup({
id: 'customCode',
label: 'Custom Code',
settings:
[
new Setting ({
id:'customCodeWhenYou',
label: 'On Your Photos',
defaultValue:'<a href="{url}"><img src="{src}" alt="{title} (by {user})" title="{title} (by {user})" width="{width}" height="{height}" /></a>',
type:'textarea'
}),
new Setting ({
id:'customCodeWhenOthers',
label: "On Other's Photos",
defaultValue:'<a href="{url}"><img src="{src}" alt="{title} (by {user})" title="{title} (by {user})" width="{width}" height="{height}" /></a>',
type:'textarea'
}),
],
suffix: function(){
var wrapper = cE('div');
var p = wrapper.appendChild(cE('p'));
var showHide = p.appendChild(cE('a', '\u00bb Show Custom Tags'));
var node = wrapper.appendChild(cE('div'));
node.id = 'settings_custom_tags_info';
node.style.display = 'none';
showHide.addEventListener('click', function(e){
var node = document.getElementById('settings_custom_tags_info');
switch (node.style.display){
case 'none':
node.style.display = 'block';
e.currentTarget.firstChild.nodeValue = '\u00bb Hide Custom Tags';
break;
default:
node.style.display = 'none';
e.currentTarget.firstChild.nodeValue = '\u00bb Show Custom Tags';
break;
}
}, false);
var propValCollections = {
Photo: [
['id', 'Id'],
['title', 'Title'],
['url', 'Photopage url']
],
Image: [
['src', 'Source url'],
['width', 'Width'],
['height', 'Height'],
['size', 'Abbreviation for the size (sq, s, t, m, l, or o)']
],
Owner: [
['user', 'Username'],
['nsid', 'User id'],
['photosUrl', 'Photostream url'],
['profileUrl', 'Profile url']
]
};
for (coll in propValCollections) {
var h = node.appendChild(cE('h5', coll));
var propVals = propValCollections[coll];
if (propVals.length > 0) {
var ul = node.appendChild(cE('ul'));
for (var i=0; i<propVals.length; i++){
var li = ul.appendChild(cE('li', '{' + propVals[i][0] + '} = ' + propVals[i][1]));
}
}
}
return wrapper;
}
//suffix:"<h4>Custom Tags</h4><h5>Photo</h5><ul><li>{id} = Id</li><li>{title} = Title</li><li>{url} = Photopage url</li></ul><h5>Image</h5><ul><li>{src} = Source url</li><li>{width} = Width</li><li>{height} = Height</li><li>{size} = Abbreviation for the size (sq, s, t, m, l, or o)</li></ul><h5>Owner</h5><ul><li>{user} = Username</li><li>{nsid} = User id</li><li>{photosUrl} = Photostream url</li><li>{profileUrl} = Profile url</li><li>{buddyiconSrc} = Source url of buddyicon</li></ul>"
})*/
];
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Object.extend(Settings, {
getBy: function(property, value){
var getBy = Array.prototype.getBy;
var setting = getBy.call(this, property, value);
// If no setting found, try settingsGroups
if (!setting)
{
var groups = getBy.call(this, 'type', 'settingsGroup', true);
if (groups)
{
for (var i=0; i<groups.length; i++) {
setting = groups[i].settings.getBy(property, value);
if (setting) { break; }
}
}
}
return setting;
},
getValue: function(id){
var setting = this.getById(id);
return (setting) ? setting.getValue() : null;
},
save: function(){
for (var i=0; i<this.length; i++)
{ var setting = this[i].save(); }
var s = document.getElementById('settings_saveBtn');
s.disabled = true;
s.className = '';
var popUp = PopUp.getById('Code');
if (popUp) { popUp.updateTextarea(); }
},
popUp: function(){
var that = Settings;
var popUp = PopUp.getById('Settings');
if (!popUp)
{
// Create a new popUp
popUp = new PopUp('Settings');
popUp.main.className += ' fullLength';
// Add a form
var div = popUp.main.appendChild(cE('div'));
var form = div.appendChild(cE('form'));
form.action = '#';
// Add user controls to popUp
for (var i=0; i<that.length; i++)
{ form.appendChild(that[i].getUserControl()); }
// Add Buttons
var p = form.appendChild(cE('p'));
p.className = 'formButtons';
// Add a save button
var saveBtn = p.appendChild(cE('input'));
saveBtn.id = 'settings_saveBtn';
saveBtn.type = 'button';
saveBtn.value = 'Save';
saveBtn.disabled = true;
// Add onclick listener to save settings
saveBtn.addEventListener('click', function(e){
that.save();
e.currentTarget.blur();
}, false);
// Default Settings Button
var defaultBtn = p.appendChild(cE('input'));
defaultBtn.id = 'settings_defaultBtn';
defaultBtn.type = 'button';
defaultBtn.value = 'Default';
defaultBtn.className = 'Butt';
// Add onclick listener to default settings
defaultBtn.addEventListener('click', function(e){
for (var i=0; i<that.length; i++)
{ that[i].controlToDefault(); }
var s = document.getElementById('settings_saveBtn');
s.disabled = true;
s.className = '';
var d = document.getElementById('settings_defaultBtn');
d.disabled = true;
d.className = '';
var popUp = PopUp.getById('Code');
if (popUp) { popUp.updateTextarea(); }
e.currentTarget.blur();
}, false);
}
return popUp.open();
}
});
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
/ / / / / / / / / / / / / / / / / / / /
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
EncodedImages = {
closeWindow: 'data:image/gif;base64,R0lGODlhDQANAJEDAPX3%2Br%2B%2Fv5mZmf%2F%2F%2FyH5BAEAAAMALAAAAAANAA0AAAInXI4ZBu0PDpwSCOFuqxf3HWQdBj6fU1kjGqqeFrWwWk5PakeGogwFADs%3D',
zoomGrey: 'data:image/gif;base64,R0lGODlhMQAYAKIAAK6rq9LS0ouCgn9%2Ff%2F%2F%2F%2FwAAAAAAAAAAACH5BAAAAAAALAAAAAAxABgAAAOESLrc%2FjDKSau9OOtthefg8iljmAlKoJLWMCgvfBKqoAYoFb8x0Veom00FyElcLt%2FiRwl6noGiTtZjToK1m3Sy8yWRF%2BywaDQBCQDt1hwWAN7PsgPM%2Bya9Vkic8IT8qkoyIX0Pd114MHltcgw8gY9LgwJMYEp0dooYmWycnZ6foKGiow4JADs%3D',
zoomColour: 'data:image/gif;base64,R0lGODlhMQAYAKIAAI2nrUFAQL%2B%2Fv8PR1AgGBQAAAJmZmf%2F%2F%2FyH5BAAAAAAALAAAAAAxABgAAAOoeLrc%2FjAuI6u9iuLNc%2F%2BX5hAk%2BIlLqahm2BDKIK9YUSg3XqEHLBOyAcySu%2BUORwjK9wsChhKbDblIPpYHIYk0eBJ1R6sDGwTKvJUiciqN8JjmJ7Tlfh0ATjRdwusRAIBbcw5tRmxTa1Z9K1t%2Bg1UMYVQ6VxiND4hqiThiixCXmFSSDYocJAGkmZuFiAyeEah7Y7Kyr7QYtrcWubp8Br%2FAwcLDxMXGwAIJADs%3D',
zoomColourDown: 'data:image/gif;base64,R0lGODlhMQAYAKIAAI2nrUFAQL%2B%2Fv8PR1AgGBQAAAJmZmf%2F%2F%2FyH5BAAAAAAALAAAAAAxABgAAAOmKLbc%2FjDKdqq9OOvNrelgKFbfaJ6kRqxo62FsFbtmKVdDfotFUfm%2FkO1AOOQIuUExBPQBD0%2BOrZhE5gDLTq8HtUQ3U%2BNqPMAyg8%2BvJlxNmkFNKHfbGVKV1xkNZD8A3G97QjAEAIZjWRp0TnNccmpDFohEehdRaV1BYCJjG45xjz9qB5EcnZ5dmBiQJisBq5%2Bhi44YpR2vgpu5u7a7KL2%2BNcGCwMMhCQA7',
creativeCommonsIcon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAMAAABFNRROAAAAA3NCSVQICAjb4U%2FgAAAAVFBMVEX%2F%2F%2F%2FMzMy0tLSsrKzMzMysrKyZmZmsrKylpaWZmZm0tLSsrKyZmZn%2F%2F%2F%2F4%2BPjx8fHm5ubc3NzY2NjMzMzExMS9vb20tLSsrKylpaWZmZmMjIyEhIQ7afucAAAAHHRSTlMAIjMzVVVmd3d3qru7%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F7LJSKwAAAAlwSFlzAAAK8AAACvABQqw0mAAAACV0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVggMjAwNId2rM8AAAAWdEVYdENyZWF0aW9uIFRpbWUAMTAvMjcvMDbcAykSAAAAeElEQVR4nC2OSwKDIAxE049aLSOBSJrA%2Fe9ZUGeVt5h5Iep5b9%2FtQXe8mln1C6oxALZ6guLK0YgWx54TojDsQ1VQXPPPC8SpMrvs6sxInVJ0E3U9Bq2KZCWK9cbaN%2FvEDkTwUDybnILcXkM4NU2cSpvu1%2BYQwjyOPz86CR3NamYwAAAAAElFTkSuQmCC',
save: 'data:image/gif;base64,R0lGODlhDQANAKIAAP%2F%2F%2F%2F%2F%2F94SEhE5R5EZLXP%2F%2F%2FwAAAAAAACH5BAUUAAUALAAAAAANAA0AAAMwSLpMVWQMAoAQIbo46wWcIlGWAI5hBQTnxLmL5Mo0LcIM2qmqpvG9GQno2xFxjUYCADs%3D',
copy: 'data:image/gif;base64,R0lGODlhDQANAKIAAAAAANnBdqWDC0ZLXP%2F%2F%2F%2F%2F%2FAP%2F%2F%2FwAAACH5BAUUAAYALAAAAAANAA0AAAMyaKrQuyMOUIAcZoRN%2BxbWFhAkCQSgFjRsg4aoIM%2BvKt41jqf6zfcfGDA1KxYBhpbSkQAAOw%3D%3D',
view: 'data:image/gif;base64,R0lGODlhDQANANUAAP%2F%2F%2F8r%2F2eH23%2BDw9Nfw4Nbv39fv4Nbt6tXs6bnrvcbj3rPrt8Ti3KjZto%2FLcbiuky7KEBPJCS23ACquAC2nAACzACemAAqhEACTAAGTAQCLAACJFQCHAACCAAJ%2BAgB9AAB0AAJrDABqCkZLXABkAAFkAT44AJ0TIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAQUAP8ALAAAAAANAA0AAAZbwJFwSCQCjoOGcnAECI8MEWkaUhyfiM9nw%2B14Ds4RoIC5mM0ZQnhcPl8yhjVAUInYK4KruOmAOJprCwkBDycPAQkLaxwcGCAmIBgaGmsWlhMSExSbcoCeRaBDQQA7',
bbCode: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANBAMAAACAxflPAAAAA3NCSVQICAjb4U%2FgAAAAGFBMVEX%2F%2F%2F9GS1xGS1xGS1xGS1xGS1xGS1xGS1xn6jnHAAAACHRSTlMAM0RViJmq%2F%2BmTQ%2BoAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAldEVYdFNvZnR3YXJlAE1hY3JvbWVkaWEgRmlyZXdvcmtzIE1YIDIwMDSHdqzPAAAAFnRFWHRDcmVhdGlvbiBUaW1lADExLzAzLzA2j9bmkQAAADJJREFUeJxjKC8PYAgvL2AoTzVgME0H0gIMDAziQFoBSKuTQcP0pygwqIQDaaD56eUFAPY3E2VV5VGNAAAAAElFTkSuQmCC',
html: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANBAMAAACAxflPAAAAA3NCSVQICAjb4U%2FgAAAAJ1BMVEX%2F%2F%2F9GS1xGS1xGS1xGS1xGS1xGS1xGS1xGS1xGS1xGS1xGS1xGS1y2OUrmAAAADXRSTlMAESJEVWZ3iJmqu93%2F6GZkLAAAAAlwSFlzAAALEgAACxIB0t1%2B%2FAAAACV0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVggMjAwNId2rM8AAAAWdEVYdENyZWF0aW9uIFRpbWUAMTEvMDMvMDaP1uaRAAAAVElEQVR4nGNgYGBiZACDEpYCEMV%2BhOUYiM6ZwDAngIGB9QQDA%2BcRBoY5IMmeBobTIDnuAww1EyB85lMQeQafhYxrgOoZWI%2BwHAWbl8KSAKYZQeYDAJyLEakfRhs9AAAAAElFTkSuQmCC',
allsizesIcon: 'data:image/gif;base64,R0lGODlhDQANANUAABMSEa6wt2x%2BidHk5lldbEZJSY2NmcDT1vP%2F%2Fzc6O2tse4SGkmZmZpmZo8TX2icoKLnAxdzv83l8iUNHWd3d34Wbo0dMXWZmZszMzGx8h%2BTl556prLG1u4WSldnZ3MTGy3Byf97v93N9ibW1vY6kq4CDj11hcEtPYJSUpaGkq5ulpv%2F%2F%2F6q6v3V3hHV5hm%2BCjcnb3eXv8ZytrYyUlOH093CEjv%2F%2F%2FwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAUUADYALAAAAAANAA0AAAZoQJtNkyIQKMKk8EPgrFaSkkZpM61iHdYKo1CmODHEQ0VjiTBJwqqTADwKjpchvWJtHgzVQdBIUiQrEQUqAxUnAUoLECQwBxUZLVQ2IBk1AhMgFhKSHg0NHDYSmpJUoi6kSqIMqEkMGEEAOw%3D%3D',
premasagarBuddyicon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAA3NCSVQICAjb4U%2FgAAABgFBMVEXmPQQZLd6K3QoQuN9lWGgQf9yxrg2o%2FVLMzJm%2FHbtaiGdvQUPMzAB5c6%2FaJ2WLC8Dwu2jjnz5j0KroiVFwdkLEfBR%2FwS3MAP%2FhwD%2FYu3nCVF9zIMtSc9D2nQbUd1qGCf%2FUE4HoG0G%2FL7vbVSizQmTP0CK6%2B6u96QWEQdzaaT5K1pSZ%2FzMI9O3Af1fmjwBaKdrbgwuxl%2FnobYrZYADzn0Xb9RErhOzB%2B16dGd0D5fTgTz3WHzziY13B0C6NRIG0ouSwrT%2FEAOLBxhzzqlsEmuxnQazMM5lPMezkZZrATRbmygc02arcr3fZ80nzkh3EPXdTivmPMsLZSlzAQkWo5ALq0HfBnRzhRTzniSC12jX1v6vufAALnM5%2FnFKU5qXd4CPT20ShS4gQ5uKY%2BGrOfiHaYSWYPb7gQl5THe1nToh8HcygXTvAMNvK0haxLzLHD8v0YADn3wqtIZ7mUhi3%2BgDSmAzFlErs%2B5z00GjMgRSd1T3rSQAHV%2BDrd1zSSj5wEf%2FMziISAAAACXBIWXMAAAsSAAALEgHS3X78AAAAJXRFWHRTb2Z0d2FyZQBNYWNyb21lZGlhIEZpcmV3b3JrcyBNWCAyMDA0h3aszwAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNS8wNi8wNRnkY5QAAAH1SURBVHicLdJtW5pQAIfxkw%2BZzVRKclMpfCqXDU9Tp5I6IbN0Tk0dUVhZQjinE4zcbHXtq%2B%2FAul%2F%2Bf%2BecF1yAFwzD2BujUum30TfUJXjhGzzbRxXYHz4MO3K7626UDnxDjV4UOILwMZU8lkqldLwEW1CoORwcRSDw2qeVLb6BBEEecg50mjCAsY9nzvc8f1SvAx%2F%2BOhM1n9c7rZAkWaHFdyvAUoUUegdCgkI3mJnL5fL7LZ46aHZwJJSgCFSbYUbPw%2BHJ0nGnGAP5tsThEAqCQkWYqTUQixV9cvj2L4K2yHEQQkVoM2eBtauOLMvS7bYONPcIIZ5MRkarHlyQZJkW%2F4MsLRYLUVy8seCCIIo0LelAB4PB6ge90mYknJRQACSbXkAfBs8d3HxeeooPzkLN8ENY%2BWPA%2BWHwEX2Sp3g8PojZx6Hmg6IAENGh6ljuamjPDGLZ0NhOdqoANLdB5%2Bdyt6tpu%2FEMgu1sxUmSdicotsCax2QyaVqXzWRs99lscTTyJxLfV7%2BA07kBu2r%2Fq%2B1%2BOuqdDIdLz729ATjdiGomU3eiqjpYzYGh1Vour1%2BDjxtYOq2x7ES9sc0S5bK5jPq0voMg9TadVtUJW7s4tppzuRzaXyEVNX6Swmbvbh9lDrRa1zsgzzcaXN%2Foak%2Ff9%2B8%2BHxys%2FPoHUK%2BKl%2Bb7xOMAAAAASUVORK5CYII%3D'
};
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
} // end init function
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
})(); // THE END!
/*
POSSIBLE TO DO LIST:
- Draggable popUp
- View image within the photopage (replace the default image)
- Tidy up - e.g. combine getLargestViaHttp with Page.allSizesPage
- Cache the 10 most recently determined photos' sizes
- Special chars for ©, etc & foreign charsets
*/