go-ethereum/swarm/examples/album/index.js
zelig f7d5ce4985 SWORM - swarm poc 0.2 homestead RC1
synced up to go-ethereum 1.5.0-unstable develop branch

major features:
* api overhaul due to rpc v2 and node service stack interface changes
* blockchain/ethereum contract interaction rewritten using abi/abigen (chequebook, ens)
* swarm - cluster control CLI - migration and revamp of prehistoric eth-utils repo
* poor man's end to end testing: scripted scenarios in swarm/test using swarm CLI
* http proxy now handles 3 url schemes for 1) ens-enabled [bzz], 2) immutable [bzzi] and 3) raw manifest [bzzr] resolution
* fixes issues with remote address setting, forwarding and syncing
* new control flags to switch swap and sync on and off
* placeholder basic implementation Ethereum Name Service
* improved logging - now debug level is coherent

regression:
* uri based versioning support is dropped temporarily since state tree pruning does not guarantee historical record
* registrar related functionality temporarily restricted - current ENS provides basic free and unrestricted Register/Resolve

accounts/abi:
  * bind: repeated attempt deployment of contracts, validation against known code, transactor creation from private keys
  * accountmanager: getUnlocked snatch private key when unlocked

cmd:
  * unlockAccount  moved to utils/cmd   and exported
  * getPassPhrase  moved to utils/input and exported
  * accountcmds: reflect the change
  * js: GlobalRegistrar is dropped (ens)

flags:
  * chequebook, bzzaccount,  bzzport, bzzconfig, bzznoswap, bzznosync

chequebook:
  * move from common/ to swarm/services
  * abigen-ised
  * specifies its own API (removed chequebook api from swarm/api)

kademlia:
  * move from common to swarm/network/kademlia
  * address abstracted out to separate file + tests

dns/ens/registrar:
  * moved from swarm/api to swarm/services/ens
  * implementation is basic placeholder before ENS is implemented
  * temporary rpc api via ens namespace
  * the old common/registrar is removed (also from eth/backend apis)

swap:
  * the abstract swap module moved from common to swarm/services
  * now embedded in the swarm and chequebook specific setup (this will change)
  * safer chequebook deployment using abigen helpers
  * backend not field of swap params

eth:
  * public accessor for GPO, needed to construct a PublicBlockChainAPI
  * extends ContractBackend in eth/bind.go with BalanceAt, GetTxReceipt and CodeAt API calls

internal/web3ext
  * add js bindings for bzz, chequebook rpc apis

swarm/api:
  * refactored api into smaller modules filesystem/storage/testapi
  * ethereum backend (needed for dns, swap, etc) moved to abi/bind
  * TODO: further refactor  due to #2040
  * swarm/api/http: now supports the 3 uri schemes
  * examples/album updated

swarm/cmd:
  * migrate old eth-utils and modify into a cluster control CLI
  * bzzup now allows non-local gateway, endpoint specified as second argument

swarm/network:
  * forwarder improved log messages, fixup condition on whether syncer is nil
  * hive extended with controls for testing support block read/write, swap/sync enabled/disabled
  * hive keepAlive launches with alarm in case no discover and no kaddb
  * fix IP address formatting issue [::1] -> became ::1 which refused to dial, now use discover.NewNode#String
  * integrate functionality for enabling/disabling sync and swap
  * allow nil sync state - improve syncer interface in protocol
  * fix SData slice out of bounds bug
  * fix disconnects by not replacing a node when bucket is full

swarm/test
  * poor man's testing framework. scripts invoking swarm/cmd/swarm
  * added tests for basic scenarios connections, swap, sync

swarm:
  * rewrite api using rpc v2
  * blockchain comms via abi/abigen + eth.ContractBackend
  * integrate new flags
2016-05-27 13:08:47 +02:00

763 lines
17 KiB
JavaScript

// fgallery: a modern, minimalist javascript photo gallery
// Copyright(c) 2003-2014 by wave++ "Yuri D'Elia" <wavexx@thregr.org>
// Distributed under GPL2 (see COPYING) WITHOUT ANY WARRANTY.
var datafile = 'data.json';
var padding = 100;
var marginTop = 50;
var duration = 500;
var thrdelay = 1500;
var hidedelay = 3000;
var prefetch = 1;
var minupscale = 640 * 480;
var thumbrt = 16/9 - 5/3;
var cutrt = 0.15;
Element.Events.hashchange =
{
onAdd: function()
{
var hash = window.location.hash;
var hashchange = function()
{
if(hash == window.location.hash) return;
else hash = window.location.hash;
var value = (!hash.indexOf('#')? hash.substr(1): hash);
window.fireEvent('hashchange', value);
document.fireEvent('hashchange', value);
};
if("onhashchange" in window
&& (!Browser.ie || Browser.version > 7))
window.onhashchange = hashchange;
else
hashchange.periodical(50);
}
};
// some state variables
var emain; // main object
var eback; // background
var enoise; // additive noise
var eflash; // flashing object
var ehdr; // header
var progress; // progress
var elist; // thumbnail list
var fscr; // thumbnail list scroll fx
var econt; // picture container
var ebuff; // picture buffer
var eleft; // go left
var eright; // go right
var oimg; // old image
var eimg; // new image
var cthumb; // current thumbnail
var mthumb; // missing thumbnails
var eidx; // current index
var tthr; // throbber timeout
var imgs; // image list
var first; // first image
var idle; // idle timer
var clayout; // current layout
var csr; // current scaling ratio
function resize()
{
// best layout
var msize = emain.getSize();
var rt = (imgs.thumb.min[0] / imgs.thumb.min[1]);
var maxw = msize.x - imgs.thumb.min[0] - padding;
var maxh = msize.y * rt - imgs.thumb.min[1] - padding;
var layout = (maxw >= maxh? 'horizontal': 'vertical');
// calculate a good multiplier for the thumbnail size
var m = (layout == 'horizontal'?
(msize.x * window.devicePixelRatio * thumbrt) / imgs.thumb.min[0]:
(msize.y * window.devicePixelRatio * thumbrt) / imgs.thumb.min[1]);
if(m >= 1)
m = Math.pow(2, Math.floor(Math.log(m) / Math.LN2));
else
m = Math.pow(2, Math.ceil(Math.log(m) / Math.LN2));
var sr = m / window.devicePixelRatio;
if(layout != clayout || sr != csr)
{
onLayoutChanged(layout, sr);
if(cthumb) centerThumb(0);
clayout = layout;
csr = sr;
}
// resize main container
var epos = elist.getPosition();
if(layout == 'horizontal')
{
econt.setStyles(
{
'width': epos.x,
'height': msize.y
});
}
else
{
econt.setStyles(
{
width: msize.x,
height: epos.y
});
}
if(oimg) resizeMainImg(oimg);
if(eimg) resizeMainImg(eimg);
}
function onLayoutChanged(layout, sr)
{
elist.setStyle('display', 'none');
// refit the thumbnails, cropping edges
imgs.data.each(function(x, i)
{
var crop = x.thumb[1];
var size = (x.thumb[2]? x.thumb[2]: crop);
var offset = (x.thumb[3]? x.thumb[3]: [0, 0]);
var center = (x.center? [x.center[0] / 1000, x.center[1] / 1000]: [0.5, 0.5]);
var maxw, maxh;
if(layout == 'horizontal')
{
maxw = imgs.thumb.min[0];
maxh = Math.round(maxw * (crop[1] / crop[0]));
maxh = Math.max(maxh, imgs.thumb.min[1]);
maxh = Math.min(maxh, imgs.thumb.max[1]);
}
else
{
maxh = imgs.thumb.min[1];
maxw = Math.round(maxh * (crop[0] / crop[1]));
maxw = Math.max(maxw, imgs.thumb.min[0]);
maxw = Math.min(maxw, imgs.thumb.max[0]);
}
x.eimg.setStyles(
{
'width': Math.round(maxw * sr),
'height': Math.round(maxh * sr),
'background-size': Math.round(crop[0] * sr) + "px " + Math.round(crop[1] * sr) + "px"
});
// center cropped thumbnail
var dx = maxw - crop[0];
var cx = size[0] * center[0] - offset[0];
cx = Math.round(crop[0] / 2 - cx + dx / 2);
cx = Math.max(Math.min(0, cx), dx);
var dy = maxh - crop[1];
var cy = size[1] * center[1] - offset[1];
cy = Math.round(crop[1] / 2 - cy + dy / 2);
cy = Math.max(Math.min(0, cy), dy);
x.eimg.setStyle('background-position', Math.round(cx * sr) + 'px ' + Math.round(cy * sr) + 'px');
// border styles
var classes = ['cut-left', 'cut-right', 'cut-top', 'cut-bottom'];
classes.each(function(c) { x.ethumb.removeClass(c); });
var wx = Math.round(size[0] * cutrt);
if((offset[0] - cx) > wx) x.ethumb.addClass('cut-left');
if((cx - offset[0] + size[0] - maxw) > wx) x.ethumb.addClass('cut-right');
var wy = Math.round(size[1] * cutrt);
if((offset[1] - cy) > wy) x.ethumb.addClass('cut-top');
if((cy - offset[1] + size[1] - maxh) > wy) x.ethumb.addClass('cut-bottom');
});
// resize thumbnail list
if(layout == 'horizontal')
{
elist.setStyles(
{
'top': 0,
'left': 'auto',
'right': 0,
'bottom': 0,
'overflow-y': 'scroll',
'overflow-x': 'hidden',
'white-space': 'pre-line'
});
}
else
{
elist.setStyles(
{
'top': 'auto',
'left': 0,
'right': 0,
'bottom': 0,
'overflow-y': 'hidden',
'overflow-x': 'scroll',
'white-space': 'nowrap'
});
}
elist.setStyle('display', 'block');
}
function resizeMainImg(img)
{
var contSize = econt.getSize();
var listSize = elist.getSize();
var thumbWidth = (clayout == 'horizontal'? listSize.x: listSize.y);
var data = imgs.data[img.idx].img;
var width = data[1][0];
var height = data[1][1];
var imgrt = width / height;
var pad = padding * 2;
if(imgrt > (contSize.x / contSize.y))
{
img.width = Math.max(thumbWidth + pad, contSize.x - pad);
img.height = img.width / imgrt;
}
else
{
img.height = Math.max(thumbWidth + pad, contSize.y - pad);
img.width = img.height * imgrt;
}
if(width * height <= minupscale && img.width > width)
{
img.width = width;
img.height = height;
}
img.setStyles(
{
'position': 'absolute',
'top': (contSize.y / 2 - img.height / 2) + marginTop,
'left': contSize.x / 2 - img.width / 2
});
}
function ts()
{
var date = new Date();
return date.getTime();
}
function detectSlowness(start)
{
var end = ts();
var delta = end - start;
if(delta > duration * 2)
duration = 0;
}
function centerThumb(duration)
{
var thumbPos = cthumb.getPosition();
var thumbSize = cthumb.getSize();
var listSize = elist.getSize();
var listScroll = elist.getScroll();
var x = thumbPos.x + listScroll.x - listSize.x / 2 + thumbSize.x / 2;
var y = thumbPos.y + listScroll.y - listSize.y / 2 + thumbSize.y / 2;
if(fscr) fscr.cancel();
fscr = new Fx.Scroll(elist, { duration: duration }).start(x, y);
}
function imageToUrl(img, w, h) {
var can = document.createElement('canvas');
can.width = w;
can.height = h;
var cntxt = can.getContext("2d");
cntxt.drawImage(img, 0, 0, w, h);
return can.toDataURL();
}
function deleteImg()
{
if(imgs.data.length < 2) return; // empty albums not allowed
var fname = imgs.data[eidx].img[0];
imgs.data.splice(eidx,1);
// construct an HTTP request
var xhr = new XMLHttpRequest();
// set response handler
xhr.onreadystatechange = function () { if (xhr.readyState === 4) {
var i = xhr.responseText;
var xhrd = new XMLHttpRequest();
xhrd.onreadystatechange = function () { if (xhrd.readyState === 4) {
var j = xhrd.responseText;
window.location.replace("/bzz:/" + j + "/");
}};
xhrd.open("DELETE", "/bzz%3A/" + i + "/" + fname, true);
xhrd.send();
}};
sendImages(xhr, "");
}
function moveUpDown(off)
{
var me = imgs.data[eidx];
imgs.data[eidx] = imgs.data[eidx + off];
imgs.data[eidx + off] = me;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () { if (xhr.readyState === 4) {
var i = xhr.responseText;
window.location.replace("/bzz:/" + i + "/#" + (eidx + off));
}};
sendImages(xhr, "");
}
function moveUp()
{
moveUpDown(-1);
}
function moveDown()
{
moveUpDown(1);
}
function onMainReady()
{
resizeMainImg(eimg);
eimg.setStyle('opacity', 0);
eimg.addClass('current');
eimg.inject(ebuff);
// setup header
var dsc = [];
if(imgs.index)
dsc.push("<a title=\"Back to index\" href=\"" + encodeURI(imgs.index) + "\"><img src=\"back.png\"/></a>");
// delete image
if(imgs.data.length > 1)
dsc.push("<a title=\"Delete image\" onclick=\"deleteImg()\"><img src=\"delete.png\"/></a>");
// add image
dsc.push("<input type=\"file\" id=\"fileElem\" multiple accept=\"image/*\" style=\"display:none\" onchange=\"handleFiles(this.files)\"><a href=\"#\" id=\"fileSelect\"><img src=\"add.png\"></a>");
// up image
if(eidx > 0)
dsc.push("<a title=\"Move up\" onclick=\"moveUp()\"><img src=\"up.png\"/></a>");
// down image
if(eidx < imgs.data.length - 1)
dsc.push("<a title=\"Move down\" onclick=\"moveDown()\"><img src=\"down.png\"/></a>");
if(imgs.data[eidx].file)
{
var img = imgs.data[eidx].file[0];
dsc.push("<a title=\"Download image\" href=\"" + encodeURI(img) + "\"><img src=\"eye.png\"/></a>");
eimg.addEvent('click', function() { window.location = img; });
eimg.setStyle('cursor', 'pointer'); // fallback
eimg.setStyle('cursor', 'zoom-in');
}
if(imgs.download)
dsc.push("<a title=\"Download album\" href=\"" + encodeURI(imgs.download) + "\"><img src=\"download.png\"/></a>");
if(imgs.data[eidx].date)
dsc.push("<b>Date</b>: " + imgs.data[eidx].date);
ehdr.set('html', dsc.join(' '));
ehdr.setStyle('display', (dsc.length? 'block': 'none'));
progress.set('html', '<img id="currentPreview">');
progress.set('style', 'text-align: center; padding-top: 20px');
// complete thumbnails
var d = duration;
if(first !== false)
{
first = false;
loadAllThumbs();
d = 0;
}
// start animations
if(oimg)
{
oimg.removeClass('current');
var fx = oimg.get('tween');
fx.cancel();
fx.duration = d;
fx.removeEvents('complete');
fx.addEvent('complete', function(x) { x.destroy(); });
fx.start('opacity', 0);
oimg = undefined;
}
var fx = new Fx.Tween(eimg, { duration: d });
if(d)
{
var now = ts();
fx.addEvent('complete', function()
{
detectSlowness(now);
});
}
eimg.set('tween', fx);
fx.start('opacity', 1);
var rp = Math.floor(Math.random() * 100);
eback.src = imgs.data[eidx].blur;
enoise.setStyle('background-position', rp + 'px ' + rp + 'px');
clearTimeout(tthr);
idle.start();
showHdr();
centerThumb(d);
// prefetch next image
if(prefetch && eidx != imgs.data.length - 1)
{
var data = imgs.data[eidx + 1];
Asset.images([data.img[0], data.blur]);
}
jqueryInit();
}
function showThrobber()
{
var img = new Element('img', { id: 'throbber' });
img.src = "throbber.gif";
ehdr.empty();
img.inject(ehdr);
ehdr.setStyle('display', 'block');
idle.stop();
showHdr();
}
function hideHdr()
{
if(idle.started && ehdr.getStyle('opacity') !== 0)
ehdr.tween('opacity', [1, 0], { link: 'ignore' });
}
function hideNav()
{
emain.addClass('no-cursor');
eleft.tween('opacity', [1, 0], { link: 'ignore' });
eright.tween('opacity', [1, 0], { link: 'ignore' });
}
function showHdr()
{
ehdr.get('tween').cancel();
ehdr.fade('show');
}
function showNav()
{
emain.removeClass('no-cursor');
eleft.get('tween').cancel();
eleft.fade('show');
eright.get('tween').cancel();
eright.fade('show');
}
function flash()
{
eflash.setStyle('display', 'block');
eflash.tween('opacity', [1, 0]);
}
function prev()
{
if(eidx != 0)
switchTo(eidx - 1);
else
{
flash();
switchTo(imgs.data.length - 1);
}
}
function next()
{
if(eidx != imgs.data.length - 1)
switchTo(eidx + 1);
else
{
flash();
switchTo(0);
}
}
function switchTo(i)
{
window.location.replace("#" + i);
}
function load(i)
{
if(i == eidx) return;
doLoad(i);
}
function doLoad(i)
{
var data = imgs.data[i];
var assets = Asset.images([data.img[0], data.blur],
{
onComplete: function() { if(i == eidx) onMainReady(); }
});
if(!oimg) oimg = eimg;
eimg = assets[0];
eimg.idx = eidx = i;
if(cthumb) cthumb.removeClass('current');
cthumb = imgs.data[eidx].ethumb;
cthumb.addClass('current');
clearTimeout(tthr);
tthr = showThrobber.delay(thrdelay);
}
function getLocationIndex()
{
var hash = window.location.hash;
var idx = parseInt(!hash.indexOf('#')? hash.substr(1): hash);
if(isNaN(idx) || idx < 0)
idx = 0;
else if(idx >= imgs.data.length)
idx = imgs.data.length - 1;
return idx;
}
function change()
{
load(getLocationIndex());
}
function loadThumb(i)
{
var x = imgs.data[i];
x.eimg.setStyle('background-image', 'url(' + encodeURI(x.thumb[0]) + ')');
}
function loadAllThumbs()
{
mthumbs.each(loadThumb);
mthumbs = [];
}
function loadNextThumb()
{
if(mthumbs.length)
{
var i = mthumbs.shift();
Asset.image(imgs.data[i].thumb[0],
{
onLoad: function()
{
loadThumb(i);
loadNextThumb();
}
});
}
}
function initGallery(data)
{
imgs = data;
emain = $('gallery');
emain.setStyle('display', 'none');
eback = new Element('img', { id: 'background' });
eback.inject(emain);
enoise = new Element('div', { id: 'noise' });
enoise.inject(emain);
econt = new Element('div', { id: 'content' });
econt.inject(emain);
ebuff = new Element('div');
ebuff.inject(econt);
eflash = new Element('div', { id: 'flash' });
eflash.setStyles({ 'opacity': 0, 'display': 'none' });
eflash.set('tween',
{
duration: duration,
link: 'cancel',
onComplete: function() { eflash.setStyle('display', 'none'); }
});
eflash.inject(econt);
eleft = new Element('a', { id: 'left' });
eleft.adopt((new Element('div')).adopt(new Element('img', { 'src': 'left.png' })));
eleft.inject(econt);
eright = new Element('a', { id: 'right' });
eright.adopt((new Element('div')).adopt(new Element('img', { 'src': 'right.png' })));
eright.inject(econt);
ehdr = new Element('div', { id: 'header' });
ehdr.inject(econt);
progress = new Element('div', { id: 'progress' });
progress.inject(econt);
elist = new Element('div', { id: 'list' });
elist.inject(emain);
imgs.data.each(function(x, i)
{
var ethumb = new Element('div', { 'class': 'thumb' });
x.ethumb = ethumb;
var a = new Element('a');
a.addEvent('click', function() { switchTo(i); });
a.href = "#" + i;
var img = new Element('div', { 'class': 'img' });
x.eimg = img;
img.inject(a);
var ovr = new Element('div', { 'class': 'ovr' });
ovr.inject(a);
a.inject(ethumb);
ethumb.inject(elist);
elist.appendText("\n");
});
emain.setStyles(
{
'display': 'block',
'visibility': 'hidden',
'min-width': imgs.thumb.min[0] + padding * 2,
'min-height': imgs.thumb.min[1] + padding * 2
});
// events and navigation shortcuts
eleft.addEvent('click', prev);
eright.addEvent('click', next);
window.addEvent('resize', resize);
window.addEvent('hashchange', change);
window.addEvent('keydown', function(ev)
{
if(ev.key == 'up' || ev.key == 'left')
{
ev.stop();
prev();
}
else if(ev.key == 'down' || ev.key == 'right' || ev.key == 'space')
{
ev.stop();
next();
}
});
econt.addEvent('mousewheel', function(ev)
{
if(ev.alt || ev.control || ev.meta || ev.shift)
return;
ev.stop();
if(ev.wheel > 0)
prev();
else
next();
});
new MooSwipe(econt,
{
onSwipeleft: next,
onSwipedown: next,
onSwiperight: prev,
onSwipeup: prev
});
// setup an idle callback for mouse movement only
var idleTmp = new IdleTimer(window, {
timeout: hidedelay,
events: ['mousemove', 'mousedown', 'mousewheel']
}).start();
idleTmp.addEvent('idle', hideNav);
idleTmp.addEvent('active', function() { showNav(); showHdr(); });
// general idle callback
idle = new IdleTimer(window, { timeout: hidedelay }).start();
idle.addEvent('idle', hideHdr);
// prepare first image
first = getLocationIndex();
resize();
load(first);
centerThumb(0);
if(imgs.name) document.title = imgs.name;
// setup thumbnail loading sequence
mthumbs = [];
if(first < 5)
{
// optimize common initial case (viewing from the beginning)
for(var i = 0; i != imgs.data.length; ++i)
mthumbs.push(i);
}
else for(var i = 0; i != imgs.data.length; ++i)
{
// distance from current
var d = (i / 2 >> 0);
var k = first + (i % 2? d + 1: -d);
if(k < 0)
k = imgs.data.length + k;
else if(k >= imgs.data.length)
k = k - imgs.data.length;
mthumbs.push(k);
}
loadNextThumb();
emain.setStyle('visibility', 'visible');
}
function initFailure()
{
emain = $('gallery');
emain.set('html', "<h2>Cannot load gallery data :'(</h2>");
emain.setStyles(
{
'background': 'inherit',
'display': 'block'
});
}
function init()
{
if(!("devicePixelRatio" in window))
window.devicePixelRatio = 1;
// read the data
new Request.JSON(
{
url: datafile,
onRequest: function()
{
if(this.xhr.overrideMimeType)
this.xhr.overrideMimeType('application/json');
},
isSuccess: function()
{
return (!this.status || (this.status >= 200 && this.status < 300));
},
onSuccess: initGallery,
onFailure: initFailure
}).get();
// preload some resources
Asset.images(['throbber.gif',
'left.png', 'right.png', 'delete.png', 'add.png',
'eye.png', 'download.png', 'back.png', 'up.png', 'down.png',
'cut-left.png', 'cut-right.png',
'cut-top.png', 'cut-mov.png']);
}
window.addEvent('domready', init);