<commit_before>/*
---
description: cwpGallery, yet another image gallery

license:
- MIT-style

authors:
- Johannes Fischer

requires:
- core/1.3: '*'
- more/1.3: 'Assets'

provides:
- cwpGallery

...
*/

var cwpGallery = new Class({

	Implements: Options,

	busy: false,
	currentImage: null,
	disableScrolling: false,
	initialized: false,

	options: {
		animateTitle: true,
		captionSource: 'title',
		enableKeys: true,
		fxDuration: 500,
		fxTransition: 'cubic:out',
		scrollRange: 4
	},

	initialize: function (element, options)
	{
		this.element = $(element);
		// Image container
		this.imageHolder = this.element.getElement('div');
		// Thumbnail container
		this.thumbnailHolder = null;
		// List elements
		this.thumbnailList = this.element.getElement('ul');
		this.thumbnails = this.element.getElements('li');

		this.setOptions(options);

		this.createControls();
		this.initThumbnails();
		this.createLoader();

		if (this.options.enableKeys)
		{
			this.attachKeyEvents();
		}
		this.loadImage(this.thumbnails[0].getElement('a'), 0);
	},

	attachKeyEvents: function ()
	{
		// TODO addEvent keydown doesn't work in FF
		document.body.addEvent('keydown', function (e) {
			var key = e.key;

			if (key == 'left')
			{
				this.previous();
			}
			if (key == 'right')
			{
				this.next();
			}
		}.bind(this));
	},

	centerImage: function (image)
	{
		var imageSize = image.getSize();
		var parentSize = image.getParent().getSize();

		// TODO hoehe des Titles von margin-top abziehen, wenn animation deaktiviert ist

		image.setStyles({
			marginLeft: ((parentSize.x - imageSize.x) / 2).round(),
			marginTop: ((parentSize.y - imageSize.y) / 2).round()
		});
	},

	createControls: function ()
	{
		var width = (this.imageHolder.getWidth() / 3).round();

		new Element('span', {
			'class': 'control-holder',
			events: {
				click: function () {
					this.previous();
				}.bind(this)
			},
			styles: {
				left: 0,
				width: width
			}
		}).grab(
			new Element('span', {
				'class': 'control-previous'
			})
		).inject(this.imageHolder);

		new Element('span', {
			'class': 'control-holder',
			events: {
				click: function () {
					this.next();
				}.bind(this)
			},
			styles: {
				right: 0,
				width: width
			}
		}).grab(
			new Element('span', {
				'class': 'control-next'
			})
		).inject(this.imageHolder);
	},

	createLoader: function ()
	{
		this.loader = new Element('div.loading', {
			styles: {
				opacity: 0
			}
		}).inject(this.imageHolder);
	},

	initThumbnails: function ()
	{
		var styles,
			width = 0;

		this.thumbnails.getElements('a').each(function (el, i) {
			el.addEvent('click', function (e) {
				e.stop();
				this.loadImage(el, i);
			}.bind(this));
		}, this);

		this.thumbnails.getElement('a').each(function (el) {
			width += el.getWidth();
		});

		var styles = this.thumbnails[0].getStyles('margin-left', 'margin-right', 'padding-left', 'padding-right');

		Object.each(styles, function (el) {
			width += el.toInt() * this.thumbnails.length;
		}, this);

		this.thumbnailList.setStyle('width', width);

		this.thumbnailHolder = new Element('div.thumbnail-holder').inject(this.element);

		new Element('div').wraps(this.thumbnailList).inject(this.thumbnailHolder);

		if (width < this.thumbnailList.getParent().getWidth())
		{
			this.disableScrolling = true;
			return;
		}

		var leftControl = new Element('span.scroll-left', {
			events: {
				click: function () {
					this.scrollThumbnails(leftControl);
				}.bind(this)
			}
		}).inject(this.thumbnailHolder);

		var controlRight = new Element('span.scroll-right', {
			events: {
				click: function () {
					this.scrollThumbnails(controlRight);
				}.bind(this)
			}
		}).inject(this.thumbnailHolder);
	},

	insertImage: function (image ,i)
	{
		var target = this.imageHolder.getElement('.images'),
			styles,
			where;

		// insert after current image
		if (i > this.currentImage)
		{
			styles = {
				right: 0
			};
			where = 'bottom';
		}
		// insert before current image
		else if (i < this.currentImage || (this.curentImage == 0 && i == this.thumbnails.length))
		{
			styles = {
				left: 0
			};
			where = 'top';
			target.setStyle('left', this.imageHolder.getWidth() * -1);
			target.getElement('div').setStyle('right', 0);
		}

		new Element('div', {
			styles: styles
		}).adopt(image).inject(target, where);

		this.centerImage(image);

		target.setStyle('width', this.imageHolder.getWidth() * 2);

		var left = where == 'top' ? 0 : this.imageHolder.getWidth() * -1;

		this.setTitle(image.getParent());

		new Fx.Tween(target, {
			duration: this.options.fxDuration,
			transition: this.options.fxTransition
		}).start('left', left).chain(function () {
			// remove previous image
			if (where == 'bottom')
			{
				var div = target.getElement('div');
			}
			else
			{
				var div = target.getElements('div')[1];
			}
			div.dispose();

			// reset styles
			target.setStyles({
				left: 0,
				width: this.imageHolder.getWidth()
			});
			this.currentImage = i;
			this.busy = false;
		}.bind(this));
	},

	loadImage: function (el, i)
	{
		if (i == this.currentImage || this.busy)
		{
			return;
		}

		this.busy = true;

		this.loader.fade(1);

		var image = new Asset.image(el.get('href'), {
			title: el.getElement('img').get(this.options.titleSource),
			onload: function () {
				this.loader.fade(0);
				this.setActiveThumbnail(i);

				if (this.initialized)
				{
					this.insertImage(image, i);
				}
				else
				{
					new Element('div.images').adopt(
						new Element('div').adopt(
							image
						)
					).inject(this.imageHolder, 'top');
					this.centerImage(image);
					this.setTitle(image.getParent());
					this.currentImage = i;
					this.busy = false;
					this.initialized = true;
				}
			}.bind(this)
		});
	},

	next: function ()
	{
		var i = this.currentImage + 1;
		if (i >= this.thumbnails.length)
		{
			i = 0;
		}
		this.loadImage(this.thumbnails[i].getElement('a'), i);
	},

	previous: function ()
	{
		var i = this.currentImage - 1;
		if (i < 0)
		{
			i = this.thumbnails.length - 1;
		}
		this.loadImage(this.thumbnails[i].getElement('a'), i);
	},

	scroll: function (to)
	{
		// center thumbnail
		var center = (this.thumbnailHolder.getElement('div').getWidth() / 2).round();
		var limit = (this.thumbnailList.getWidth() - (center * 2) - this.thumbnails[0].retrieve('spacing'));

		var coordinates = {};
		var left = to;

		if (to != undefined)
		{
			coordinates = this.thumbnailList.getElement('.active').getCoordinates(this.thumbnailList);
			left = (coordinates.left - center + (coordinates.width / 2).round());
		}
		if (coordinates.left < center || to < 0)
		{
			left = 0;
		}
		else if (left >= limit)
		{
			left = limit;
		}

		if (left !== this.thumbnailList.getStyle('left').toInt())
		{
			new Fx.Tween(this.thumbnailList, {
				duration: 500,
				transition: 'quart:out'
			}).start('left', left * -1);
		}
	},

	scrollThumbnails: function (el)
	{
		var left;

		var thumbnailWidth = this.thumbnails[0].getWidth();
		left = this.thumbnailList.getStyle('left').toInt() * -1;

		if (el.get('class').test('left'))
		{
			this.scroll(left - (thumbnailWidth * this.options.scrollRange));
		}
		else
		{
			this.scroll(left + (thumbnailWidth * this.options.scrollRange));
		}
	},

	setActiveThumbnail: function (i)
	{
		var active = this.thumbnailHolder.getElement('.active');

		if (active)
		{
			active.removeClass('active');
		}

		this.thumbnails[i].addClass('active');

		if (!this.disableScrolling)
		{
			this.scroll();
		}
	},

	setTitle: function (target)
	{
		var image = target.getElement('img');
		var title = image.get('title');
		image.removeAttribute('title');

		if (title)
		{
			var span = new Element('span', {
				'class': 'image-title',
				html: '' + title + ''
			}).inject(target);

			if (this.options.animateTitle)
			{
				var imageCoordinates = image.getCoordinates(target);

				span.setStyles({
					bottom: imageCoordinates.top,
					opacity: 0,
					left: image.getStyle('margin-left').toInt(),
					width: imageCoordinates.width
				});

				new Fx.Morph(span, {}).start({
					height: [0, span.getHeight()],
					opacity: 1
				});
			}
		}
	}

});<commit_msg>fixed thumbnail centering<commit_after>/*
---
description: cwpGallery, yet another image gallery

license:
- MIT-style

authors:
- Johannes Fischer

requires:
- core/1.3: '*'
- more/1.3: 'Assets'

provides:
- cwpGallery

...
*/

var cwpGallery = new Class({

	Implements: Options,

	busy: false,
	currentImage: null,
	disableScrolling: false,
	initialized: false,

	options: {
		animateTitle: true,
		captionSource: 'title',
		enableKeys: true,
		fxDuration: 500,
		fxTransition: 'cubic:out',
		scrollRange: 4
	},

	initialize: function (element, options)
	{
		this.element = $(element);
		// Image container
		this.imageHolder = this.element.getElement('div');
		// Thumbnail container
		this.thumbnailHolder = null;
		// List elements
		this.thumbnailList = this.element.getElement('ul');
		this.thumbnails = this.element.getElements('li');

		this.setOptions(options);

		this.createControls();
		this.initThumbnails();
		this.createLoader();

		if (this.options.enableKeys)
		{
			this.attachKeyEvents();
		}
		this.loadImage(this.thumbnails[0].getElement('a'), 0);
	},

	attachKeyEvents: function ()
	{
		// TODO addEvent keydown doesn't work in FF
		document.body.addEvent('keydown', function (e) {
			var key = e.key;

			if (key === 'left')
			{
				this.previous();
			}
			if (key === 'right')
			{
				this.next();
			}
		}.bind(this));
	},

	centerImage: function (image)
	{
		var imageSize = image.getSize(),
			parentSize = image.getParent().getSize();

		// TODO hoehe des Titles von margin-top abziehen, wenn animation deaktiviert ist

		image.setStyles({
			marginLeft: ((parentSize.x - imageSize.x) / 2).round(),
			marginTop: ((parentSize.y - imageSize.y) / 2).round()
		});
	},

	createControls: function ()
	{
		var width = (this.imageHolder.getWidth() / 3).round();

		new Element('span', {
			'class': 'control-holder',
			events: {
				click: function () {
					this.previous();
				}.bind(this)
			},
			styles: {
				left: 0,
				width: width
			}
		}).grab(
			new Element('span', {
				'class': 'control-previous'
			})
		).inject(this.imageHolder);

		new Element('span', {
			'class': 'control-holder',
			events: {
				click: function () {
					this.next();
				}.bind(this)
			},
			styles: {
				right: 0,
				width: width
			}
		}).grab(
			new Element('span', {
				'class': 'control-next'
			})
		).inject(this.imageHolder);
	},

	createLoader: function ()
	{
		this.loader = new Element('div.loading', {
			styles: {
				opacity: 0
			}
		}).inject(this.imageHolder);
	},

	initThumbnails: function ()
	{
		var styles,
			leftControl,
			rightControl,
			width = 0;

		this.thumbnails.getElements('a').each(function (el, i) {
			el.addEvent('click', function (e) {
				e.stop();
				this.loadImage(el, i);
			}.bind(this));
		}, this);

		this.thumbnails.getElement('a').each(function (el) {
			width += el.getWidth();
		});

		styles = this.thumbnails[0].getStyles('margin-left', 'margin-right', 'padding-left', 'padding-right');

		Object.each(styles, function (el) {
			width += el.toInt() * this.thumbnails.length;
		}, this);

		this.thumbnailList.setStyle('width', width);

		this.thumbnailHolder = new Element('div.thumbnail-holder').inject(this.element);

		new Element('div').wraps(this.thumbnailList).inject(this.thumbnailHolder);

		if (width < this.thumbnailList.getParent().getWidth())
		{
			this.disableScrolling = true;
			return;
		}

		leftControl = new Element('span.scroll-left', {
			events: {
				click: function () {
					this.scrollThumbnails(leftControl);
				}.bind(this)
			}
		}).inject(this.thumbnailHolder);

		rightControl = new Element('span.scroll-right', {
			events: {
				click: function () {
					this.scrollThumbnails(rightControl);
				}.bind(this)
			}
		}).inject(this.thumbnailHolder);
	},

	insertImage: function (image, i)
	{
		var div,
			left,
			target = this.imageHolder.getElement('.images'),
			styles,
			where;

		// insert after current image
		if (i > this.currentImage)
		{
			styles = {
				right: 0
			};
			where = 'bottom';
		}
		// insert before current image
		else if (i < this.currentImage || (this.curentImage === 0 && i === this.thumbnails.length))
		{
			styles = {
				left: 0
			};
			where = 'top';
			target.setStyle('left', this.imageHolder.getWidth() * -1);
			target.getElement('div').setStyle('right', 0);
		}

		new Element('div', {
			styles: styles
		}).adopt(image).inject(target, where);

		this.centerImage(image);

		target.setStyle('width', this.imageHolder.getWidth() * 2);

		left = where === 'top' ? 0 : this.imageHolder.getWidth() * -1;

		this.setTitle(image.getParent());

		new Fx.Tween(target, {
			duration: this.options.fxDuration,
			transition: this.options.fxTransition
		}).start('left', left).chain(function () {
			// remove previous image
			if (where === 'bottom')
			{
				div = target.getElement('div');
			}
			else
			{
				div = target.getElements('div')[1];
			}
			div.dispose();

			// reset styles
			target.setStyles({
				left: 0,
				width: this.imageHolder.getWidth()
			});
			this.currentImage = i;
			this.busy = false;
		}.bind(this));
	},

	loadImage: function (el, i)
	{
		if (i === this.currentImage || this.busy)
		{
			return;
		}

		this.busy = true;

		this.loader.fade(1);

		var image = new Asset.image(el.get('href'), {
			title: el.getElement('img').get(this.options.titleSource),
			onload: function () {
				this.loader.fade(0);
				this.setActiveThumbnail(i);

				if (this.initialized)
				{
					this.insertImage(image, i);
				}
				else
				{
					new Element('div.images').adopt(
						new Element('div').adopt(
							image
						)
					).inject(this.imageHolder, 'top');
					this.centerImage(image);
					this.setTitle(image.getParent());
					this.currentImage = i;
					this.busy = false;
					this.initialized = true;
				}
			}.bind(this)
		});
	},

	next: function ()
	{
		var i = this.currentImage + 1;
		if (i >= this.thumbnails.length)
		{
			i = 0;
		}
		this.loadImage(this.thumbnails[i].getElement('a'), i);
	},

	previous: function ()
	{
		var i = this.currentImage - 1;
		if (i < 0)
		{
			i = this.thumbnails.length - 1;
		}
		this.loadImage(this.thumbnails[i].getElement('a'), i);
	},

	scroll: function (to)
	{
		var center,
			coordinates = {},
			left = to,
			limit;

		center = (this.thumbnailHolder.getElement('div').getWidth() / 2).round();
		limit = (this.thumbnailList.getWidth() - (center * 2));

		if (to === undefined)
		{
			coordinates = this.thumbnailList.getElement('.active').getCoordinates(this.thumbnailList);
			left = (coordinates.left - center + (coordinates.width / 2).round());
		}

		if (coordinates.left < center || to < 0)
		{
			left = 0;
		}
		else if (left >= limit)
		{
			left = limit;
		}

		if (left !== this.thumbnailList.getStyle('left').toInt())
		{
			new Fx.Tween(this.thumbnailList, {
				duration: 500,
				transition: 'quart:out'
			}).start('left', left * -1);
		}
	},

	scrollThumbnails: function (el)
	{
		var left = this.thumbnailList.getStyle('left').toInt() * -1,
			thumbnailWidth = this.thumbnails[0].getWidth();

		if (el.get('class').test('left'))
		{
			this.scroll(left - (thumbnailWidth * this.options.scrollRange));
		}
		else
		{
			this.scroll(left + (thumbnailWidth * this.options.scrollRange));
		}
	},

	setActiveThumbnail: function (i)
	{
		var active = this.thumbnailHolder.getElement('.active');

		if (active)
		{
			active.removeClass('active');
		}

		this.thumbnails[i].addClass('active');

		if (!this.disableScrolling)
		{
			this.scroll();
		}
	},

	setTitle: function (target)
	{
		var image = target.getElement('img'),
			imageCoordinates,
			span,
			title = image.get('title');

		image.removeAttribute('title');

		if (title)
		{
			span = new Element('span', {
				'class': 'image-title',
				html: '' + title + ''
			}).inject(target);

			if (this.options.animateTitle)
			{
				imageCoordinates = image.getCoordinates(target);

				span.setStyles({
					bottom: imageCoordinates.top,
					opacity: 0,
					left: image.getStyle('margin-left').toInt(),
					width: imageCoordinates.width
				});

				new Fx.Morph(span, {}).start({
					height: [0, span.getHeight()],
					opacity: 1
				});
			}
		}
	}

});<|endoftext|>


<commit_before>var socket = io.connect(window.location.href);

$(document).ready(function() {

  $('#song-count').text($('.track').length + ' tracks')

  // Get total time
  var total = 0;
  $('.time').each(function(index) {
    total += $(this).data('time');
  });
  var time = moment.duration({s: total });
  var hours = ' hours ';
  var minutes = ' minutes';

  if (time.hours() === 1) hours = ' hour ';
  if (time.minutes() === 1) minutes = ' minute';

  $('#total-time').text(time.hours() + hours + time.minutes() + minutes);

  /**
   * Socket.io and stuff.
   */

  socket.on('connect', function() {

    if (localStorage.getItem('isHost')) {
      socket.emit('hostComeback', this.socket.sessionid);
      socket.emit('checkIfHost', this.socket.sessionid);
    }

    socket.emit('checkIfHost', this.socket.sessionid);
    socket.on('checkIfHostAnswer', function(isHost) {
      if (!isHost) {
        console.log('You are not a host');
        $('#play').unbind('click');
        $('.track').unbind('dblclick');
        $('#pause').unbind('click');
        $('#forward').unbind('click');
        $('#backward').unbind('click');
        $('.guest-mode').show();
      } else {
        console.log('Yes you are a host');
        $('.host-mode').show();
        localStorage.setItem('isHost', true);

        // If host, set localstorage variable isHost = true
        // When disconnected, check on server if host is disconnected.
        // If it is, create a 60 sec timeout, after which hostId is next socket in line
        // If host comes back within 60 sec, clear the timeout

      }
    });

  });

  var latency;
  var latencyInterval;
  var isPlaying = false;
  var startTime;
  var latencyArray = [];

  var $track = $('.track');
  var $playlistControls = $('.playlist-controls');
  var $sync = $('.sync');
  var $highlight = $('.highlight');
  var $sync = $('.sync');
  socket.on('pong', function() {
    latency = Date.now() - startTime;
    console.log(latency)
    if (latency > 1) latencyArray.push(latency);
    $sync.text('Ping: ' + latency + ' ms');
  });

  socket.on('everyone_ping', function() {
    latencyInterval = setInterval (function() {
      startTime = Date.now();
      socket.emit('ping');
    }, 10);
  });

  $track.dblclick(function (e) {

    // Cleanup service
    $('audio').remove();
    $playlistControls.removeClass('fadeInDown animated');

    // Prevent playback of the same track that is currently playing
    if ($(e.target).parent().hasClass('highlight')) {
      return;
    }

    isPlaying = true;

    $sync.show();

    // Highlight current track when user double clicks on it
    if (e.originalEvent !== undefined) {
      $highlight.removeClass('highlight');
      $(this).addClass('highlight');
    }

    // Pause currently playing track first
    socket.emit('pause');

    // update ping
    socket.emit('startping');

    // Step 2
    // Tell server that we want to play a song, by passing a track id.
    // Start with a 0.5s delay to give time for synchronization.
    var self = this;
    setTimeout(function() {
      console.log('initiating play');

      socket.emit('initiatePlay', {
        id: $(self).find('.id').text(),
        file: $(self).find('.file').text(),
        name: $(self).find('.name').text(),
        time: $(self).find('.time').text(),
        artist: $(self).find('.artist').text(),
        album: $(self).find('.album').text(),
        genre: $(self).find('.genre').text()
      });

    }, 1000);
  });

  // Step 3
  // Start playing with the latency offset.
  // This happens after server receives initiatePlay event
  socket.on('beginPlaying', function (data) {
    console.log('Begin Playing');
    // No longer need to show synchronizing.. message
    $('.sync').hide();

    // Find track by id and add highlight class for other clients
    $('.highlight').removeClass('highlight');
    $('.id:contains(' + data.id + ')').first().parent().addClass('highlight');

    $('.playlist-controls').text(data.name);
    $('.playlist-controls').addClass('fadeInDown animated');

    var player = '<audio class="player">' +
      '<source src="/uploads/' + data.file + '" type="audio/mpeg">' +
      '</audio>';

    $(player).insertAfter('#playlist');
    var audio = $('.player').get(0);

    function updateProgress() {
      var value = 0;
      if (audio.currentTime > 0) {
        // value = Math.floor((100 / audio.duration) * audio.currentTime);

        var time = moment.duration({s: audio.currentTime });
        var prettyTime = moment().startOf('day').add(time).format('m:ss');
        $('#currentTime').text(prettyTime);
      }

      var time2 = moment.duration({s: audio.duration });
      var prettyTime2 = moment().startOf('day').add(time2).format('m:ss');
      $('#timeLeft').text(prettyTime2);

      // $trackProgressBar.css('width', value + '%');
    }

    audio.addEventListener('timeupdate', updateProgress, false);

    console.log('starting music now...');

    var averageLatency;
    var total = 0;

    for (var i = 0; i < latencyArray.length; i++) {
      total += latencyArray[i];
    }

    averageLatency = total / latencyArray.length;

    console.log('Average: ' + averageLatency);

    audio.addEventListener('canplaythrough', function() {
      console.log('loaded audio metadata');

      this.currentTime = averageLatency / 1000;

      // Start music playback here with the latency offset
      setTimeout(function() {
        console.log('PLAYING!!!!');
        audio.play();
      }, averageLatency);
    });

    clearInterval(latencyInterval);

    console.log('cleared interval');
  });

  $('#play').click(function(player) {
    if (isPlaying) {
      return;
    }
    $('.track').first().trigger('dblclick');
  });

  $('#pause').click(function () {
    isPlaying = false;
    clearInterval(latencyInterval);
    socket.emit('pause');
  });

  $('#forward').click(function() {
    if (isPlaying) {
      $('.highlight').next().trigger('dblclick');
    }
  });

  $('#backward').click(function() {
    if (isPlaying) {
      $('.highlight').prev().trigger('dblclick');
    }
  });

// Display number of connected users
  socket.on('count', function (data) {
    // clear everything in the dropdown menu
    $('.connected-counter ul.dropdown-menu').html('');
    for (var i = 0; i < data.clients.length; i++) {
      var client = data.clients[i];
      console.log(client)
      $('.connected-counter ul.dropdown-menu').append('
' + client.address.address + '
')
    }
    console.log(data.clients);
    $('#numberOfClients').hide().fadeIn(200).text(data.numberOfClients);
  });

// Pause currently playing track.
  socket.on('halt', function (data) {
    $.each($('audio'), function () {
      this.pause();
    });
  });

  /**
   * Table List
   * @type {{valueNames: string[]}}
   */
  var options = {
    valueNames: ['id', 'name', 'time', 'artist', 'album', 'genre']
  };

  // Init list
  var playlist = new List('playlist', options);

  $('.search').keyup(function() {
    playlist.search($(this).val());
  });

  /**
   * File Upload
   */

  var $progrecss = $('.progrecss');

  $('#fileupload').fileupload({
    dataType: 'json',
    submit: function(event, data) {
      $progrecss.fadeIn(200)
    },
    stop: function() {
      $progrecss
        .delay(1500)
        .fadeOut(800)
        .queue(function(next) {
          $(this).attr('data-progrecss', 0);
          next();
        });
    },
    progressall: function (event, data) {
      var progress = parseInt(data.loaded / data.total * 100, 10);
      $progrecss.attr('data-progrecss', progress);
    }
  });

  /**
   * Convert track duration in secs to m:ss format
   * E.g. 187 to 3:07
   */
  $('.time').each(function(index) {
    var time = moment.duration({s: $(this).text() });
    var prettyTime = moment().startOf('day').add(time).format('m:ss')
    $(this).text(prettyTime);
  });

});

<commit_msg>Reduced ping delay<commit_after>var socket = io.connect(window.location.href);

$(document).ready(function() {

  $('#song-count').text($('.track').length + ' tracks')

  // Get total time
  var total = 0;
  $('.time').each(function(index) {
    total += $(this).data('time');
  });
  var time = moment.duration({s: total });
  var hours = ' hours ';
  var minutes = ' minutes';

  if (time.hours() === 1) hours = ' hour ';
  if (time.minutes() === 1) minutes = ' minute';

  $('#total-time').text(time.hours() + hours + time.minutes() + minutes);

  /**
   * Socket.io and stuff.
   */

  socket.on('connect', function() {

    if (localStorage.getItem('isHost')) {
      socket.emit('hostComeback', this.socket.sessionid);
      socket.emit('checkIfHost', this.socket.sessionid);
    }

    socket.emit('checkIfHost', this.socket.sessionid);
    socket.on('checkIfHostAnswer', function(isHost) {
      if (!isHost) {
        console.log('You are not a host');
        $('#play').unbind('click');
        $('.track').unbind('dblclick');
        $('#pause').unbind('click');
        $('#forward').unbind('click');
        $('#backward').unbind('click');
        $('.guest-mode').show();
      } else {
        console.log('Yes you are a host');
        $('.host-mode').show();
        localStorage.setItem('isHost', true);

        // If host, set localstorage variable isHost = true
        // When disconnected, check on server if host is disconnected.
        // If it is, create a 60 sec timeout, after which hostId is next socket in line
        // If host comes back within 60 sec, clear the timeout

      }
    });

  });

  var latency;
  var latencyInterval;
  var isPlaying = false;
  var startTime;
  var latencyArray = [];

  var $track = $('.track');
  var $playlistControls = $('.playlist-controls');
  var $sync = $('.sync');
  var $highlight = $('.highlight');
  var $sync = $('.sync');
  socket.on('pong', function() {
    latency = Date.now() - startTime;
    console.log(latency)
    if (latency > 1) latencyArray.push(latency);
    $sync.text('Ping: ' + latency + ' ms');
  });

  socket.on('everyone_ping', function() {
    latencyInterval = setInterval (function() {
      startTime = Date.now();
      socket.emit('ping');
    }, 10);
  });

  $track.dblclick(function (e) {

    // Cleanup service
    $('audio').remove();
    $playlistControls.removeClass('fadeInDown animated');

    // Prevent playback of the same track that is currently playing
    if ($(e.target).parent().hasClass('highlight')) {
      return;
    }

    isPlaying = true;

    $sync.show();

    // Highlight current track when user double clicks on it
    if (e.originalEvent !== undefined) {
      $highlight.removeClass('highlight');
      $(this).addClass('highlight');
    }

    // Pause currently playing track first
    socket.emit('pause');

    // update ping
    socket.emit('startping');

    // Step 2
    // Tell server that we want to play a song, by passing a track id.
    // Start with a 0.5s delay to give time for synchronization.
    var self = this;
    setTimeout(function() {
      console.log('initiating play');

      socket.emit('initiatePlay', {
        id: $(self).find('.id').text(),
        file: $(self).find('.file').text(),
        name: $(self).find('.name').text(),
        time: $(self).find('.time').text(),
        artist: $(self).find('.artist').text(),
        album: $(self).find('.album').text(),
        genre: $(self).find('.genre').text()
      });

    }, 400);
  });

  // Step 3
  // Start playing with the latency offset.
  // This happens after server receives initiatePlay event
  socket.on('beginPlaying', function (data) {
    console.log('Begin Playing');
    // No longer need to show synchronizing.. message
    $('.sync').hide();

    // Find track by id and add highlight class for other clients
    $('.highlight').removeClass('highlight');
    $('.id:contains(' + data.id + ')').first().parent().addClass('highlight');

    $('.playlist-controls').text(data.name);
    $('.playlist-controls').addClass('fadeInDown animated');

    var player = '<audio class="player">' +
      '<source src="/uploads/' + data.file + '" type="audio/mpeg">' +
      '</audio>';

    $(player).insertAfter('#playlist');
    var audio = $('.player').get(0);

    function updateProgress() {
      var value = 0;
      if (audio.currentTime > 0) {
        // value = Math.floor((100 / audio.duration) * audio.currentTime);

        var time = moment.duration({s: audio.currentTime });
        var prettyTime = moment().startOf('day').add(time).format('m:ss');
        $('#currentTime').text(prettyTime);
      }

      var time2 = moment.duration({s: audio.duration });
      var prettyTime2 = moment().startOf('day').add(time2).format('m:ss');
      $('#timeLeft').text(prettyTime2);

      // $trackProgressBar.css('width', value + '%');
    }

    audio.addEventListener('timeupdate', updateProgress, false);

    console.log('starting music now...');

    var averageLatency;
    var total = 0;

    for (var i = 0; i < latencyArray.length; i++) {
      total += latencyArray[i];
    }

    averageLatency = total / latencyArray.length;

    console.log('Average: ' + averageLatency);

    setTimeout(function() {
      console.log('PLAYING!!!!');
      audio.play();
    }, averageLatency);

//    audio.addEventListener('canplaythrough', function() {
//      console.log('loaded audio metadata');
//
//      this.currentTime = averageLatency / 1000;
//
//      // Start music playback here with the latency offset
//
//    });

    clearInterval(latencyInterval);

    console.log('cleared interval');
  });

  $('#play').click(function(player) {
    if (isPlaying) {
      return;
    }
    $('.track').first().trigger('dblclick');
  });

  $('#pause').click(function () {
    isPlaying = false;
    clearInterval(latencyInterval);
    socket.emit('pause');
  });

  $('#forward').click(function() {
    if (isPlaying) {
      $('.highlight').next().trigger('dblclick');
    }
  });

  $('#backward').click(function() {
    if (isPlaying) {
      $('.highlight').prev().trigger('dblclick');
    }
  });

// Display number of connected users
  socket.on('count', function (data) {
    // clear everything in the dropdown menu
    $('.connected-counter ul.dropdown-menu').html('');
    for (var i = 0; i < data.clients.length; i++) {
      var client = data.clients[i];
      console.log(client)
      $('.connected-counter ul.dropdown-menu').append('
' + client.address.address + '
')
    }
    console.log(data.clients);
    $('#numberOfClients').hide().fadeIn(200).text(data.numberOfClients);
  });

// Pause currently playing track.
  socket.on('halt', function (data) {
    $.each($('audio'), function () {
      this.pause();
    });
  });

  /**
   * Table List
   * @type {{valueNames: string[]}}
   */
  var options = {
    valueNames: ['id', 'name', 'time', 'artist', 'album', 'genre']
  };

  // Init list
  var playlist = new List('playlist', options);

  $('.search').keyup(function() {
    playlist.search($(this).val());
  });

  /**
   * File Upload
   */

  var $progrecss = $('.progrecss');

  $('#fileupload').fileupload({
    dataType: 'json',
    submit: function(event, data) {
      $progrecss.fadeIn(200)
    },
    stop: function() {
      $progrecss
        .delay(1500)
        .fadeOut(800)
        .queue(function(next) {
          $(this).attr('data-progrecss', 0);
          next();
        });
    },
    progressall: function (event, data) {
      var progress = parseInt(data.loaded / data.total * 100, 10);
      $progrecss.attr('data-progrecss', progress);
    }
  });

  /**
   * Convert track duration in secs to m:ss format
   * E.g. 187 to 3:07
   */
  $('.time').each(function(index) {
    var time = moment.duration({s: $(this).text() });
    var prettyTime = moment().startOf('day').add(time).format('m:ss')
    $(this).text(prettyTime);
  });

});

<|endoftext|>


<commit_before>var socket = io.connect(window.location.href);

$(document).ready(function() {

  $('#song-count').text($('.track').length + ' tracks')

  // Get total time
  var total = 0;
  $('.time').each(function(index) {
    total += $(this).data('time');
  });
  var time = moment.duration({s: total });
  var hours = ' hours ';
  var minutes = ' minutes';

  if (time.hours() === 1) hours = ' hour ';
  if (time.minutes() === 1) minutes = ' minute';

  $('#total-time').text(time.hours() + hours + time.minutes() + minutes);

  socket.on('connect', function() {
    if (localStorage.getItem('isHost')) {
      socket.emit('hostComeback', this.socket.sessionid);
      socket.emit('checkIfHost', this.socket.sessionid);
    }

    socket.emit('checkIfHost', this.socket.sessionid);
    socket.on('checkIfHostAnswer', function(isHost) {
      if (!isHost) {
        console.log('You are not a host');
        $('#play').unbind('click');
        $('.track').unbind('dblclick');
        $('#pause').unbind('click');
        $('#forward').unbind('click');
        $('#backward').unbind('click');
        $('.guest-mode').show();
      } else {
        console.log('Yes you are a host');
        $('.host-mode').show();
        localStorage.setItem('isHost', true);

        // If host, set localstorage variable isHost = true
        // When disconnected, check on server if host is disconnected.
        // If it is, create a 60 sec timeout, after which hostId is next socket in line
        // If host comes back within 60 sec, clear the timeout

      }
    });

  });

  var latency;
  var latencyInterval;
  var isPlaying = false;
  var startTime;

  socket.on('pong', function() {
    latency = Date.now() - startTime;
  });

  $('#play').click(function(player) {
    if (isPlaying) {
      return;
    }
    $('.track').first().trigger('dblclick');
  });

  $('#pause').click(function () {
    isPlaying = false;
    clearInterval(latencyInterval);
    socket.emit('pause');
  });

  $('#forward').click(function() {
    if (isPlaying) {
      $('.highlight').next().trigger('dblclick');
    }
  });

  $('#backward').click(function() {
    if (isPlaying) {
      $('.highlight').prev().trigger('dblclick');
    }
  });

  // Display number of connected users
  socket.on('count', function (data) {
    // clear everything in the dropdown menu
    $('.connected-counter ul.dropdown-menu').html('');
    for (var i = 0; i < data.clients.length; i++) {
      var client = data.clients[i];
      console.log(client)
      $('.connected-counter ul.dropdown-menu').append('
' + client.address.address + '
')
    }
    console.log(data.clients);
    $('#numberOfClients').hide().fadeIn(200).text(data.numberOfClients);
  });
});<commit_msg>Added halt socket.io event that stops the playback after pause event has been triggered<commit_after>var socket = io.connect(window.location.href);

$(document).ready(function() {

  $('#song-count').text($('.track').length + ' tracks')

  // Get total time
  var total = 0;
  $('.time').each(function(index) {
    total += $(this).data('time');
  });
  var time = moment.duration({s: total });
  var hours = ' hours ';
  var minutes = ' minutes';

  if (time.hours() === 1) hours = ' hour ';
  if (time.minutes() === 1) minutes = ' minute';

  $('#total-time').text(time.hours() + hours + time.minutes() + minutes);

  socket.on('connect', function() {
    if (localStorage.getItem('isHost')) {
      socket.emit('hostComeback', this.socket.sessionid);
      socket.emit('checkIfHost', this.socket.sessionid);
    }

    socket.emit('checkIfHost', this.socket.sessionid);
    socket.on('checkIfHostAnswer', function(isHost) {
      if (!isHost) {
        console.log('You are not a host');
        $('#play').unbind('click');
        $('.track').unbind('dblclick');
        $('#pause').unbind('click');
        $('#forward').unbind('click');
        $('#backward').unbind('click');
        $('.guest-mode').show();
      } else {
        console.log('Yes you are a host');
        $('.host-mode').show();
        localStorage.setItem('isHost', true);

        // If host, set localstorage variable isHost = true
        // When disconnected, check on server if host is disconnected.
        // If it is, create a 60 sec timeout, after which hostId is next socket in line
        // If host comes back within 60 sec, clear the timeout

      }
    });

  });

  var latency;
  var latencyInterval;
  var isPlaying = false;
  var startTime;

  socket.on('pong', function() {
    latency = Date.now() - startTime;
  });

  $('#play').click(function(player) {
    if (isPlaying) {
      return;
    }
    $('.track').first().trigger('dblclick');
  });

  $('#pause').click(function () {
    isPlaying = false;
    clearInterval(latencyInterval);
    socket.emit('pause');
  });

  $('#forward').click(function() {
    if (isPlaying) {
      $('.highlight').next().trigger('dblclick');
    }
  });

  $('#backward').click(function() {
    if (isPlaying) {
      $('.highlight').prev().trigger('dblclick');
    }
  });

  // Display number of connected users
  socket.on('count', function (data) {
    // clear everything in the dropdown menu
    $('.connected-counter ul.dropdown-menu').html('');
    for (var i = 0; i < data.clients.length; i++) {
      var client = data.clients[i];
      console.log(client)
      $('.connected-counter ul.dropdown-menu').append('
' + client.address.address + '
')
    }
    console.log(data.clients);
    $('#numberOfClients').hide().fadeIn(200).text(data.numberOfClients);
  });

  socket.on('halt', function (data) {
    $.each($('audio'), function () {
      this.pause();
    });
  });

});<|endoftext|>


<commit_before>function register_onload(func) {
  Event.observe(window, 'load', func, false);
}

function show_dates_as_local_time() {
  var spans = document.getElementsByTagName('span');
  for (var i=0; i<spans.length; i++) {
    if (spans[i].className.match(/\btypo_date\b/i)) {
      spans[i].innerHTML = get_local_time_for_date(spans[i].title);
    }
  }
}

function get_local_time_for_date(time) {
  system_date = new Date(time);
  user_date = new Date();
  delta_minutes = Math.floor((user_date - system_date) / (60 * 1000));
  if (Math.abs(delta_minutes) <= (8*7*24*60)) { // eight weeks... I'm lazy to count days for longer than that
    distance = distance_of_time_in_words(delta_minutes);
    if (delta_minutes < 0) {
      return distance + ' from now';
    } else {
      return distance + ' ago';
    }
  } else {
    return 'on ' + system_date.toLocaleDateString();
  }
}

// a vague copy of rails' inbuilt function,
// but a bit more friendly with the hours.
function distance_of_time_in_words(minutes) {
  if (minutes.isNaN) return "";
  minutes = Math.abs(minutes);
  if (minutes < 1) return ('less than a minute');
  if (minutes < 50) return (minutes + ' minute' + (minutes == 1 ? '' : 's'));
  if (minutes < 90) return ('about one hour');
  if (minutes < 1080) return (Math.round(minutes / 60) + ' hours');
  if (minutes < 1440) return ('one day');
  if (minutes < 2880) return ('about one day');
  else return (Math.round(minutes / 1440) + ' days')
}

function commentAdded(request) {
  new Effect.BlindDown($('commentList').lastChild);
  if ($('dummy_comment')) { Element.remove('dummy_comment'); }
  $('commentform').elements[3].value = '';
  $('commentform').elements[3].focus();
}

function failure(request) {
  $('errors').innerHTML = request.responseText;
  new Effect.Highlight('errors');
}

function loading() {
  $('form-submit-button').disabled = true;
  Element.show('comment_loading');
  new Element.hide('preview');
}

function complete(request) {
  Element.hide('comment_loading');
  Element.show('commentform');
  $('form-submit-button').disabled = false;

  if (request.status == 200) { commentAdded() };
}

register_onload(function() {
  if ($('commentform')) {
	var _author = getCookie('author');
	var _url = getCookie('url');

    if(_author != null) { $('commentform').elements['comment[author]'].value = _author }
    if(_url != null) { $('commentform').elements['comment[url]'].value = _url }

    if ($('commentform').elements['comment[url]'].value != ''
        || $('commentform').elements['comment[email]'].value != '') {
      Element.show('guest_url'); Element.show('guest_email');
    }
  }
})
register_onload(function() { if ($('q')) {$('q').setAttribute('autocomplete', 'off');} })<commit_msg>Commit patch for #682 - should fix AJAX comment effect on Mozilla-based browsers for some themes<commit_after>function register_onload(func) {
  Event.observe(window, 'load', func, false);
}

function show_dates_as_local_time() {
  var spans = document.getElementsByTagName('span');
  for (var i=0; i<spans.length; i++) {
    if (spans[i].className.match(/\btypo_date\b/i)) {
      spans[i].innerHTML = get_local_time_for_date(spans[i].title);
    }
  }
}

function get_local_time_for_date(time) {
  system_date = new Date(time);
  user_date = new Date();
  delta_minutes = Math.floor((user_date - system_date) / (60 * 1000));
  if (Math.abs(delta_minutes) <= (8*7*24*60)) { // eight weeks... I'm lazy to count days for longer than that
    distance = distance_of_time_in_words(delta_minutes);
    if (delta_minutes < 0) {
      return distance + ' from now';
    } else {
      return distance + ' ago';
    }
  } else {
    return 'on ' + system_date.toLocaleDateString();
  }
}

// a vague copy of rails' inbuilt function,
// but a bit more friendly with the hours.
function distance_of_time_in_words(minutes) {
  if (minutes.isNaN) return "";
  minutes = Math.abs(minutes);
  if (minutes < 1) return ('less than a minute');
  if (minutes < 50) return (minutes + ' minute' + (minutes == 1 ? '' : 's'));
  if (minutes < 90) return ('about one hour');
  if (minutes < 1080) return (Math.round(minutes / 60) + ' hours');
  if (minutes < 1440) return ('one day');
  if (minutes < 2880) return ('about one day');
  else return (Math.round(minutes / 1440) + ' days')
}

function commentAdded(request) {
  Element.cleanWhitespace('commentList');
  new Effect.BlindDown($('commentList').lastChild);
  if ($('dummy_comment')) { Element.remove('dummy_comment'); }
  $('commentform').elements[3].value = '';
  $('commentform').elements[3].focus();
}

function failure(request) {
  $('errors').innerHTML = request.responseText;
  new Effect.Highlight('errors');
}

function loading() {
  $('form-submit-button').disabled = true;
  Element.show('comment_loading');
  new Element.hide('preview');
}

function complete(request) {
  Element.hide('comment_loading');
  Element.show('commentform');
  $('form-submit-button').disabled = false;

  if (request.status == 200) { commentAdded() };
}

register_onload(function() {
  if ($('commentform')) {
	var _author = getCookie('author');
	var _url = getCookie('url');

    if(_author != null) { $('commentform').elements['comment[author]'].value = _author }
    if(_url != null) { $('commentform').elements['comment[url]'].value = _url }

    if ($('commentform').elements['comment[url]'].value != ''
        || $('commentform').elements['comment[email]'].value != '') {
      Element.show('guest_url'); Element.show('guest_email');
    }
  }
})
register_onload(function() { if ($('q')) {$('q').setAttribute('autocomplete', 'off');} })<|endoftext|>


<commit_before>$(function(){
  var mapModel;
  //var canvasSize= { width:  $('#container').width(), height: $('#container').height()};
  var canvasSize= { width:  100, height: 100};

  showAlert("creating canvas of ",JSON.stringify(canvasSize)) ;

  var initCanvas=function(idea){
    var stage = new Kinetic.Stage($.extend(canvasSize,{
      container: 'container',
      draggable:true
    })),
    dimensionProvider = function (title) {
      var text = new Kinetic.Idea({
        text: title
      });
      return {
        width: text.getWidth(),
        height: text.getHeight()
      };
    };
    stage.attrs.x = 0.5 * stage.getWidth();
	  stage.attrs.y = 0.5 * stage.getHeight();

mapModel = new MAPJS.MapModel(function layoutCalculator(idea) {
  return MAPJS.calculateLayout(idea, dimensionProvider);
});
var mediator = new MAPJS.KineticMediator(mapModel, stage);
mapModel.setIdea(idea);
}
var attachTooltips=function(){
  _.each($('[rel=tooltip]'),function(item){ $(item).tooltip({placement:'bottom',title:$(item).attr('title')})});
}
var attach_menu_listeners=function(active_content){
  var changed=false;
  var publishMap = function(result) {
    var publishTime=Date.now();
    logMapActivity('Publish',result.key);
    $("#s3form [name='file']").val("window.map=" + JSON.stringify(active_content));
    for (var name in result) {$('#s3form [name='+name+']').val(result[name])};
    $('#s3form').submit();
  }
  active_content.addEventSink(function() {
    if (!changed) {
      $("#toolbarShare").hide();
      $("#toolbarSave").show();
      logMapActivity('Edit');
      changed = true;
    }
    logUserActivity(_.toArray(arguments));
  });
  $('#menuAdd').click(mapModel.addSubIdea.bind(mapModel, 'double click to edit'));
  $('#menuEdit').click(mapModel.editNode);
  $('#menuDelete').click(mapModel.removeSubIdea);
  $('#menuClear').click(mapModel.clear);
  $("#menuPublish").click(function(){
    $.getJSON("/publishingConfig", publishMap);
  });
}
function updateTitle(newTitle){
  document.title=newTitle;
  $('.st_btn').attr('st_title',newTitle);
  $('.brand').text(newTitle);
}
var load_content = function (jsonDocument) {
  var idea = content(jsonDocument);
  initCanvas(idea);
  attach_menu_listeners(idea);
  logMapActivity('View');
  updateTitle(idea.title);
};
load_content(window.map);
attachTooltips();
});
<commit_msg>temporary debug for ipad<commit_after>$(function(){
  var mapModel;
  var canvasSize= { width:  $('#container').width(), height: $('#container').height()};
  //var canvasSize= { width:  100, height: 100};
  showAlert("creating canvas of ",JSON.stringify(canvasSize)) ;

  var initCanvas=function(idea){
    var stage = new Kinetic.Stage($.extend(canvasSize,{
      container: 'container',
      draggable:true
    })),
    dimensionProvider = function (title) {
      var text = new Kinetic.Idea({
        text: title
      });
      return {
        width: text.getWidth(),
        height: text.getHeight()
      };
    };
    stage.attrs.x = 0.5 * stage.getWidth();
	  stage.attrs.y = 0.5 * stage.getHeight();

mapModel = new MAPJS.MapModel(function layoutCalculator(idea) {
  return MAPJS.calculateLayout(idea, dimensionProvider);
});
var mediator = new MAPJS.KineticMediator(mapModel, stage);
mapModel.setIdea(idea);
}
var attachTooltips=function(){
  _.each($('[rel=tooltip]'),function(item){ $(item).tooltip({placement:'bottom',title:$(item).attr('title')})});
}
var attach_menu_listeners=function(active_content){
  var changed=false;
  var publishMap = function(result) {
    var publishTime=Date.now();
    logMapActivity('Publish',result.key);
    $("#s3form [name='file']").val("window.map=" + JSON.stringify(active_content));
    for (var name in result) {$('#s3form [name='+name+']').val(result[name])};
    $('#s3form').submit();
  }
  active_content.addEventSink(function() {
    if (!changed) {
      $("#toolbarShare").hide();
      $("#toolbarSave").show();
      logMapActivity('Edit');
      changed = true;
    }
    logUserActivity(_.toArray(arguments));
  });
  $('#menuAdd').click(mapModel.addSubIdea.bind(mapModel, 'double click to edit'));
  $('#menuEdit').click(mapModel.editNode);
  $('#menuDelete').click(mapModel.removeSubIdea);
  $('#menuClear').click(mapModel.clear);
  $("#menuPublish").click(function(){
    $.getJSON("/publishingConfig", publishMap);
  });
}
function updateTitle(newTitle){
  document.title=newTitle;
  $('.st_btn').attr('st_title',newTitle);
  $('.brand').text(newTitle);
}
var load_content = function (jsonDocument) {
  var idea = content(jsonDocument);
  initCanvas(idea);
  attach_menu_listeners(idea);
  logMapActivity('View');
  updateTitle(idea.title);
};
load_content(window.map);
attachTooltips();
});
<|endoftext|>


<commit_before>!function($) {

    function DocumentArray() {

        this.editingArray = undefined;
        this.editingObject = undefined;
        this.editingIndex = undefined;
        this.formHtml = {};
        this.editingFor = undefined;
        this.listTemplate = undefined;

    }

    DocumentArray.prototype.setLabel = function (document) {

        if (!document.label) {

            if (document.title) {
                document.label = document.title
            }

            if (document.firstName) {

                document.label = document.firstName;

                if (document.surname) {
                    document.label += ' ' + document.surname;
                }

                if (document.lastName) {
                    document.label += ' ' + document.lastName;
                }

            }

        }

        return document;

    };

    DocumentArray.prototype.drawDocuments = function (documentArrayInstance, documents) {

        var da = this,
            setLabel = this.setLabel;

        // check if there is a custom setLabel for this documentarray
        if ($('[data-document-field-for="' + documentArrayInstance + '"]').attr('data-document-set-label') !== undefined) {
            setLabel = linz.documents[documentArrayInstance + 'SetLabel'];
        }

        // loop through each document and ensure there is a label
        for (var i = 0; i < documents.length; i++) {
            documents[i] = setLabel(documents[i]);
        }

        documents = { documents: documents };

        $('[data-document-field-for="' + documentArrayInstance + '"] .documents').html(this.listTemplate(documents));

        if (da.canEdit) {

            // now bind the documents, handle the edit button
            $('[data-document-field-for="' + documentArrayInstance + '"]').find('a[data-document-action="edit"]').click(function () {

                $('#documentsModal .edit-actions .btn-save').unbind('click');
                $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                $('#documentsModal .delete-actions .btn-save').unbind('click');
                $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                $('#documentsModal button.close').unbind('click');

                $('#documentsModal .edit-actions .btn-save').click(function () {  da.saveAction(); });
                $('#documentsModal .edit-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal .delete-actions .btn-save').click(function () {  da.deleteAction(); });
                $('#documentsModal .delete-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal button.close').click(function () { da.closeAction(); });

                da.editingFor = documentArrayInstance;

                da.editingIndex = $(this).parent().attr('data-document-index');

                // now grab the array if there already is one and turn it into a JavaScript object
                da.editingArray = JSON.parse($('[data-document-field-for="' + documentArrayInstance + '"]').find('input[type="hidden"][name="' + documentArrayInstance + '"]').val());

                da.editingObject = da.editingArray[da.editingIndex];

                da.editDocument(documentArrayInstance);

            });

        }

        if (da.canDelete) {

            // now bind the documents, handle the delete button
            $('[data-document-field-for="' + documentArrayInstance + '"]').find('a[data-document-action="remove"]').click(function () {

                $('#documentsModal .edit-actions .btn-save').unbind('click');
                $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                $('#documentsModal .delete-actions .btn-save').unbind('click');
                $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                $('#documentsModal button.close').unbind('click');

                $('#documentsModal .edit-actions .btn-save').click(function () {  da.saveAction(); });
                $('#documentsModal .edit-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal .delete-actions .btn-save').click(function () {  da.deleteAction(); });
                $('#documentsModal .delete-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal button.close').click(function () { da.closeAction(); });

                da.editingFor = documentArrayInstance;

                da.editingIndex = $(this).parent().attr('data-document-index');

                // now grab the array if there already is one and turn it into a JavaScript object
                da.editingArray = JSON.parse($('[data-document-field-for="' + documentArrayInstance + '"]').find('input[type="hidden"][name="' + documentArrayInstance + '"]').val());

                da.editingObject = da.setLabel(da.editingArray[da.editingIndex]);

                da.removeDocument(documentArrayInstance);

            });

        }

    };

    DocumentArray.prototype.redrawDocuments = function (editingFor) {

        this.drawDocuments(editingFor, JSON.parse($('input[type="hidden"][name="' + editingFor + '"]').val()));

    };

    DocumentArray.prototype.editDocument = function (editingFor) {

        var form = $('#documentsModal .modal-body form').html(this.retrieveForm(editingFor));
        var datepickers = form.find('[data-linz-date-format]');

        var transforms = [];

        // Loop through each datetimepicker field and create a new transform so we get a proper date string.
        datepickers.each(function () {

            var field = $(this);
            var name = field.attr('name');
            var format = field.data('linz-date-format');

            var transform = {};

            transform.name = new RegExp(name);

            transform.getset = function (type, value) {
                return moment(value, format);
            };

            transforms.push(transform);

        });

        // apply the form to the modal
        form.binddata(this.editingObject, { transforms: transforms });

        // apply the label to the modal
        $('#documentsModal .modal-title').html(this.retrieveLabel(editingFor));

        // initialize multiselect
        $('#documentsModal .multiselect').multiselect({
            buttonContainer: '<div class="btn-group btn-group-multiselect" />'
        });

        // Switch the footer buttons considering the context.
        $('#documentsModal .modal-footer .edit-actions').show();
        $('#documentsModal .modal-footer .delete-actions').hide();

        // add an edit class to the model
        $('#documentsModal .modal-dialog').addClass('edit');

        this.toggleModal();

        // prevent the button from submitting the form
        return false;

    };

    DocumentArray.prototype.removeDocument = function (editingFor) {

        $('#documentsModal .modal-body form').html(Handlebars.compile('Are you sure you would like to delete \'{{label}}\'?')(this.editingObject));

        // apply the label to the modal
        $('#documentsModal .modal-title').html(this.retrieveLabel(editingFor));

        // Switch the footer buttons considering the context.
        $('#documentsModal .modal-footer .edit-actions').hide();
        $('#documentsModal .modal-footer .delete-actions').show();

        $('#documentsModal .modal-dialog').removeClass('edit');

        this.toggleModal();

        // prevent the button from submitting the form
        return false;

    };

    DocumentArray.prototype.saveDocument = function () {

        if (this.editingIndex === undefined) {
            this.editingArray.push(this.editingObject);
        } else {
            this.editingArray[this.editingIndex] = this.editingObject;
        }

        // now grab the array if there already is one and turn it into a JavaScript object
        $('input[type="hidden"][name="' + this.editingFor + '"]').val(JSON.stringify(this.editingArray));

        // now update the view
        this.drawDocuments(this.editingFor, this.editingArray);

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.deleteDocument = function () {

        this.editingArray.splice(this.editingIndex, 1);

        // now grab the array if there already is one and turn it into a JavaScript object
        $('input[type="hidden"][name="' + this.editingFor + '"]').val(JSON.stringify(this.editingArray));

        // now update the view
        this.drawDocuments(this.editingFor, this.editingArray);

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.saveAction = function () {

        var validator = $('#documentsModal .modal-body form').data('bootstrapValidator');

        // Validate the form.
        validator.validate();

        // // Check that everything is valid before saving.
        if (validator.isValid()) {
            this.saveDocument();
        }

    };

    DocumentArray.prototype.deleteAction = function () {

        this.deleteDocument();

    };

    DocumentArray.prototype.closeAction = function () {

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.reset = function () {

        this.editingFor = undefined;
        this.editingIndex = undefined;
        this.editingArray = undefined;
        this.editingObject = undefined;

    };

    DocumentArray.prototype.toggleModal = function () {

        // popup the modal
        $('#documentsModal').modal('toggle');

    };

    DocumentArray.prototype.retrieveForm = function (editingFor) {

        if (!this.formHtml[editingFor]) {

            // now grab the form HTML
            this.formHtml[editingFor] = window.linz.templates['document-' + editingFor].clone().html();

        }

        return this.formHtml[editingFor];

    };

    DocumentArray.prototype.retrieveLabel = function (editingFor) {

        return $('[data-document-field-for="' + editingFor + '"]').attr('data-document-field-label');

    }

    $.fn.documentarray = function(option, parameter, extraOptions) {

        return this.each(function(index, el) {

            var data = $(this).data('documentarray'),
                isModalWired = false;

            // initialize the documentarray.
            if (!data) {
                data = new DocumentArray();
                $(this).data('documentarray', data);
            }

            // determine the actions for this documentarray
            data.canCreate = $(el).attr('data-document-can-create') !== undefined ? true : false,
            data.canEdit = $(el).attr('data-document-can-edit') !== undefined ? true : false,
            data.canDelete = $(el).attr('data-document-can-delete') !== undefined ? true : false;

            if (!isModalWired) {

                $('#documentsModal').on('show.bs.modal', function (e) {

                    // Load the datepicker code incase the documentarray contains date inputs.
                    linz.loadDatepicker();

                });

                $('#documentsModal').on('shown.bs.modal', function (e) {

                    // Enable form validation.
                    var validator = $('#documentsModal .modal-body form').data('bootstrapValidator');

                    // The validator might alread exist, if so, remove it so we can start fresh.
                    if (validator) {

                        validator.destroy();
                        $('#documentsModal .modal-body form').data('bootstrapValidator', null);

                    }

                    // Freshly start the validator every time the modal is shown.
                    $('#documentsModal .modal-body form').bootstrapValidator();

                    $('#documentsModal').animate({ scrollTop: 0 }, 'fast');

                });

                var template = $('template.document-array-list').clone().html();

                if (!data.canEdit) {
                    // remove edit button from template
                    template = $(template).find('[data-document-action="edit"]').remove().end()[0].outerHTML;
                }

                if (!data.canDelete) {
                    // remove delete button from template
                    template = $(template).find('[data-document-action="remove"]').remove().end()[0].outerHTML;
                }

                data.listTemplate = Handlebars.compile(template);

                // activate switch to make sure the above if statement is executed just once!
                isModalWired = true;

            }

            var documentArrayInstance = $(el).attr('data-document-field-for');

            if (data.canCreate) {

                // handle the create button
                $('[data-document-field-for="' + documentArrayInstance + '"] [data-document-action="create"]').click(function (event) {

                    var parentElem = $(event.target).closest('.documents-container');

                    // unbind click events before we can bind new ones
                    $('#documentsModal .edit-actions .btn-save').unbind('click');
                    $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                    $('#documentsModal .delete-actions .btn-save').unbind('click');
                    $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                    $('#documentsModal button.close').unbind('click');

                    $('#documentsModal .edit-actions .btn-save').click(function () {  data.saveAction(); });
                    $('#documentsModal .edit-actions .btn-cancel').click(function () { data.closeAction(); });
                    $('#documentsModal .delete-actions .btn-save').click(function () {  data.deleteAction(); });
                    $('#documentsModal .delete-actions .btn-cancel').click(function () { data.closeAction(); });
                    $('#documentsModal button.close').click(function () { data.closeAction(); });

                    // clear out persitence fields
                    data.editingObject = {};
                    data.editingInstance = undefined;

                    // which field are we editing for?
                    data.editingFor = $(parentElem).attr('data-document-field-for');

                    // now grab the array if there already is one and turn it into a JavaScript object
                    data.editingArray = JSON.parse($(parentElem).children('input[type="hidden"][name="' + data.editingFor + '"]').val());

                    // now pop the form
                    data.editDocument(data.editingFor);

                });

            }

            data.retrieveForm(documentArrayInstance);

            data.drawDocuments(documentArrayInstance, JSON.parse($(el).children('input[type="hidden"][name="' + documentArrayInstance + '"]').val()));

            // Call sandyle method.
            if (typeof option === 'string') {
                data[option](parameter, extraOptions);
            }

        });

    };

    $.fn.documentarray.Constructor = DocumentArray;

    $(function() {

        $('[data-document-field-for]').documentarray();

    });

}(window.jQuery);
<commit_msg>set correct time for datepickers<commit_after>!function($) {

    function DocumentArray() {

        this.editingArray = undefined;
        this.editingObject = undefined;
        this.editingIndex = undefined;
        this.formHtml = {};
        this.editingFor = undefined;
        this.listTemplate = undefined;

    }

    DocumentArray.prototype.setLabel = function (document) {

        if (!document.label) {

            if (document.title) {
                document.label = document.title
            }

            if (document.firstName) {

                document.label = document.firstName;

                if (document.surname) {
                    document.label += ' ' + document.surname;
                }

                if (document.lastName) {
                    document.label += ' ' + document.lastName;
                }

            }

        }

        return document;

    };

    DocumentArray.prototype.drawDocuments = function (documentArrayInstance, documents) {

        var da = this,
            setLabel = this.setLabel;

        // check if there is a custom setLabel for this documentarray
        if ($('[data-document-field-for="' + documentArrayInstance + '"]').attr('data-document-set-label') !== undefined) {
            setLabel = linz.documents[documentArrayInstance + 'SetLabel'];
        }

        // loop through each document and ensure there is a label
        for (var i = 0; i < documents.length; i++) {
            documents[i] = setLabel(documents[i]);
        }

        documents = { documents: documents };

        $('[data-document-field-for="' + documentArrayInstance + '"] .documents').html(this.listTemplate(documents));

        if (da.canEdit) {

            // now bind the documents, handle the edit button
            $('[data-document-field-for="' + documentArrayInstance + '"]').find('a[data-document-action="edit"]').click(function () {

                $('#documentsModal .edit-actions .btn-save').unbind('click');
                $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                $('#documentsModal .delete-actions .btn-save').unbind('click');
                $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                $('#documentsModal button.close').unbind('click');

                $('#documentsModal .edit-actions .btn-save').click(function () {  da.saveAction(); });
                $('#documentsModal .edit-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal .delete-actions .btn-save').click(function () {  da.deleteAction(); });
                $('#documentsModal .delete-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal button.close').click(function () { da.closeAction(); });

                da.editingFor = documentArrayInstance;

                da.editingIndex = $(this).parent().attr('data-document-index');

                // now grab the array if there already is one and turn it into a JavaScript object
                da.editingArray = JSON.parse($('[data-document-field-for="' + documentArrayInstance + '"]').find('input[type="hidden"][name="' + documentArrayInstance + '"]').val());

                da.editingObject = da.editingArray[da.editingIndex];

                da.editDocument(documentArrayInstance);

            });

        }

        if (da.canDelete) {

            // now bind the documents, handle the delete button
            $('[data-document-field-for="' + documentArrayInstance + '"]').find('a[data-document-action="remove"]').click(function () {

                $('#documentsModal .edit-actions .btn-save').unbind('click');
                $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                $('#documentsModal .delete-actions .btn-save').unbind('click');
                $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                $('#documentsModal button.close').unbind('click');

                $('#documentsModal .edit-actions .btn-save').click(function () {  da.saveAction(); });
                $('#documentsModal .edit-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal .delete-actions .btn-save').click(function () {  da.deleteAction(); });
                $('#documentsModal .delete-actions .btn-cancel').click(function () { da.closeAction(); });
                $('#documentsModal button.close').click(function () { da.closeAction(); });

                da.editingFor = documentArrayInstance;

                da.editingIndex = $(this).parent().attr('data-document-index');

                // now grab the array if there already is one and turn it into a JavaScript object
                da.editingArray = JSON.parse($('[data-document-field-for="' + documentArrayInstance + '"]').find('input[type="hidden"][name="' + documentArrayInstance + '"]').val());

                da.editingObject = da.setLabel(da.editingArray[da.editingIndex]);

                da.removeDocument(documentArrayInstance);

            });

        }

    };

    DocumentArray.prototype.redrawDocuments = function (editingFor) {

        this.drawDocuments(editingFor, JSON.parse($('input[type="hidden"][name="' + editingFor + '"]').val()));

    };

    DocumentArray.prototype.editDocument = function (editingFor) {

        var form = $('#documentsModal .modal-body form').html(this.retrieveForm(editingFor));
        var datepickers = form.find('[data-linz-date-format]');

        var transforms = [];

        // Loop through each datetimepicker field and create a new transform so we get a proper date string.
        datepickers.each(function () {

            var field = $(this);
            var name = field.attr('name');
            var format = field.data('linz-date-format');

            var transform = {};

            transform.name = new RegExp(name);

            transform.getset = function (type, value) {
                return moment(value, format);
            };

            transforms.push(transform);

        });

        // apply the form to the modal
        form.binddata(this.editingObject, { transforms: transforms });

        // apply the label to the modal
        $('#documentsModal .modal-title').html(this.retrieveLabel(editingFor));

        // initialize multiselect
        $('#documentsModal .multiselect').multiselect({
            buttonContainer: '<div class="btn-group btn-group-multiselect" />'
        });

        // Switch the footer buttons considering the context.
        $('#documentsModal .modal-footer .edit-actions').show();
        $('#documentsModal .modal-footer .delete-actions').hide();

        // add an edit class to the model
        $('#documentsModal .modal-dialog').addClass('edit');

        this.toggleModal();

        // prevent the button from submitting the form
        return false;

    };

    DocumentArray.prototype.removeDocument = function (editingFor) {

        $('#documentsModal .modal-body form').html(Handlebars.compile('Are you sure you would like to delete \'{{label}}\'?')(this.editingObject));

        // apply the label to the modal
        $('#documentsModal .modal-title').html(this.retrieveLabel(editingFor));

        // Switch the footer buttons considering the context.
        $('#documentsModal .modal-footer .edit-actions').hide();
        $('#documentsModal .modal-footer .delete-actions').show();

        $('#documentsModal .modal-dialog').removeClass('edit');

        this.toggleModal();

        // prevent the button from submitting the form
        return false;

    };

    DocumentArray.prototype.saveDocument = function () {

        if (this.editingIndex === undefined) {
            this.editingArray.push(this.editingObject);
        } else {
            this.editingArray[this.editingIndex] = this.editingObject;
        }

        // now grab the array if there already is one and turn it into a JavaScript object
        $('input[type="hidden"][name="' + this.editingFor + '"]').val(JSON.stringify(this.editingArray));

        // now update the view
        this.drawDocuments(this.editingFor, this.editingArray);

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.deleteDocument = function () {

        this.editingArray.splice(this.editingIndex, 1);

        // now grab the array if there already is one and turn it into a JavaScript object
        $('input[type="hidden"][name="' + this.editingFor + '"]').val(JSON.stringify(this.editingArray));

        // now update the view
        this.drawDocuments(this.editingFor, this.editingArray);

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.saveAction = function () {

        var validator = $('#documentsModal .modal-body form').data('bootstrapValidator');

        // Validate the form.
        validator.validate();

        // // Check that everything is valid before saving.
        if (validator.isValid()) {
            this.saveDocument();
        }

    };

    DocumentArray.prototype.deleteAction = function () {

        this.deleteDocument();

    };

    DocumentArray.prototype.closeAction = function () {

        this.reset();

        this.toggleModal();

    };

    DocumentArray.prototype.reset = function () {

        this.editingFor = undefined;
        this.editingIndex = undefined;
        this.editingArray = undefined;
        this.editingObject = undefined;

    };

    DocumentArray.prototype.toggleModal = function () {

        // popup the modal
        $('#documentsModal').modal('toggle');

    };

    DocumentArray.prototype.retrieveForm = function (editingFor) {

        if (!this.formHtml[editingFor]) {

            // now grab the form HTML
            this.formHtml[editingFor] = window.linz.templates['document-' + editingFor].clone().html();

        }

        return this.formHtml[editingFor];

    };

    DocumentArray.prototype.retrieveLabel = function (editingFor) {

        return $('[data-document-field-for="' + editingFor + '"]').attr('data-document-field-label');

    }

    $.fn.documentarray = function(option, parameter, extraOptions) {

        return this.each(function(index, el) {

            var data = $(this).data('documentarray'),
                isModalWired = false;

            // initialize the documentarray.
            if (!data) {
                data = new DocumentArray();
                $(this).data('documentarray', data);
            }

            // determine the actions for this documentarray
            data.canCreate = $(el).attr('data-document-can-create') !== undefined ? true : false,
            data.canEdit = $(el).attr('data-document-can-edit') !== undefined ? true : false,
            data.canDelete = $(el).attr('data-document-can-delete') !== undefined ? true : false;

            if (!isModalWired) {

                $('#documentsModal').on('show.bs.modal', function () {

                    // Load the datepicker code incase the documentarray contains date inputs.
                    linz.loadDatepicker();

                    var values = JSON.parse($(this).siblings('form').find('input[name="docs"]').val());

                    // Set the value for each datepicker
                    if (data.editingIndex && values && values.length) {

                        var datepickers = $(this).find('[data-linz-date-format]');

                        datepickers.each(function () {

                            var field = $(this);
                            var name = field.attr('name');
                            var format = field.data('linz-date-format');

                            field.val(moment(values[data.editingIndex][name]).format(format));

                        });

                    }

                });

                $('#documentsModal').on('shown.bs.modal', function (e) {

                    // Enable form validation.
                    var validator = $('#documentsModal .modal-body form').data('bootstrapValidator');

                    // The validator might alread exist, if so, remove it so we can start fresh.
                    if (validator) {

                        validator.destroy();
                        $('#documentsModal .modal-body form').data('bootstrapValidator', null);

                    }

                    // Freshly start the validator every time the modal is shown.
                    $('#documentsModal .modal-body form').bootstrapValidator();

                    $('#documentsModal').animate({ scrollTop: 0 }, 'fast');

                });

                var template = $('template.document-array-list').clone().html();

                if (!data.canEdit) {
                    // remove edit button from template
                    template = $(template).find('[data-document-action="edit"]').remove().end()[0].outerHTML;
                }

                if (!data.canDelete) {
                    // remove delete button from template
                    template = $(template).find('[data-document-action="remove"]').remove().end()[0].outerHTML;
                }

                data.listTemplate = Handlebars.compile(template);

                // activate switch to make sure the above if statement is executed just once!
                isModalWired = true;

            }

            var documentArrayInstance = $(el).attr('data-document-field-for');

            if (data.canCreate) {

                // handle the create button
                $('[data-document-field-for="' + documentArrayInstance + '"] [data-document-action="create"]').click(function (event) {

                    var parentElem = $(event.target).closest('.documents-container');

                    // unbind click events before we can bind new ones
                    $('#documentsModal .edit-actions .btn-save').unbind('click');
                    $('#documentsModal .edit-actions .btn-cancel').unbind('click');
                    $('#documentsModal .delete-actions .btn-save').unbind('click');
                    $('#documentsModal .delete-actions .btn-cancel').unbind('click');
                    $('#documentsModal button.close').unbind('click');

                    $('#documentsModal .edit-actions .btn-save').click(function () {  data.saveAction(); });
                    $('#documentsModal .edit-actions .btn-cancel').click(function () { data.closeAction(); });
                    $('#documentsModal .delete-actions .btn-save').click(function () {  data.deleteAction(); });
                    $('#documentsModal .delete-actions .btn-cancel').click(function () { data.closeAction(); });
                    $('#documentsModal button.close').click(function () { data.closeAction(); });

                    // clear out persitence fields
                    data.editingObject = {};
                    data.editingInstance = undefined;

                    // which field are we editing for?
                    data.editingFor = $(parentElem).attr('data-document-field-for');

                    // now grab the array if there already is one and turn it into a JavaScript object
                    data.editingArray = JSON.parse($(parentElem).children('input[type="hidden"][name="' + data.editingFor + '"]').val());

                    // now pop the form
                    data.editDocument(data.editingFor);

                });

            }

            data.retrieveForm(documentArrayInstance);

            data.drawDocuments(documentArrayInstance, JSON.parse($(el).children('input[type="hidden"][name="' + documentArrayInstance + '"]').val()));

            // Call sandyle method.
            if (typeof option === 'string') {
                data[option](parameter, extraOptions);
            }

        });

    };

    $.fn.documentarray.Constructor = DocumentArray;

    $(function() {

        $('[data-document-field-for]').documentarray();

    });

}(window.jQuery);
<|endoftext|>