App-sitelenmute

 view release on metacpan or  search on metacpan

share/view/index.js  view on Meta::CPAN

// Sitelen Mute: a modern, minimalist javascript photo gallery
// Copyright(c) 2011-2016 by wave++ "Yuri D'Elia" <wavexx@thregr.org>
// Distributed under GPLv2+ (see COPYING) WITHOUT ANY WARRANTY.
"use strict";

var datafile = 'data.json';

// dimensions
var padding = 22;
var duration = 500;      // for scrolling
var thrdelay = 1500;     // throbber delay
var hidedelay = 3000;    // header and caption hiding delay
var slidedelay = 5000;   // slide show delay
var prefetch = 1;
var minupscale = 640 * 480;
var thumbrt = 16/9 - 5/3;
var cutrt = 0.15;
var capdelay = 5000;
var rdwdelay = 500;

// state variables
var emain;      // main object
var eback;      // background
var enoise;     // additive noise
var eflash;     // flashing object
var ehdr;       // header
var ecap;       // caption
var capst;      // caption status
var captm;      // caption timeout
var elist;      // thumbnail list
var fscr;       // thumbnail list scroll fx
var econt;      // picture container
var ebuff;      // picture buffer
var oimg;       // old image
var eimg;       // new image
var cthumb;     // current thumbnail
var mthumb;     // thumbnail measurement cache
var eidx;       // current index
var tthr;       // throbber timeout
var imgs;       // image list
var first;      // first image
var idle;       // general idle timer
var idleMouse;  // idle mouse timer
var clayout;    // current layout
var csr;        // current scaling ratio
var sdir;       // scrolling direction
var slideshow;  // slideshow status

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);
  }
};

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'?

share/view/index.js  view on Meta::CPAN

  if(layout == 'horizontal')
  {
    econt.setStyles(
    {
      'width': (slideshow == 'on'? msize.x: epos.x),
      'height': msize.y
    });
  }
  else
  {
    econt.setStyles(
    {
      'width': msize.x,
      'height': (slideshow == 'on'? msize.y: epos.y)
    });
  }

  if(oimg) resizeMainImg(oimg);
  if(eimg) resizeMainImg(eimg);
}

function onResize()
{
  setSlideshowOff();
  resize();
  onScroll();
}

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');

  // update measurement cache
  mthumb = {'beg': [], 'end': []};
  if(layout == 'horizontal')
  {
    var off = elist.getScrollTop();
    imgs.data.each(function(x, i)
    {
      var top = off + x.ethumb.getTop();
      var bottom = top + x.ethumb.getHeight();
      mthumb.beg.push(top);
      mthumb.end.push(bottom);
    });
  }
  else
  {

share/view/index.js  view on Meta::CPAN

    ecap.empty();
    if(cap[0].length)
      ecap.adopt(new Element('div', { 'id': 'title', 'text': cap[0] }));
    if(cap[1].length)
      ecap.adopt(new Element('div', { 'id': 'desc', 'text': cap[1] }));
    showCap(first);
  }

  // disable transitions for first image
  var d = duration;
  if(first !== false)
  {
    first = false;
    d = 0;
  }

  // start animations
  if(oimg)
  {
    // scrolling direction
    var pred = umod(oimg.idx + sdir, imgs.data.length);
    if(pred != eidx)
    {
      var diff = umod(eidx - oimg.idx, imgs.data.length);
      if(diff == 1)
        sdir = 1;
      else if(diff == imgs.data.length - 1)
        sdir = -1;
      else
        sdir = 0;
    }

    // fade old image
    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 = '';
  if (imgs.data[eidx].blur)
  {
    eback.src = encodeURI(imgs.data[eidx].blur);
    enoise.setStyle('background-position', rp + 'px ' + rp + 'px');
  }

  tthr = resetTimeout(tthr);
  idle.start();
  if(slideshow != 'on') showHdr();
  centerThumb(d);

  // prefetch next image
  if(prefetch && sdir != 0)
  {
    var data = imgs.data[umod(eidx + sdir, imgs.data.length)];
    Asset.images([encodeURI(data.img[0]), data.blur? data.blur :[]]);
  }
}

function showThrobber()
{
  var img = new Element('img', { id: 'throbber' });
  img.src = "view/throbber.gif";
  ehdr.empty();
  img.inject(ehdr);
  ehdr.setStyle('display', 'block');
  idle.stop();
  showHdr();
}

function hideHdr()
{
  ehdr.tween('opacity', 0);
  emain.addClass('no-cursor');
}

function showHdr()
{
  emain.removeClass('no-cursor');
  ehdr.get('tween').cancel();
  ehdr.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;

  var data = imgs.data[i];
  var assets = Asset.images([data.img[0], data.blur? 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');

  resetTimeout(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("' + x.thumb[0] + '")');
  x.thumbLoaded = true;
}

function initGallery(data)
{
  // prepare the data
  imgs = data;
  if(imgs.name) document.title = imgs.name;
  imgs.captions = false;
  capst = 'normal';
  for(var i = 0; i != imgs.data.length; ++i)
  {
    if(imgs.data[i]['caption'])
    {
      imgs.captions = true;
      break;
    }
  }

  // build the dom
  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);

  ecap = new Element('div', { id: 'caption' });
  ecap.inject(econt);

  ehdr = new Element('div', { id: 'header' });
  ehdr.set('tween', { link: 'ignore' })
  ehdr.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;
    x.thumbLoaded = false;

    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
  });

share/view/index.js  view on Meta::CPAN

    }
  });

  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
  idleMouse = new IdleTimer(window, {
    timeout: hidedelay,
    events: ['mousemove', 'mousedown', 'mousewheel']
  }).start();
  idleMouse.addEvent('active', showHdr);
  idleMouse.addEvent('idle', hideHdr);

  // general idle callback
  idle = new IdleTimer(window, { timeout: slidedelay }).start();

  // start slide show immediately if specified in data.json
  if(imgs.startslideshow == 'yes')
    setSlideshowOn();
  else
    setSlideshowOff();

  // prepare first image
  sdir = 1;
  first = getLocationIndex();
  resize();
  load(first);
  loadThumb(first);
  centerThumb(0);

  // set visibility
  emain.setStyle('visibility', 'visible');
  if(slideshow == 'on')
    elist.setStyle('display', 'none');
}

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([
    'view/throbber.gif', 'view/overview.png', 'view/eye.png',
    'view/download.png', 'view/back.png', 'view/cap-normal.png',
    'view/cap-always.png', 'view/cap-never.png', 'view/cut-left.png',
    'view/cut-right.png', 'view/cut-top.png', 'view/cut-mov.png'
   ]);
}

window.addEvent('domready', init);



( run in 1.118 second using v1.01-cache-2.11-cpan-fe3c2283af0 )