<commit_before>var _ = require('underscore');

var days = {
  SUN: 0,
  MON: 1,
  TUE: 2,
  WED: 3,
  THU: 4,
  FRI: 5,
  SAT: 6
};

var parseTime = function parseTime(str) {
  var match = str.match(/(\d\d?)(:\d\d)?((?:A|P)M)/i),
      hour, min, pm;

  if(!match || !match[1] || !match[3]) {
    throw new Error("Invalid time string: " + str);
  }

  hour = parseInt(match, 10);
  if(match[2]) {
    min = parseInt(match[2].replace(":",""), 10);
  } else {
    min = 0;
  }

  pm = !!match[3].match(/PM/i);

  if(pm && hour !== 12) {
    return [(hour + 12), min];
  } else {
    return [hour, min];
  }
};

var timeToOffset = function(time) {
  return time.getHours()*100 + time.getMinutes();
};

var timeStringToOffset = function(timeString) {
  var parsed = parseTime(timeString);
  return parsed[0]*100 + parsed[1];
};

/* Input format:

 {
   "Mon": "9:00AM-5:00PM",
   "Tue": "9:00AM-11:00AM,1:00PM-5:00PM",
   "Wed": "9:00AM-5:00PM",
   "Thu": "9:00AM-5:00PM",
   "Fri": "9:00AM-5:00PM",
   "Sat": "9:00AM-11:00AM",
   "Sun": "9:00AM-11:00AM"
 }

*/

var Hours = function Hours(hours){
  var processed = {}, day;

  for(var k in hours) {
    if(!hours.hasOwnProperty(k)) { continue; }
    day = days[k.toUpperCase()];

    processed[day] = this.addDay(day, hours[k]);
  }

  this.hours = processed;
};

Hours.prototype.addDay = function(day, str) {
  var intervals, interval, result = [];

  intervals = str.split(",");

  for(var idx = 0; idx < intervals.length; idx++) {
    interval = intervals[idx].split("-");
    result.push([ timeStringToOffset(interval[0]),
                  timeStringToOffset(interval[1]) ]);
  }

  return result;
};

Hours.prototype.within = function(time) {
  var intervals, instant, parts, day;

  if(_.isDate(time)) {
    intervals = this.hours[time.getDay()];
    instant   = timeToOffset(time);
  } else {
    parts      = time.split(","),
    day        = days[parts[0].toUpperCase()],
    intervals  = this.hours[day],
    instant    = timeStringToOffset(parts[1]);
  }

  return !!_(intervals).find(function(interval) {
    return (interval[0] <= instant) &&
           (interval[1] >= instant);
  });
};

module.exports = Hours;
<commit_msg>hours: allow empty input when creating<commit_after>var _ = require('underscore');

var days = {
  SUN: 0,
  MON: 1,
  TUE: 2,
  WED: 3,
  THU: 4,
  FRI: 5,
  SAT: 6
};

var parseTime = function parseTime(str) {
  var match = str.match(/(\d\d?)(:\d\d)?((?:A|P)M)/i),
      hour, min, pm;

  if(!match || !match[1] || !match[3]) {
    throw new Error("Invalid time string: " + str);
  }

  hour = parseInt(match, 10);
  if(match[2]) {
    min = parseInt(match[2].replace(":",""), 10);
  } else {
    min = 0;
  }

  pm = !!match[3].match(/PM/i);

  if(pm && hour !== 12) {
    return [(hour + 12), min];
  } else {
    return [hour, min];
  }
};

var timeToOffset = function(time) {
  return time.getHours()*100 + time.getMinutes();
};

var timeStringToOffset = function(timeString) {
  var parsed = parseTime(timeString);
  return parsed[0]*100 + parsed[1];
};

/* Input format:

 {
   "Mon": "9:00AM-5:00PM",
   "Tue": "9:00AM-11:00AM,1:00PM-5:00PM",
   "Wed": "9:00AM-5:00PM",
   "Thu": "9:00AM-5:00PM",
   "Fri": "9:00AM-5:00PM",
   "Sat": "9:00AM-11:00AM",
   "Sun": "9:00AM-11:00AM"
 }

*/

var Hours = function Hours(hours){
  var processed = {}, day, hours = hours || {};

  for(var k in hours) {
    if(!hours.hasOwnProperty(k)) { continue; }
    day = days[k.toUpperCase()];

    processed[day] = this.addDay(day, hours[k]);
  }

  this.hours = processed;
};

Hours.prototype.addDay = function(day, str) {
  var intervals, interval, result = [];

  intervals = str.split(",");

  for(var idx = 0; idx < intervals.length; idx++) {
    interval = intervals[idx].split("-");
    result.push([ timeStringToOffset(interval[0]),
                  timeStringToOffset(interval[1]) ]);
  }

  return result;
};

Hours.prototype.within = function(time) {
  var intervals, instant, parts, day;

  if(_.isDate(time)) {
    intervals = this.hours[time.getDay()];
    instant   = timeToOffset(time);
  } else {
    parts      = time.split(","),
    day        = days[parts[0].toUpperCase()],
    intervals  = this.hours[day],
    instant    = timeStringToOffset(parts[1]);
  }

  return !!_(intervals).find(function(interval) {
    return (interval[0] <= instant) &&
           (interval[1] >= instant);
  });
};

module.exports = Hours;
<|endoftext|>


<commit_before>import { context, environment } from 'ember-environment';
import require from 'require';

let jQuery;

if (environment.hasDOM) {
  jQuery = context.imports.jQuery;
  if (!jQuery && typeof require === 'function') {
    jQuery = require('jquery');
  }

  if (jQuery) {
    // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
    [
      'dragstart',
      'drag',
      'dragenter',
      'dragleave',
      'dragover',
      'drop',
      'dragend'
    ].forEach(eventName => {
      jQuery.event.fixHooks[eventName] = {
        props: ['dataTransfer']
      };
    });
  }
}

export default jQuery;
<commit_msg>Use `jQuery.event.addProp` to add `dataTransfer` property<commit_after>import { context, environment } from 'ember-environment';
import require from 'require';

let jQuery;

if (environment.hasDOM) {
  jQuery = context.imports.jQuery;
  if (!jQuery && typeof require === 'function') {
    jQuery = require('jquery');
  }

  if (jQuery) {
    if (jQuery.event.addProp) {
      jQuery.event.addProp('dataTransfer');
    } else {
      // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
      [
        'dragstart',
        'drag',
        'dragenter',
        'dragleave',
        'dragover',
        'drop',
        'dragend'
      ].forEach(eventName => {
        jQuery.event.fixHooks[eventName] = {
          props: ['dataTransfer']
        };
      });
    }
  }
}

export default jQuery;
<|endoftext|>


<commit_before>define(function (require) {

    "use strict";

var $                   = require('jquery'),
    _                   = require('underscore'),
    Backbone            = require('backbone'),
    tpl                 = require('text!tpl/Player.html'),
    soundManager		= require('soundmanager2'),
    Slider				= require('slider'),
    Display				= require('display'),
    PlaylistItem		= require('app/views/PlayerPlaylistItem'),
    Song				= require('app/models/Song'),

    template = _.template(tpl),

    // Custom collection for the playlist
	Playlist = Backbone.Collection.extend({
		model: Song
	}),

    Player = Backbone.View.extend({

    	current: {},		// Current track object
    	state : 1,			// 0 => Pause, 1 => Playing
    	random: false,		// Random mode
    	repeat: false,		// Repeat mode

        initialize: function () {
        	console.log('Player: init');

        	soundManager.setup({
				url: '../../soundmanager/swf/',
				flashVersion: 8,
				debugMode: false
			});

			// Almost always there will be a timeout on the first try
			// this is due to the load order in RequireJS I believe.
			soundManager.ontimeout(function(status) {
				soundManager.flashLoadTimeout = 0;	// Wait infinitely for flash, then restart
				soundManager.onerror = {}; 			// Prevent an infinite loop, in case it's not flashblock
				soundManager.reboot();				// and, go!
			});

			// Playlist holder
			this.playlist = new Playlist();

			this.playlist.on('add', this.renderPlaylist, this);
			this.playlist.on('remove', this.renderPlaylist, this);
        },

        events: {
        	"click .playPause": "playPause",
        	"click .previous": "prev",
        	"click .next": "next",
        	"click .random": "toggleRandom",
        	"click .repeat": "toggleRepeat",
        	"click .playlist a.track": "clickedTrack",
        	"click .playlist a.delete": "removeTrack",
        	"mouseover .playlist li" : "overTrack",
        	"mouseout .playlist li" : "outTrack"
        },

		// Initial render of the Player. Should happen only once
        render: function () {
        	this.$el.html(template());

        	this.$loaded = this.$el.find('.seek-loaded');
			this.$songInfo = this.$el.find('.song-info');
        	this.$elapsed = this.$el.find('.elapsed');
        	this.$total = this.$el.find('.total');
        	this.$playlist = this.$el.find('.playlist');
        	this.$next = this.$el.find('.next');
        	this.$prev = this.$el.find('.previous');

        	var this_ = this;

        	this.slider = this.$el.find('input.seek-slider').slider({
        		enabled: false,
        		formater : function(val){
        			if(typeof(this_.current)==='undefined' || typeof(this_.current.duration)==='undefined'){
        				this_.current.duration = 0;
        			}
        			var total = this_.current.duration/1000, // Total time in seconds
        				elapsed = total * val / 1000;
        			return Display.timeToString(elapsed);
        		}
        	}).on('slideStart',function(){
        		// Set up a flag to prevent the seeker to be moved
        		// if it's on play state.
        		this_.slider.sliding = true;
        	}).on('slideStop',function(slide){
        		if(this_.ready()){
        			var pos = slide.value;
        			this_.current.sound.setPosition(this_.current.duration * pos/1000);
        			this_.$elapsed.text(Display.timeToString(pos/1000));
        			this_.slider.sliding = false;
        		}
        	});

            return this;
        },

        // Renders only the playlist
        renderPlaylist: function(){
        	this.$playlist.empty();

        	_.each(this.playlist.models, function (song) {
        		this.$playlist.append(new PlaylistItem({model: song}).render().el);
			}, this);

            return this;
        },

        /**
         * Add a track to the playlist
         * @param (Object) Backbone song model or Songs collection
         */
        addToPlaylist: function(model){

        	this.show();

        	if(model instanceof Backbone.Model){
				this.checkModelAndAdd(model);
			}else if(model instanceof Backbone.Collection){
				// Loop through the collection adding each model
				for(var i=0;i<model.models.length;i++){
					this.checkModelAndAdd(model.models[i]);
				}
			}
        },

        /**
         * Check the added model and add to the Playlist collection if valid
         * @param (Object) Backbone song model
         */
        checkModelAndAdd: function(model){
        	var this_ = this;

        	console.log('Player: Adding to playlist: ', model.attributes);

        	console.log('Exists? ',this.playlist.get(model));

        	soundManager.onready(function(){
        		// Check if it's playable
				if(soundManager.canPlayURL(model.get('track').url)){

					model.played = false;	// Played flag, used by the random mode

					model.sound = soundManager.createSound({
						url: model.get('track').url,
						id: model.get('track').url+'-'+this_.playlist.length,
						autoPlay: false,
						autoLoad: false,
						whileloading: function(){
							var percent = this.bytesLoaded*100/this.bytesTotal;
							this_.setLoaded(percent);
						},
						whileplaying: function(){
							var percent = this.position*100/this.duration;
							this_.setPlayed(percent);
							this_.$elapsed.text(Display.timeToString(this.position/1000));
						},
						onload: function(){
							console.log('Player: Track loaded');
							model.duration = this.duration;
							this_.$total.text(Display.timeToString(this_.current.duration/1000));
						}
					});

					this_.playlist.add(model);

					if(typeof(this_.current.index)==='undefined'){
						this_.current.index = -1;
					}

					// Update the next button status
					if(this_.current.index < this_.playlist.length-1){
						this_.enable(this_.$next);
					}else{
						this_.disable(this_.$next);
					}

					// Load in the player if it's the only song
					if(this_.playlist.length == 1){
		        		this_.next();
		        	}
				}else{
					console.error('Player: Cant play track: '+model.get('track').title+' ('+model.get('track').url+')',model);
				}
			});

        },

        /**
		 * Show the player
		 */
		show: function(){
			$('#player').removeClass('hidden').show();
		},
		/**
		 * Hide the player
		 */
		hide: function(){
			$('#player').hide();
		},
		/**
		 * Play the next song in the playlist
		 */
		next: function(){
			console.log('Player: Next');

			console.log('Playlist:', this.playlist);

			if(this.playlist.length==0 && this.repeat && this.ready()){
				// Playlist is empty, but we are in repeat mode
				// so keep playing the loaded track
				this.playCurrent();
				return true;
			}

			// Select the normal next index
			var index = this.current.index+1;

			// Check random and repeat modes
			if(this.random && this.playlist.length > 1){
				// Select a random track and play it
				// Different from the current one
				index = Math.floor(Math.random()*this.playlist.length);
				var initial = index;
				while(index == this.current.index || this.playlist.at(index).played){
					// Chose another one until it's different and it wasn't already played
					index++;
					if(index == initial){
						// Already looped through all tracks!
						console.error('Player: No next track');
						return false;
					}
					if(typeof(this.playlist.at(index)) === 'undefined'){
						index = 0; // Start over
					}
				}
				this.playTrack(index);

				// Check if there are any more available
				var available = false;
				for(var i=0;i<this.playlist.length;i++){
					if(!this.playlist.at(i).played){
						available = true;
						break;
					}
				}
				if(!available){
					// No more tracks available. Since the user wants to go to next
					// reset the status and keep looping.
					this.resetPlayed();
				}

				return true;
			}

			// Make sure it's valid
			if(typeof(this.playlist.at(index)) === 'undefined'){
				if(this.repeat){
					index = 0;
				}else{
					this.disable(this.$next);
					console.error('Player: No next track');
					return false;
				}
			}

			this.playTrack(index);

			return true;
		},
		/**
		 * Play the previous song in the playlist
		 */
		prev: function(){
			console.log('Player: Prev');

			var index = this.current.index-1;

			if(typeof(this.playlist.at(index)) === 'undefined'){
				console.error('Player: No prev track');
				this.disable(this.$prev);
				return false;
			}

			this.playTrack(index);

			return true;
		},
		/**
		 * Enables an element
		 */
		enable: function($obj){
			$obj.removeClass('disabled');
		},
		/*
		 *  Disables an element
		 */
		disable: function($obj){
			$obj.addClass('disabled');
		},
		/**
		 * Takes the current track to the beginning
		 */
		rewind: function(){
			this.current.sound.setPosition(0);
			this.setPlayed(0);
			this.$elapsed.text('00:00');
		},
		/**
		 * Plays the clicked tracked from the playlist
		 */
		clickedTrack: function(e){
			e.preventDefault();
			var index = $(e.currentTarget).parent('li').index('.playlist li');
			this.playTrack(index);
		},
		/**
		 * Plays the selected object from the playlist
		 */
		playTrack: function(index){
			this.current = this.playlist.at(index);
			this.current.index = index;

			// Rewind the track in case it was already listened
			this.rewind();

			this.playCurrent();
		},
		/**
		 * Remove the selected track from the playlist
		 */
		removeTrack: function(e){
			e.preventDefault();
			var index = $(e.currentTarget).parent('li').index('.playlist li'),
				item = this.playlist.at(index);

			this.playlist.remove(item);
		},
		/**
		 * Play the track in current
		 */
		playCurrent: function(){
			// Add the active class
			this.$playlist.find('a.active').removeClass('active');

			// Enable/Disable next/prev buttons
			if(this.current.index > 0){
				this.enable(this.$prev);
			}else{
				this.disable(this.$prev);
			}
			if(this.current.index < this.playlist.length-1){
				this.enable(this.$next);
			}else if(!this.random && !this.repeat){
				this.disable(this.$next);
			}

			this.slider.slider('enable');

			this.$songInfo.html(''+this.current.get('track').name+' by '+this.current.get('artist').name+'');

			// Start playing
			this.play();
		},
		/**
		 * Toggle the state of the player. Always according to what the sound library says.
		 * Also update the internal 'state' variable
		 */
		playPause: function(){
			var icon;
			if(!this.ready()){
				console.warn('Player: Sound not ready: ',this.current);
				return;
			}
			if(this.state==0){
				this.play();
			}else{
				this.pause();
			}
		},
		/**
		 * Play current sound, after pausing all. Just in case.
		 */
		play: function(){
			soundManager.pauseAll();
			var this_ = this;
			this.current.sound.play({
				onfinish: function() {
					// Try to play the next track
					if(!this_.next()){
						// Check repeat mode
						if(this_.repeat){
							this_.playTrack(0);
							return;
						}
						this_.pause();
						this_.rewind();
					}
				}
			});
			// Set the played flag of the current sound to true.
			// This flag is used by the random mode to avoid repeating the same tracks
			this.current.played = true;
			console.log('Player: Now Playing');
			this.state = 1;
			this.$el.find("a.playPause i").removeClass('fa-play').addClass('fa-pause');
		},
		/**
		 * Pause all sounds. Just in case.
		 */
		pause: function(){
			soundManager.pauseAll();
			console.log('Player: Now Paused');
			this.state = 0;
			this.$el.find("a.playPause i").removeClass('fa-pause').addClass('fa-play');
		},
		/**
		 * Toggle random mode
		 */
		toggleRandom: function(){
			var $random = this.$el.find("a.random");
			if($random.hasClass('active')){
				// Disable random mode
				$random.removeClass('active');
				this.random = false;
				console.log('Player: Random mode OFF');
			}else{
				$random.addClass('active');
				this.random = true;
				// Reset all the played status
				this.resetPlayed();
				this.enable(this.$next);
				console.log('Player: Random mode ON');
			}
		},
		/**
		 * Resets the played status of all tracks in the playlist
		 */
		resetPlayed: function(){
			for(var i=0;i<this.playlist.length;i++){
				this.playlist.at(i).played = false;
			}
		},
		/**
		 * Toggle repeat mode
		 */
		toggleRepeat: function(){
			var $repeat = this.$el.find("a.repeat");
			if($repeat.hasClass('active')){
				// Disable random mode
				$repeat.removeClass('active');
				this.repeat = false;
				console.log('Player: Repeat mode OFF');
			}else{
				$repeat.addClass('active');
				this.repeat = true;
				this.enable(this.$next);
				console.log('Player: Repeat mode ON');
			}
		},
		/**
		 * Sets the played percentage only if it's not being moved.
		 */
		setPlayed: function(percent){
			if(this.slider.sliding) return;
			this.slider.slider('setValue', percent*10);
		},
		/**
		 * Sets the loaded percentage
		 */
		setLoaded: function(percent){
			this.$loaded.width(percent+'%');
		},
		/**
		 * Returns whether current is holding a valid song to play
		 */
		ready: function(){
			if(typeof(this.current.sound)=='object'){
				return true;
			}
			return false;
		},
		/**
		 * Triggered when the mouse is over a track.
		 * Displays the delete button
		 */
		overTrack: function(e){
			var $obj = $(e.currentTarget);
			$obj.find('a.delete').show();
		},
		/**
		 * Triggered on mouse out. Hides the delete button
 		 * @param {Object} event
		 */
		outTrack: function(e){
			var $obj = $(e.currentTarget);

			$obj.find('a.delete').hide();
		},
		/**
		 *  Resets the player:
		 *  Restore the song info, reset the seek bar
		 *  And the timers.
		 */
		resetPlayer: function(){
			this.$songInfo.html('');
			this.setLoaded(0);
			this.setPlayed(0);
			this.$elapsed.text('00:00');
			this.$total.text('00:00');
			this.current.sound.destruct();
			this.current = {};
		}
    });

    return new Player();

});<commit_msg>Fix model in Player as well<commit_after>define(function (require) {

    "use strict";

var $                   = require('jquery'),
    _                   = require('underscore'),
    Backbone            = require('backbone'),
    tpl                 = require('text!tpl/Player.html'),
    soundManager		= require('soundmanager2'),
    Slider				= require('slider'),
    Display				= require('display'),
    PlaylistItem		= require('app/views/PlayerPlaylistItem'),
    song				= require('app/models/song'),

    template = _.template(tpl),

    // Custom collection for the playlist
	Playlist = Backbone.Collection.extend({
		model: song
	}),

    Player = Backbone.View.extend({

    	current: {},		// Current track object
    	state : 1,			// 0 => Pause, 1 => Playing
    	random: false,		// Random mode
    	repeat: false,		// Repeat mode

        initialize: function () {
        	console.log('Player: init');

        	soundManager.setup({
				url: '../../soundmanager/swf/',
				flashVersion: 8,
				debugMode: false
			});

			// Almost always there will be a timeout on the first try
			// this is due to the load order in RequireJS I believe.
			soundManager.ontimeout(function(status) {
				soundManager.flashLoadTimeout = 0;	// Wait infinitely for flash, then restart
				soundManager.onerror = {}; 			// Prevent an infinite loop, in case it's not flashblock
				soundManager.reboot();				// and, go!
			});

			// Playlist holder
			this.playlist = new Playlist();

			this.playlist.on('add', this.renderPlaylist, this);
			this.playlist.on('remove', this.renderPlaylist, this);
        },

        events: {
        	"click .playPause": "playPause",
        	"click .previous": "prev",
        	"click .next": "next",
        	"click .random": "toggleRandom",
        	"click .repeat": "toggleRepeat",
        	"click .playlist a.track": "clickedTrack",
        	"click .playlist a.delete": "removeTrack",
        	"mouseover .playlist li" : "overTrack",
        	"mouseout .playlist li" : "outTrack"
        },

		// Initial render of the Player. Should happen only once
        render: function () {
        	this.$el.html(template());

        	this.$loaded = this.$el.find('.seek-loaded');
			this.$songInfo = this.$el.find('.song-info');
        	this.$elapsed = this.$el.find('.elapsed');
        	this.$total = this.$el.find('.total');
        	this.$playlist = this.$el.find('.playlist');
        	this.$next = this.$el.find('.next');
        	this.$prev = this.$el.find('.previous');

        	var this_ = this;

        	this.slider = this.$el.find('input.seek-slider').slider({
        		enabled: false,
        		formater : function(val){
        			if(typeof(this_.current)==='undefined' || typeof(this_.current.duration)==='undefined'){
        				this_.current.duration = 0;
        			}
        			var total = this_.current.duration/1000, // Total time in seconds
        				elapsed = total * val / 1000;
        			return Display.timeToString(elapsed);
        		}
        	}).on('slideStart',function(){
        		// Set up a flag to prevent the seeker to be moved
        		// if it's on play state.
        		this_.slider.sliding = true;
        	}).on('slideStop',function(slide){
        		if(this_.ready()){
        			var pos = slide.value;
        			this_.current.sound.setPosition(this_.current.duration * pos/1000);
        			this_.$elapsed.text(Display.timeToString(pos/1000));
        			this_.slider.sliding = false;
        		}
        	});

            return this;
        },

        // Renders only the playlist
        renderPlaylist: function(){
        	this.$playlist.empty();

        	_.each(this.playlist.models, function (song) {
        		this.$playlist.append(new PlaylistItem({model: song}).render().el);
			}, this);

            return this;
        },

        /**
         * Add a track to the playlist
         * @param (Object) Backbone song model or Songs collection
         */
        addToPlaylist: function(model){

        	this.show();

        	if(model instanceof Backbone.Model){
				this.checkModelAndAdd(model);
			}else if(model instanceof Backbone.Collection){
				// Loop through the collection adding each model
				for(var i=0;i<model.models.length;i++){
					this.checkModelAndAdd(model.models[i]);
				}
			}
        },

        /**
         * Check the added model and add to the Playlist collection if valid
         * @param (Object) Backbone song model
         */
        checkModelAndAdd: function(model){
        	var this_ = this;

        	console.log('Player: Adding to playlist: ', model.attributes);

        	console.log('Exists? ',this.playlist.get(model));

        	soundManager.onready(function(){
        		// Check if it's playable
				if(soundManager.canPlayURL(model.get('track').url)){

					model.played = false;	// Played flag, used by the random mode

					model.sound = soundManager.createSound({
						url: model.get('track').url,
						id: model.get('track').url+'-'+this_.playlist.length,
						autoPlay: false,
						autoLoad: false,
						whileloading: function(){
							var percent = this.bytesLoaded*100/this.bytesTotal;
							this_.setLoaded(percent);
						},
						whileplaying: function(){
							var percent = this.position*100/this.duration;
							this_.setPlayed(percent);
							this_.$elapsed.text(Display.timeToString(this.position/1000));
						},
						onload: function(){
							console.log('Player: Track loaded');
							model.duration = this.duration;
							this_.$total.text(Display.timeToString(this_.current.duration/1000));
						}
					});

					this_.playlist.add(model);

					if(typeof(this_.current.index)==='undefined'){
						this_.current.index = -1;
					}

					// Update the next button status
					if(this_.current.index < this_.playlist.length-1){
						this_.enable(this_.$next);
					}else{
						this_.disable(this_.$next);
					}

					// Load in the player if it's the only song
					if(this_.playlist.length == 1){
		        		this_.next();
		        	}
				}else{
					console.error('Player: Cant play track: '+model.get('track').title+' ('+model.get('track').url+')',model);
				}
			});

        },

        /**
		 * Show the player
		 */
		show: function(){
			$('#player').removeClass('hidden').show();
		},
		/**
		 * Hide the player
		 */
		hide: function(){
			$('#player').hide();
		},
		/**
		 * Play the next song in the playlist
		 */
		next: function(){
			console.log('Player: Next');

			console.log('Playlist:', this.playlist);

			if(this.playlist.length==0 && this.repeat && this.ready()){
				// Playlist is empty, but we are in repeat mode
				// so keep playing the loaded track
				this.playCurrent();
				return true;
			}

			// Select the normal next index
			var index = this.current.index+1;

			// Check random and repeat modes
			if(this.random && this.playlist.length > 1){
				// Select a random track and play it
				// Different from the current one
				index = Math.floor(Math.random()*this.playlist.length);
				var initial = index;
				while(index == this.current.index || this.playlist.at(index).played){
					// Chose another one until it's different and it wasn't already played
					index++;
					if(index == initial){
						// Already looped through all tracks!
						console.error('Player: No next track');
						return false;
					}
					if(typeof(this.playlist.at(index)) === 'undefined'){
						index = 0; // Start over
					}
				}
				this.playTrack(index);

				// Check if there are any more available
				var available = false;
				for(var i=0;i<this.playlist.length;i++){
					if(!this.playlist.at(i).played){
						available = true;
						break;
					}
				}
				if(!available){
					// No more tracks available. Since the user wants to go to next
					// reset the status and keep looping.
					this.resetPlayed();
				}

				return true;
			}

			// Make sure it's valid
			if(typeof(this.playlist.at(index)) === 'undefined'){
				if(this.repeat){
					index = 0;
				}else{
					this.disable(this.$next);
					console.error('Player: No next track');
					return false;
				}
			}

			this.playTrack(index);

			return true;
		},
		/**
		 * Play the previous song in the playlist
		 */
		prev: function(){
			console.log('Player: Prev');

			var index = this.current.index-1;

			if(typeof(this.playlist.at(index)) === 'undefined'){
				console.error('Player: No prev track');
				this.disable(this.$prev);
				return false;
			}

			this.playTrack(index);

			return true;
		},
		/**
		 * Enables an element
		 */
		enable: function($obj){
			$obj.removeClass('disabled');
		},
		/*
		 *  Disables an element
		 */
		disable: function($obj){
			$obj.addClass('disabled');
		},
		/**
		 * Takes the current track to the beginning
		 */
		rewind: function(){
			this.current.sound.setPosition(0);
			this.setPlayed(0);
			this.$elapsed.text('00:00');
		},
		/**
		 * Plays the clicked tracked from the playlist
		 */
		clickedTrack: function(e){
			e.preventDefault();
			var index = $(e.currentTarget).parent('li').index('.playlist li');
			this.playTrack(index);
		},
		/**
		 * Plays the selected object from the playlist
		 */
		playTrack: function(index){
			this.current = this.playlist.at(index);
			this.current.index = index;

			// Rewind the track in case it was already listened
			this.rewind();

			this.playCurrent();
		},
		/**
		 * Remove the selected track from the playlist
		 */
		removeTrack: function(e){
			e.preventDefault();
			var index = $(e.currentTarget).parent('li').index('.playlist li'),
				item = this.playlist.at(index);

			this.playlist.remove(item);
		},
		/**
		 * Play the track in current
		 */
		playCurrent: function(){
			// Add the active class
			this.$playlist.find('a.active').removeClass('active');

			// Enable/Disable next/prev buttons
			if(this.current.index > 0){
				this.enable(this.$prev);
			}else{
				this.disable(this.$prev);
			}
			if(this.current.index < this.playlist.length-1){
				this.enable(this.$next);
			}else if(!this.random && !this.repeat){
				this.disable(this.$next);
			}

			this.slider.slider('enable');

			this.$songInfo.html(''+this.current.get('track').name+' by '+this.current.get('artist').name+'');

			// Start playing
			this.play();
		},
		/**
		 * Toggle the state of the player. Always according to what the sound library says.
		 * Also update the internal 'state' variable
		 */
		playPause: function(){
			var icon;
			if(!this.ready()){
				console.warn('Player: Sound not ready: ',this.current);
				return;
			}
			if(this.state==0){
				this.play();
			}else{
				this.pause();
			}
		},
		/**
		 * Play current sound, after pausing all. Just in case.
		 */
		play: function(){
			soundManager.pauseAll();
			var this_ = this;
			this.current.sound.play({
				onfinish: function() {
					// Try to play the next track
					if(!this_.next()){
						// Check repeat mode
						if(this_.repeat){
							this_.playTrack(0);
							return;
						}
						this_.pause();
						this_.rewind();
					}
				}
			});
			// Set the played flag of the current sound to true.
			// This flag is used by the random mode to avoid repeating the same tracks
			this.current.played = true;
			console.log('Player: Now Playing');
			this.state = 1;
			this.$el.find("a.playPause i").removeClass('fa-play').addClass('fa-pause');
		},
		/**
		 * Pause all sounds. Just in case.
		 */
		pause: function(){
			soundManager.pauseAll();
			console.log('Player: Now Paused');
			this.state = 0;
			this.$el.find("a.playPause i").removeClass('fa-pause').addClass('fa-play');
		},
		/**
		 * Toggle random mode
		 */
		toggleRandom: function(){
			var $random = this.$el.find("a.random");
			if($random.hasClass('active')){
				// Disable random mode
				$random.removeClass('active');
				this.random = false;
				console.log('Player: Random mode OFF');
			}else{
				$random.addClass('active');
				this.random = true;
				// Reset all the played status
				this.resetPlayed();
				this.enable(this.$next);
				console.log('Player: Random mode ON');
			}
		},
		/**
		 * Resets the played status of all tracks in the playlist
		 */
		resetPlayed: function(){
			for(var i=0;i<this.playlist.length;i++){
				this.playlist.at(i).played = false;
			}
		},
		/**
		 * Toggle repeat mode
		 */
		toggleRepeat: function(){
			var $repeat = this.$el.find("a.repeat");
			if($repeat.hasClass('active')){
				// Disable random mode
				$repeat.removeClass('active');
				this.repeat = false;
				console.log('Player: Repeat mode OFF');
			}else{
				$repeat.addClass('active');
				this.repeat = true;
				this.enable(this.$next);
				console.log('Player: Repeat mode ON');
			}
		},
		/**
		 * Sets the played percentage only if it's not being moved.
		 */
		setPlayed: function(percent){
			if(this.slider.sliding) return;
			this.slider.slider('setValue', percent*10);
		},
		/**
		 * Sets the loaded percentage
		 */
		setLoaded: function(percent){
			this.$loaded.width(percent+'%');
		},
		/**
		 * Returns whether current is holding a valid song to play
		 */
		ready: function(){
			if(typeof(this.current.sound)=='object'){
				return true;
			}
			return false;
		},
		/**
		 * Triggered when the mouse is over a track.
		 * Displays the delete button
		 */
		overTrack: function(e){
			var $obj = $(e.currentTarget);
			$obj.find('a.delete').show();
		},
		/**
		 * Triggered on mouse out. Hides the delete button
 		 * @param {Object} event
		 */
		outTrack: function(e){
			var $obj = $(e.currentTarget);

			$obj.find('a.delete').hide();
		},
		/**
		 *  Resets the player:
		 *  Restore the song info, reset the seek bar
		 *  And the timers.
		 */
		resetPlayer: function(){
			this.$songInfo.html('');
			this.setLoaded(0);
			this.setPlayed(0);
			this.$elapsed.text('00:00');
			this.$total.text('00:00');
			this.current.sound.destruct();
			this.current = {};
		}
    });

    return new Player();

});<|endoftext|>


<commit_before>/* =========================================================
 * bootstrap-slider.js v2.0.0
 * http://www.eyecon.ro/bootstrap-slider
 * =========================================================
 * Copyright 2012 Stefan Petre
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function( $ ) {

	var Slider = function(element, options) {
		var el = this.element = $(element).hide();
        var origWidth = el.outerWidth();

		var updateSlider = false;
		var parent = this.element.parent();

		if (parent.hasClass('slider') === true) {
			updateSlider = true;
			this.picker = parent;
		} else {
			this.picker = $('
'+
								'
'+
									'

'+
									'

'+
									'

'+
								'
'+
								'

'+
							'
')
								.insertBefore(this.element)
								.append(this.element);
		}

		this.id = this.element.data('slider-id')||options.id;
		if (this.id) {
			this.picker[0].id = this.id;
		}

		if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
			this.touchCapable = true;
		}

		var tooltip = this.element.data('slider-tooltip')||options.tooltip;

		this.tooltip = this.picker.find('.tooltip');
		this.tooltipInner = this.tooltip.find('div.tooltip-inner');

		this.orientation = this.element.data('slider-orientation')||options.orientation;
		switch(this.orientation) {
			case 'vertical':
				this.picker.addClass('slider-vertical');
				this.stylePos = 'top';
				this.mousePos = 'pageY';
				this.sizePos = 'offsetHeight';
				this.tooltip.addClass('right')[0].style.left = '100%';
				break;
			default:
				this.picker
					.addClass('slider-horizontal')
					.css('width', origWidth);
				this.orientation = 'horizontal';
				this.stylePos = 'left';
				this.mousePos = 'pageX';
				this.sizePos = 'offsetWidth';
				this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
				break;
		}

        ['min', 'max', 'step', 'value'].forEach(function(attr) {
            this[attr] = el.data('slider-' + attr) || options[attr] || el.prop(attr);
        }, this);

        if (this.value[1]) {
			this.range = true;
		}

		this.selection = this.element.data('slider-selection')||options.selection;
		this.selectionEl = this.picker.find('.slider-selection');
		if (this.selection === 'none') {
			this.selectionEl.addClass('hide');
		}
		this.selectionElStyle = this.selectionEl[0].style;

		this.handle1 = this.picker.find('.slider-handle:first');
		this.handle1Stype = this.handle1[0].style;
		this.handle2 = this.picker.find('.slider-handle:last');
		this.handle2Stype = this.handle2[0].style;

		var handle = this.element.data('slider-handle')||options.handle;
		switch(handle) {
			case 'round':
				this.handle1.addClass('round');
				this.handle2.addClass('round');
				break;
			case 'triangle':
				this.handle1.addClass('triangle');
				this.handle2.addClass('triangle');
				break;
		}

		if (this.range) {
			this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
			this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
		} else {
			this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
			this.handle2.addClass('hide');
			if (this.selection === 'after') {
				this.value[1] = this.max;
			} else {
				this.value[1] = this.min;
			}
		}
		this.diff = this.max - this.min;
		this.percentage = [
			(this.value[0]-this.min)*100/this.diff,
			(this.value[1]-this.min)*100/this.diff,
			this.step*100/this.diff
		];

		this.offset = this.picker.offset();
		this.size = this.picker[0][this.sizePos];

		this.formater = options.formater;

		this.reversed = this.element.data('slider-reversed')||options.reversed;

		this.layout();

		if (this.touchCapable) {
			// Touch: Bind touch events:
			this.picker.on({
				touchstart: $.proxy(this.mousedown, this)
			});
		} else {
			this.picker.on({
				mousedown: $.proxy(this.mousedown, this)
			});
		}

		if (tooltip === 'show') {
			this.picker.on({
				mouseenter: $.proxy(this.showTooltip, this),
				mouseleave: $.proxy(this.hideTooltip, this)
			});
		} else {
			this.tooltip.addClass('hide');
		}

		if (updateSlider === true) {
			var old = this.getValue();
			var val = this.calculateValue();
			this.element
				.trigger({
					type: 'slide',
					value: val
				})
				.data('value', val)
				.prop('value', val);

			if (old !== val) {
				this.element
                    .trigger({
                        type: 'slideChange',
                        new: val,
                        old: old
                    })
                    .data('value', val)
                    .prop('value', val);
			}
		}
	};

	Slider.prototype = {
		constructor: Slider,

		over: false,
		inDrag: false,

		showTooltip: function(){
			this.tooltip.addClass('in');
			//var left = Math.round(this.percent*this.width);
			//this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
			this.over = true;
		},

		hideTooltip: function(){
			if (this.inDrag === false) {
				this.tooltip.removeClass('in');
			}
			this.over = false;
		},

		layout: function(){
      var positionPercentages;

      if(this.reversed) {
        positionPercentages = [ 100 - this.percentage[0], this.percentage[1] ];
      } else {
        positionPercentages = [ this.percentage[0], this.percentage[1] ];
      }

      this.handle1Stype[this.stylePos] = positionPercentages[0]+'%';
      this.handle2Stype[this.stylePos] = positionPercentages[1]+'%';

      if (this.orientation === 'vertical') {
        this.selectionElStyle.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
        this.selectionElStyle.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
      } else {
        this.selectionElStyle.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
        this.selectionElStyle.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
      }

      if (this.range) {
        this.tooltipInner.text(
          this.formater(this.value[0]) + ' : ' + this.formater(this.value[1])
        );
        this.tooltip[0].style[this.stylePos] = this.size * (positionPercentages[0] + (positionPercentages[1] - positionPercentages[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
      } else {
        this.tooltipInner.text(
          this.formater(this.value[0])
        );
        this.tooltip[0].style[this.stylePos] = this.size * positionPercentages[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
      }
    },

		mousedown: function(ev) {

			// Touch: Get the original event:
			if (this.touchCapable && ev.type === 'touchstart') {
				ev = ev.originalEvent;
			}

			this.offset = this.picker.offset();
			this.size = this.picker[0][this.sizePos];

			var percentage = this.getPercentage(ev);

			if (this.range) {
				var diff1 = Math.abs(this.percentage[0] - percentage);
				var diff2 = Math.abs(this.percentage[1] - percentage);
				this.dragged = (diff1 < diff2) ? 0 : 1;
			} else {
				this.dragged = 0;
			}

			this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
			this.layout();

			if (this.touchCapable) {
				// Touch: Bind touch events:
				$(document).on({
					touchmove: $.proxy(this.mousemove, this),
					touchend: $.proxy(this.mouseup, this)
				});
			} else {
				$(document).on({
					mousemove: $.proxy(this.mousemove, this),
					mouseup: $.proxy(this.mouseup, this)
				});
			}

			this.inDrag = true;
			var val = this.calculateValue();
			this.setValue(val);
			this.element.trigger({
					type: 'slideStart',
					value: val
				}).trigger({
					type: 'slide',
					value: val
				});
			return false;
		},

		mousemove: function(ev) {

			// Touch: Get the original event:
			if (this.touchCapable && ev.type === 'touchmove') {
				ev = ev.originalEvent;
			}

			var percentage = this.getPercentage(ev);
			if (this.range) {
				if (this.dragged === 0 && this.percentage[1] < percentage) {
					this.percentage[0] = this.percentage[1];
					this.dragged = 1;
				} else if (this.dragged === 1 && this.percentage[0] > percentage) {
					this.percentage[1] = this.percentage[0];
					this.dragged = 0;
				}
			}
			this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
			this.layout();
			var val = this.calculateValue();
			this.setValue(val);
			this.element
				.trigger({
					type: 'slide',
					value: val
				})
				.data('value', val)
				.prop('value', val);
			return false;
		},

		mouseup: function() {
			if (this.touchCapable) {
				// Touch: Bind touch events:
				$(document).off({
					touchmove: this.mousemove,
					touchend: this.mouseup
				});
			} else {
				$(document).off({
					mousemove: this.mousemove,
					mouseup: this.mouseup
				});
			}

			this.inDrag = false;
			if (this.over === false) {
				this.hideTooltip();
			}
			var val = this.calculateValue();
			this.layout();
			this.element
				.trigger({
					type: 'slideStop',
					value: val
				})
				.data('value', val)
				.prop('value', val);
			return false;
		},

		calculateValue: function() {
			var val;
			if (this.range) {
				val = [
					(Math.max(this.min, this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step)),
					(Math.min(this.max, this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step))
				];
				this.value = val;
			} else {
				val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
                if (val < this.min) {
                    val = this.min;
                else if (val > this.max) {
                    val = this.max;
                }
				this.value = [val, this.value[1]];
			}
			return val;
		},

		getPercentage: function(ev) {
			if (this.touchCapable) {
				ev = ev.touches[0];
			}
			var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
			percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
			return Math.max(0, Math.min(100, percentage));
		},

		getValue: function() {
			if (this.range) {
				return this.value;
			}
			return this.value[0];
		},

		setValue: function(val) {
			this.value = val;

			if (this.range) {
				this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
				this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
			} else {
				this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
				this.handle2.addClass('hide');
				if (this.selection === 'after') {
					this.value[1] = this.max;
				} else {
					this.value[1] = this.min;
				}
			}
			this.diff = this.max - this.min;
			this.percentage = [
				(this.value[0]-this.min)*100/this.diff,
				(this.value[1]-this.min)*100/this.diff,
				this.step*100/this.diff
			];
			this.layout();
		},
		destroy: function(){
			this.element.show().insertBefore(this.picker);
			this.picker.remove();
		},
	};

	$.fn.slider = function ( option, val ) {
        if (option) {
            if (typeof option == 'string') {
                return $(this).data('slider')[option](val);
            }
        } else {
            return this.each(function () {
                var $this = $(this),
                    data = $this.data('slider'),
                    options = typeof option === 'object' && option;
                if (!data)  {
                    $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
                }
            });
        }
	};

	$.fn.slider.defaults = {
		min: 0,
		max: 10,
		step: 1,
		orientation: 'horizontal',
		value: 5,
		selection: 'before',
		tooltip: 'show',
		handle: 'round',
		reversed : false,
		formater: function(value) {
			return value;
		}
	};

	$.fn.slider.Constructor = Slider;

})( window.jQuery );
<commit_msg>insert missing curly brace<commit_after>/* =========================================================
 * bootstrap-slider.js v2.0.0
 * http://www.eyecon.ro/bootstrap-slider
 * =========================================================
 * Copyright 2012 Stefan Petre
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function( $ ) {

	var Slider = function(element, options) {
		var el = this.element = $(element).hide();
        var origWidth = el.outerWidth();

		var updateSlider = false;
		var parent = this.element.parent();

		if (parent.hasClass('slider') === true) {
			updateSlider = true;
			this.picker = parent;
		} else {
			this.picker = $('
'+
								'
'+
									'

'+
									'

'+
									'

'+
								'
'+
								'

'+
							'
')
								.insertBefore(this.element)
								.append(this.element);
		}

		this.id = this.element.data('slider-id')||options.id;
		if (this.id) {
			this.picker[0].id = this.id;
		}

		if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
			this.touchCapable = true;
		}

		var tooltip = this.element.data('slider-tooltip')||options.tooltip;

		this.tooltip = this.picker.find('.tooltip');
		this.tooltipInner = this.tooltip.find('div.tooltip-inner');

		this.orientation = this.element.data('slider-orientation')||options.orientation;
		switch(this.orientation) {
			case 'vertical':
				this.picker.addClass('slider-vertical');
				this.stylePos = 'top';
				this.mousePos = 'pageY';
				this.sizePos = 'offsetHeight';
				this.tooltip.addClass('right')[0].style.left = '100%';
				break;
			default:
				this.picker
					.addClass('slider-horizontal')
					.css('width', origWidth);
				this.orientation = 'horizontal';
				this.stylePos = 'left';
				this.mousePos = 'pageX';
				this.sizePos = 'offsetWidth';
				this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
				break;
		}

        ['min', 'max', 'step', 'value'].forEach(function(attr) {
            this[attr] = el.data('slider-' + attr) || options[attr] || el.prop(attr);
        }, this);

        if (this.value[1]) {
			this.range = true;
		}

		this.selection = this.element.data('slider-selection')||options.selection;
		this.selectionEl = this.picker.find('.slider-selection');
		if (this.selection === 'none') {
			this.selectionEl.addClass('hide');
		}
		this.selectionElStyle = this.selectionEl[0].style;

		this.handle1 = this.picker.find('.slider-handle:first');
		this.handle1Stype = this.handle1[0].style;
		this.handle2 = this.picker.find('.slider-handle:last');
		this.handle2Stype = this.handle2[0].style;

		var handle = this.element.data('slider-handle')||options.handle;
		switch(handle) {
			case 'round':
				this.handle1.addClass('round');
				this.handle2.addClass('round');
				break;
			case 'triangle':
				this.handle1.addClass('triangle');
				this.handle2.addClass('triangle');
				break;
		}

		if (this.range) {
			this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
			this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
		} else {
			this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
			this.handle2.addClass('hide');
			if (this.selection === 'after') {
				this.value[1] = this.max;
			} else {
				this.value[1] = this.min;
			}
		}
		this.diff = this.max - this.min;
		this.percentage = [
			(this.value[0]-this.min)*100/this.diff,
			(this.value[1]-this.min)*100/this.diff,
			this.step*100/this.diff
		];

		this.offset = this.picker.offset();
		this.size = this.picker[0][this.sizePos];

		this.formater = options.formater;

		this.reversed = this.element.data('slider-reversed')||options.reversed;

		this.layout();

		if (this.touchCapable) {
			// Touch: Bind touch events:
			this.picker.on({
				touchstart: $.proxy(this.mousedown, this)
			});
		} else {
			this.picker.on({
				mousedown: $.proxy(this.mousedown, this)
			});
		}

		if (tooltip === 'show') {
			this.picker.on({
				mouseenter: $.proxy(this.showTooltip, this),
				mouseleave: $.proxy(this.hideTooltip, this)
			});
		} else {
			this.tooltip.addClass('hide');
		}

		if (updateSlider === true) {
			var old = this.getValue();
			var val = this.calculateValue();
			this.element
				.trigger({
					type: 'slide',
					value: val
				})
				.data('value', val)
				.prop('value', val);

			if (old !== val) {
				this.element
                    .trigger({
                        type: 'slideChange',
                        new: val,
                        old: old
                    })
                    .data('value', val)
                    .prop('value', val);
			}
		}
	};

	Slider.prototype = {
		constructor: Slider,

		over: false,
		inDrag: false,

		showTooltip: function(){
			this.tooltip.addClass('in');
			//var left = Math.round(this.percent*this.width);
			//this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
			this.over = true;
		},

		hideTooltip: function(){
			if (this.inDrag === false) {
				this.tooltip.removeClass('in');
			}
			this.over = false;
		},

		layout: function(){
      var positionPercentages;

      if(this.reversed) {
        positionPercentages = [ 100 - this.percentage[0], this.percentage[1] ];
      } else {
        positionPercentages = [ this.percentage[0], this.percentage[1] ];
      }

      this.handle1Stype[this.stylePos] = positionPercentages[0]+'%';
      this.handle2Stype[this.stylePos] = positionPercentages[1]+'%';

      if (this.orientation === 'vertical') {
        this.selectionElStyle.top = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
        this.selectionElStyle.height = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
      } else {
        this.selectionElStyle.left = Math.min(positionPercentages[0], positionPercentages[1]) +'%';
        this.selectionElStyle.width = Math.abs(positionPercentages[0] - positionPercentages[1]) +'%';
      }

      if (this.range) {
        this.tooltipInner.text(
          this.formater(this.value[0]) + ' : ' + this.formater(this.value[1])
        );
        this.tooltip[0].style[this.stylePos] = this.size * (positionPercentages[0] + (positionPercentages[1] - positionPercentages[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
      } else {
        this.tooltipInner.text(
          this.formater(this.value[0])
        );
        this.tooltip[0].style[this.stylePos] = this.size * positionPercentages[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
      }
    },

		mousedown: function(ev) {

			// Touch: Get the original event:
			if (this.touchCapable && ev.type === 'touchstart') {
				ev = ev.originalEvent;
			}

			this.offset = this.picker.offset();
			this.size = this.picker[0][this.sizePos];

			var percentage = this.getPercentage(ev);

			if (this.range) {
				var diff1 = Math.abs(this.percentage[0] - percentage);
				var diff2 = Math.abs(this.percentage[1] - percentage);
				this.dragged = (diff1 < diff2) ? 0 : 1;
			} else {
				this.dragged = 0;
			}

			this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
			this.layout();

			if (this.touchCapable) {
				// Touch: Bind touch events:
				$(document).on({
					touchmove: $.proxy(this.mousemove, this),
					touchend: $.proxy(this.mouseup, this)
				});
			} else {
				$(document).on({
					mousemove: $.proxy(this.mousemove, this),
					mouseup: $.proxy(this.mouseup, this)
				});
			}

			this.inDrag = true;
			var val = this.calculateValue();
			this.setValue(val);
			this.element.trigger({
					type: 'slideStart',
					value: val
				}).trigger({
					type: 'slide',
					value: val
				});
			return false;
		},

		mousemove: function(ev) {

			// Touch: Get the original event:
			if (this.touchCapable && ev.type === 'touchmove') {
				ev = ev.originalEvent;
			}

			var percentage = this.getPercentage(ev);
			if (this.range) {
				if (this.dragged === 0 && this.percentage[1] < percentage) {
					this.percentage[0] = this.percentage[1];
					this.dragged = 1;
				} else if (this.dragged === 1 && this.percentage[0] > percentage) {
					this.percentage[1] = this.percentage[0];
					this.dragged = 0;
				}
			}
			this.percentage[this.dragged] = this.reversed ? 100 - percentage : percentage;
			this.layout();
			var val = this.calculateValue();
			this.setValue(val);
			this.element
				.trigger({
					type: 'slide',
					value: val
				})
				.data('value', val)
				.prop('value', val);
			return false;
		},

		mouseup: function() {
			if (this.touchCapable) {
				// Touch: Bind touch events:
				$(document).off({
					touchmove: this.mousemove,
					touchend: this.mouseup
				});
			} else {
				$(document).off({
					mousemove: this.mousemove,
					mouseup: this.mouseup
				});
			}

			this.inDrag = false;
			if (this.over === false) {
				this.hideTooltip();
			}
			var val = this.calculateValue();
			this.layout();
			this.element
				.trigger({
					type: 'slideStop',
					value: val
				})
				.data('value', val)
				.prop('value', val);
			return false;
		},

		calculateValue: function() {
			var val;
			if (this.range) {
				val = [
					(Math.max(this.min, this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step)),
					(Math.min(this.max, this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step))
				];
				this.value = val;
			} else {
				val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
                if (val < this.min) {
                    val = this.min;
                }
                else if (val > this.max) {
                    val = this.max;
                }
				this.value = [val, this.value[1]];
			}
			return val;
		},

		getPercentage: function(ev) {
			if (this.touchCapable) {
				ev = ev.touches[0];
			}
			var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
			percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
			return Math.max(0, Math.min(100, percentage));
		},

		getValue: function() {
			if (this.range) {
				return this.value;
			}
			return this.value[0];
		},

		setValue: function(val) {
			this.value = val;

			if (this.range) {
				this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
				this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
			} else {
				this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
				this.handle2.addClass('hide');
				if (this.selection === 'after') {
					this.value[1] = this.max;
				} else {
					this.value[1] = this.min;
				}
			}
			this.diff = this.max - this.min;
			this.percentage = [
				(this.value[0]-this.min)*100/this.diff,
				(this.value[1]-this.min)*100/this.diff,
				this.step*100/this.diff
			];
			this.layout();
		},
		destroy: function(){
			this.element.show().insertBefore(this.picker);
			this.picker.remove();
		},
	};

	$.fn.slider = function ( option, val ) {
        if (option) {
            if (typeof option == 'string') {
                return $(this).data('slider')[option](val);
            }
        } else {
            return this.each(function () {
                var $this = $(this),
                    data = $this.data('slider'),
                    options = typeof option === 'object' && option;
                if (!data)  {
                    $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
                }
            });
        }
	};

	$.fn.slider.defaults = {
		min: 0,
		max: 10,
		step: 1,
		orientation: 'horizontal',
		value: 5,
		selection: 'before',
		tooltip: 'show',
		handle: 'round',
		reversed : false,
		formater: function(value) {
			return value;
		}
	};

	$.fn.slider.Constructor = Slider;

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


<commit_before>/*! ========================================================================
 * Bootstrap Toggle: bootstrap-toggle.js v2.2.0
 * http://www.bootstraptoggle.com
 * ========================================================================
 * Copyright 2014 Min Hur, The New York Times Company
 * Licensed under MIT
 * ======================================================================== */

 +function ($) {
 	'use strict';

	// TOGGLE PUBLIC CLASS DEFINITION
	// ==============================

	var Toggle = function (element, options) {
		this.$element  = $(element)
		this.options   = $.extend({}, this.defaults(), options)
		this.render()
	}

	Toggle.VERSION  = '2.2.0'

	Toggle.DEFAULTS = {
		on: 'On',
		off: 'Off',
		onstyle: 'primary',
		offstyle: 'default',
		size: 'normal',
		style: '',
		width: null,
		height: null
	}

	Toggle.prototype.defaults = function() {
		return {
			on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
			off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
			onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
			offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
			size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
			style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
			width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
			height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
		}
	}

	Toggle.prototype.render = function () {
		this._onstyle = 'btn-' + this.options.onstyle
		this._offstyle = 'btn-' + this.options.offstyle
		this._indeterminatestyle = 'indeterminate'
		var size = this.options.size === 'large' ? 'btn-lg'
			: this.options.size === 'small' ? 'btn-sm'
			: this.options.size === 'mini' ? 'btn-xs'
			: ''
		var checked = this.isChecked()
		var $toggleOn = $('').html(this.options.on)
			.addClass(this._onstyle + ' ' + size)
		var $toggleOff = $('').html(this.options.off)
			.addClass(this._offstyle + ' ' + size + ' active')
		var $toggleHandle = $('')
			.addClass(size)
		var $toggleGroup = $('
')
			.append($toggleOn, $toggleOff, $toggleHandle)
		var $toggle = $('
')
			.addClass( checked ? this._onstyle : this._offstyle+' off' )
			.addClass(size).addClass(this.options.style)

		this.$element.wrap($toggle)
		$.extend(this, {
			$toggle: this.$element.parent(),
			$toggleOn: $toggleOn,
			$toggleOff: $toggleOff,
			$toggleGroup: $toggleGroup
		})
		this.$toggle.append(this.$element.attr('placeholder'), $toggleGroup)

		var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
		var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
		$toggleOn.addClass('toggle-on')
		$toggleOff.addClass('toggle-off')
		this.$toggle.css({ width: width, height: height }).toggleClass(this._indeterminatestyle, checked === '')
		if (this.options.height) {
			$toggleOn.css('line-height', $toggleOn.height() + 'px')
			$toggleOff.css('line-height', $toggleOff.height() + 'px')
		}
		this.update(true)
		this.trigger(true)
	}

	Toggle.prototype.isChecked = function () {
		if (this.$element.is(':checkbox')) return this.$element.prop('checked')
		var val = this.$element.val()
		return val === '' ? val : val == 'true'
	}

	Toggle.prototype.setChecked = function (checked) {
		return this.$element.is(':checkbox') ? this.$element.prop('checked', checked) : this.$element.val(checked)
	}

	Toggle.prototype.toggle = function () {
		this._toggle(!this.isChecked())
	}

	Toggle.prototype.on = function (silent) {
		this._toggle(true, silent)
	}

	Toggle.prototype.off = function (silent) {
		this._toggle(false, silent)
	}

	Toggle.prototype._toggle = function (checked, silent) {
		if (this.$element.prop('disabled')) return false
		this.$toggle.removeClass(this._indeterminatestyle).toggleClass(this._onstyle, checked).toggleClass(this._offstyle + ' off', !checked)
		this.setChecked(checked)
		if (!silent) this.trigger()
	}

	Toggle.prototype.enable = function () {
		this.$toggle.removeAttr('disabled')
		this.$element.prop('disabled', false)
	}

	Toggle.prototype.disable = function () {
		this.$toggle.attr('disabled', 'disabled')
		this.$element.prop('disabled', true)
	}

	Toggle.prototype.update = function (silent) {
		if (this.$element.prop('disabled')) this.disable()
		else this.enable()
		var checked = this.isChecked();
		if (checked == true) this.on(silent)
		else if (checked === false) this.off(silent)
	}

	Toggle.prototype.trigger = function (silent) {
		this.$element.off('change.bs.toggle')
		if (!silent) this.$element.change()
		this.$element.on('change.bs.toggle', $.proxy(function() {
			this.update()
		}, this))
	}

	Toggle.prototype.destroy = function() {
		this.$element.off('change.bs.toggle')
		this.$toggleGroup.remove()
		this.$element.removeData('bs.toggle')
		this.$element.unwrap()
	}

	// TOGGLE PLUGIN DEFINITION
	// ========================

	function Plugin(option) {
		return this.each(function () {
			var $this   = $(this)
			var data    = $this.data('bs.toggle')
			var options = typeof option == 'object' && option

			if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
			if (typeof option == 'string' && data[option]) data[option]()
		})
	}

	var old = $.fn.bootstrapToggle

	$.fn.bootstrapToggle             = Plugin
	$.fn.bootstrapToggle.Constructor = Toggle

	// TOGGLE NO CONFLICT
	// ==================

	$.fn.toggle.noConflict = function () {
		$.fn.bootstrapToggle = old
		return this
	}

	// TOGGLE DATA-API
	// ===============

	$(function() {
		$('input[type=checkbox][data-toggle^=toggle],input[type=hidden][data-toggle^=toggle]').bootstrapToggle()
	})

	$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
		var $checkbox = $(this).find('input[type=checkbox],input[type=hidden]')
		$checkbox.bootstrapToggle('toggle')
		e.preventDefault()
	})

}(jQuery);
<commit_msg>Fix condition<commit_after>/*! ========================================================================
 * Bootstrap Toggle: bootstrap-toggle.js v2.2.0
 * http://www.bootstraptoggle.com
 * ========================================================================
 * Copyright 2014 Min Hur, The New York Times Company
 * Licensed under MIT
 * ======================================================================== */

 +function ($) {
 	'use strict';

	// TOGGLE PUBLIC CLASS DEFINITION
	// ==============================

	var Toggle = function (element, options) {
		this.$element  = $(element)
		this.options   = $.extend({}, this.defaults(), options)
		this.render()
	}

	Toggle.VERSION  = '2.2.0'

	Toggle.DEFAULTS = {
		on: 'On',
		off: 'Off',
		onstyle: 'primary',
		offstyle: 'default',
		size: 'normal',
		style: '',
		width: null,
		height: null
	}

	Toggle.prototype.defaults = function() {
		return {
			on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
			off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
			onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
			offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
			size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
			style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
			width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
			height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
		}
	}

	Toggle.prototype.render = function () {
		this._onstyle = 'btn-' + this.options.onstyle
		this._offstyle = 'btn-' + this.options.offstyle
		this._indeterminatestyle = 'indeterminate'
		var size = this.options.size === 'large' ? 'btn-lg'
			: this.options.size === 'small' ? 'btn-sm'
			: this.options.size === 'mini' ? 'btn-xs'
			: ''
		var checked = this.isChecked()
		var $toggleOn = $('').html(this.options.on)
			.addClass(this._onstyle + ' ' + size)
		var $toggleOff = $('').html(this.options.off)
			.addClass(this._offstyle + ' ' + size + ' active')
		var $toggleHandle = $('')
			.addClass(size)
		var $toggleGroup = $('
')
			.append($toggleOn, $toggleOff, $toggleHandle)
		var $toggle = $('
')
			.addClass( checked ? this._onstyle : this._offstyle+' off' )
			.addClass(size).addClass(this.options.style)

		this.$element.wrap($toggle)
		$.extend(this, {
			$toggle: this.$element.parent(),
			$toggleOn: $toggleOn,
			$toggleOff: $toggleOff,
			$toggleGroup: $toggleGroup
		})
		this.$toggle.append(this.$element.attr('placeholder'), $toggleGroup)

		var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
		var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
		$toggleOn.addClass('toggle-on')
		$toggleOff.addClass('toggle-off')
		this.$toggle.css({ width: width, height: height }).toggleClass(this._indeterminatestyle, checked === '')
		if (this.options.height) {
			$toggleOn.css('line-height', $toggleOn.height() + 'px')
			$toggleOff.css('line-height', $toggleOff.height() + 'px')
		}
		this.update(true)
		this.trigger(true)
	}

	Toggle.prototype.isChecked = function () {
		if (this.$element.is(':checkbox')) return this.$element.prop('checked')
		var val = this.$element.val()
		return val === '' ? val : val == 'true'
	}

	Toggle.prototype.setChecked = function (checked) {
		return this.$element.is(':checkbox') ? this.$element.prop('checked', checked) : this.$element.val(checked)
	}

	Toggle.prototype.toggle = function () {
		this._toggle(!this.isChecked())
	}

	Toggle.prototype.on = function (silent) {
		this._toggle(true, silent)
	}

	Toggle.prototype.off = function (silent) {
		this._toggle(false, silent)
	}

	Toggle.prototype._toggle = function (checked, silent) {
		if (this.$element.prop('disabled')) return false
		this.$toggle.removeClass(this._indeterminatestyle).toggleClass(this._onstyle, checked).toggleClass(this._offstyle + ' off', !checked)
		this.setChecked(checked)
		if (!silent) this.trigger()
	}

	Toggle.prototype.enable = function () {
		this.$toggle.removeAttr('disabled')
		this.$element.prop('disabled', false)
	}

	Toggle.prototype.disable = function () {
		this.$toggle.attr('disabled', 'disabled')
		this.$element.prop('disabled', true)
	}

	Toggle.prototype.update = function (silent) {
		if (this.$element.prop('disabled')) this.disable()
		else this.enable()
		var checked = this.isChecked();
		if (checked === true) this.on(silent)
		else if (checked === false) this.off(silent)
	}

	Toggle.prototype.trigger = function (silent) {
		this.$element.off('change.bs.toggle')
		if (!silent) this.$element.change()
		this.$element.on('change.bs.toggle', $.proxy(function() {
			this.update()
		}, this))
	}

	Toggle.prototype.destroy = function() {
		this.$element.off('change.bs.toggle')
		this.$toggleGroup.remove()
		this.$element.removeData('bs.toggle')
		this.$element.unwrap()
	}

	// TOGGLE PLUGIN DEFINITION
	// ========================

	function Plugin(option) {
		return this.each(function () {
			var $this   = $(this)
			var data    = $this.data('bs.toggle')
			var options = typeof option == 'object' && option

			if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
			if (typeof option == 'string' && data[option]) data[option]()
		})
	}

	var old = $.fn.bootstrapToggle

	$.fn.bootstrapToggle             = Plugin
	$.fn.bootstrapToggle.Constructor = Toggle

	// TOGGLE NO CONFLICT
	// ==================

	$.fn.toggle.noConflict = function () {
		$.fn.bootstrapToggle = old
		return this
	}

	// TOGGLE DATA-API
	// ===============

	$(function() {
		$('input[type=checkbox][data-toggle^=toggle],input[type=hidden][data-toggle^=toggle]').bootstrapToggle()
	})

	$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
		var $checkbox = $(this).find('input[type=checkbox],input[type=hidden]')
		$checkbox.bootstrapToggle('toggle')
		e.preventDefault()
	})

}(jQuery);
<|endoftext|>


<commit_before>/* @flow */

import type { LoggerTypes } from '../types';

const chalk = require('chalk');

const success = chalk.green;
const info = chalk.gray;
const warn = chalk.yellow;
const filename = chalk.cyan;
const highlight = chalk.bold;
const debug = chalk.dim;
const error = chalk.red;

type ColorScheme = LoggerTypes & {
  filename: Function;
  highlight: Function;
}

const colorScheme: ColorScheme = {
  success,
  info,
  warn,
  debug,
  error,
  filename,
  highlight,
};

module.exports = colorScheme;
<commit_msg>set info color to default<commit_after>/* @flow */

import type { LoggerTypes } from '../types';

const chalk = require('chalk');

const success = chalk.green;
// Here we don't want to set color
// cause of https://github.com/TrueCar/gluestick/issues/624
const info = (msg) => msg;
const warn = chalk.yellow;
const filename = chalk.cyan;
const highlight = chalk.bold;
const debug = chalk.dim;
const error = chalk.red;

type ColorScheme = LoggerTypes & {
  filename: Function;
  highlight: Function;
}

const colorScheme: ColorScheme = {
  success,
  info,
  warn,
  debug,
  error,
  filename,
  highlight,
};

module.exports = colorScheme;
<|endoftext|>


<commit_before>/* This is a variant of the suggestion in the jQuery FAQ:
     https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
   We need this since election IDs now have dots in them.
 */
function escapeID(originalID) {
  return originalID.replace( /(:|\.|\[|\]|,)/g, "\\$1" );
}

/* Change the visibility of a Select2 widget; select2Element should be a
   jQuery-wrapped element */

function setSelect2Visibility(select2Element, visibility) {
  /* If visibility is false, this both disables the Select2 boxes and
   * hides them by hiding their enclosing element. Otherwise it
   * enables it and makes the enclosure visible. */
  select2Element.prop(
    'disabled',
    !visibility
  );

  if (visibility) {
    select2Element.parent().show()
  } else {
    select2Element.parent().hide();
  }
}

/* Make all the party drop-downs into Select2 widgets */

function setUpPartySelect2s() {
  $('select.party-select').not('.select2-offscreen').not('.select2-container').each(function(i) {
    var partySelect = $(this)
    var select_options = {
      width: '100%',
      placeholder: 'Select a party',
      allowClear: true
    }

    if (partySelect.attr('show_load_more')) {
      var data = {
          id: 0,
          text: 'Click to load more parties…'
      };
      var loadMoreOption = new Option(data.text, data.id, false, false);
      partySelect.append(loadMoreOption)

      select_options.matcher = function(params, data) {
        var match = partySelect.select2.defaults.defaults.matcher(params, data);
        if (match) {
          return match;
        }
        if (data.id === "0") {
          return data;
        } else {
          return null
        }
      }
      partySelect.on('select2:select', function (e) {
          var data = e.params.data;
          if (data.id == 0) {
            var initial_val = partySelect.val();
            var partyset = $(this).data('partyset').toUpperCase();
            // partySelect.find('option[value="0"]').text('Loading…');
            data.text = "Loading…"
            partySelect.trigger('change.select2');

            $.getJSON('/all-parties.json?register=' + partyset, function(items) {
              $.each(items['items'], function(party_id, descs) {
                var group = $('<optgroup label="' + descs.text + '" />');
                if (descs['children']) {
                  $.each(descs['children'], function(child) {
                    $('<option value="'+this.id+'"/>').html(this.text).appendTo(group);
                  });
                } else {
                    $('<option value="'+descs.id+'"/>').html(descs.text).appendTo(group);
                }
                group.appendTo(partySelect);
              });
              partySelect.find('option[value="0"]').remove();
              partySelect.select2('open');
            });

          }
      });

    }

    partySelect.select2(select_options);
  });
}

$(document).on('focus', '.select2', function (e) {
  if (e.originalEvent) {
    $(this).siblings('select').select2('open');
  }
});

/* Make all the post drop-downs into Select2 widgets */

function setUpPostSelect2s() {
  $('.post-select').each(function(i) {
    var postSelect = $(this),
      hidden = postSelect.prop('tagName') == 'INPUT' &&
         postSelect.attr('type') == 'hidden';
    /* If it's a real select box (not a hidden input) make it into a
     * Select2 box; also, don't try to reinitialize a select that's
     * already a Select2 */
    if (!(hidden || $(postSelect).data('select2'))) {
        var select_config = {
        placeholder: 'Post',
        allowClear: true,
        width: '100%'
      }
      if (postSelect.prop('show_load_more')) {
          var load_more_option = {
              id: 0,
              text: 'Load more parties…'
          }
          postSelect.append(load_more_option)
          // select_config.
      }
      postSelect.select2(select_config);
    }
    postSelect.on('change', function (e) {
      updateFields();
    });
    updateFields();
  });
}

/* Set the visibility of an input element and any label for it */

function setVisibility(plainInputElement, newVisiblity) {
  var inputElement = $(plainInputElement),
      inputElementID = escapeID(plainInputElement.id),
      labelElement = $('label[for=' + inputElementID + ']');
  inputElement.toggle(newVisiblity);
  labelElement.toggle(newVisiblity);
}

/* Update the visibility of the party and post drop-downs for a particular
   election */

function updateSelectsForElection(show, election) {
  /* Whether we should show the party and post selects is
     determined by the boolean 'show'. */
  var partySelectToShowID,
      partyPositionToShowID,
      postID = $('#id_constituency_' + escapeID(election)).val(),
      partySet;
  if (postID) {
    partySet = postIDToPartySet[postID].toUpperCase();
  }
  if (show) {
    if (postID) {
      partySelectToShowID = 'id_party_' + partySet + '_' + election;
      partyPositionToShowID = 'id_party_list_position_' + partySet + '_' + election;
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility(
          $(this),
          $(this).attr('id') == partySelectToShowID
        );
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, $(this).attr('id') == partyPositionToShowID);
      });
    }
  } else {
    $('.party-select-' + escapeID(election)).each(function(i) {
      setSelect2Visibility($(this), false);
    });
    $('.party-position-' + escapeID(election)).each(function() {
      setVisibility(this, false);
    });
  }
  setSelect2Visibility($('#id_constituency_' + escapeID(election)), show);
}

/* Make sure that the party and constituency select boxes are updated
   when you choose whether the candidate is standing in that election
   or not. */

function setUpStandingCheckbox() {
  $('#person-details select.standing-select').on('change', function() {
    updateFields();
  });
}

/* This should be called whenever the select drop-downs for party
   and post that have to be shown might have to be shown.  */

function updateFields() {
  $('#person-details select.standing-select').each(function(i) {
    var standing = $(this).val() == 'standing',
        match = /^id_standing_(.*)/.exec($(this).attr('id')),
        election = match[1];
    updateSelectsForElection(standing, election); });
}

/* This is called to display a new election form on the edit person
   page, if the dynamic "add new election" button is being used. */

function showElectionsForm() {
  $.getJSON("/api/current-elections/?future=1").done(function( data ) {
    var select_data = $.map(data, function(obj, key) {
      return { id: key, text: obj.name + ' (' + obj.election_date + ')' };
    })
    $('#add_more_elections').select2({
      data: select_data,
    }).on('select2:select', function(e) {
      var data = e.params.data;
      var url = window.location.pathname + '/single_election_form/' + data.id;
      $.get(url, function(data) {
        $('.extra_elections_forms').html(data);
        setUpStandingCheckbox();
        setUpPartySelect2s();
        setUpPostSelect2s();
        updateFields();
      });
    });
    $('.add_more_elections_field').show();
    $('#add_election_button').hide();
  });
}

function toTitleCase(str) {
    return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

suggest_correction = function(el, suggestion) {

    suggestion_el = $('Change to ' + suggestion + '?');
    suggestion_el.click(function(clicked_el) {
        var this_link = $(this);
        this_link.prev('input').val($(this_link).find('span').text());
        $('.suggested').remove();
    })
    $('.suggested').remove();
    $(el).after(suggestion_el);

};

function checkNameFormat(e) {
    var name = e.target.value;
    var upper_first_matcher = /([A-Z]+,? [A-Za-z]+)/g;
    var match = upper_first_matcher.exec(name);
    if (match) {
        var name_parts = name.split(' ');
        var last_name = name_parts.shift();
        var name = name_parts.join(' ') + ' ' + toTitleCase(last_name);
        suggest_correction(e.target, name);
    }
}

$(document).ready(function() {
  $.getJSON('/post-id-to-party-set.json', function(data) {
      window.postIDToPartySet = data;
      setUpPartySelect2s();
      setUpPostSelect2s();
      setUpStandingCheckbox();
      updateFields();
      /* Now enable the "add an extra election" button if it's present */
      $('#add_election_button').on('click', showElectionsForm);
      $('.add_more_elections_field').hide();
      $('[name=name]').on('paste keyup', checkNameFormat);
      $('[name*=-name]').on('paste keyup', checkNameFormat);
  });
});
<commit_msg>Default to only showing the GB parties if there are two party lists<commit_after>/* This is a variant of the suggestion in the jQuery FAQ:
     https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
   We need this since election IDs now have dots in them.
 */
function escapeID(originalID) {
  return originalID.replace( /(:|\.|\[|\]|,)/g, "\\$1" );
}

/* Change the visibility of a Select2 widget; select2Element should be a
   jQuery-wrapped element */

function setSelect2Visibility(select2Element, visibility) {
  /* If visibility is false, this both disables the Select2 boxes and
   * hides them by hiding their enclosing element. Otherwise it
   * enables it and makes the enclosure visible. */
  select2Element.prop(
    'disabled',
    !visibility
  );

  if (visibility) {
    select2Element.parent().show()
  } else {
    select2Element.parent().hide();
  }
}

/* Make all the party drop-downs into Select2 widgets */

function setUpPartySelect2s() {
  var party_selects = $("select.party-select");
  party_selects.not('.select2-offscreen').not('.select2-container').each(function(i) {
    var partySelect = $(this)
    var select_options = {
      width: '100%',
      placeholder: 'Select a party',
      allowClear: true
    }

    if (partySelect.attr('show_load_more')) {
      var data = {
          id: 0,
          text: 'Click to load more parties…'
      };
      var loadMoreOption = new Option(data.text, data.id, false, false);
      partySelect.append(loadMoreOption)

      select_options.matcher = function(params, data) {
        var match = partySelect.select2.defaults.defaults.matcher(params, data);
        if (match) {
          return match;
        }
        if (data.id === "0") {
          return data;
        } else {
          return null
        }
      }
      partySelect.on('select2:select', function (e) {
          var data = e.params.data;
          if (data.id == 0) {
            var initial_val = partySelect.val();
            var partyset = $(this).data('partyset').toUpperCase();
            // partySelect.find('option[value="0"]').text('Loading…');
            data.text = "Loading…"
            partySelect.trigger('change.select2');

            $.getJSON('/all-parties.json?register=' + partyset, function(items) {
              $.each(items['items'], function(party_id, descs) {
                var group = $('<optgroup label="' + descs.text + '" />');
                if (descs['children']) {
                  $.each(descs['children'], function(child) {
                    $('<option value="'+this.id+'"/>').html(this.text).appendTo(group);
                  });
                } else {
                    $('<option value="'+descs.id+'"/>').html(descs.text).appendTo(group);
                }
                group.appendTo(partySelect);
              });
              partySelect.find('option[value="0"]').remove();
              partySelect.select2('open');
            });

          }
      });

    }

    partySelect.select2(select_options);
  });

  var post_select_exists = $(".post-select").length;
  if (post_select_exists && party_selects.length > 1) {
    /* If there is more than one party list, only show GB parties by default */
    party_selects.each(function(i, el) {
      if (el.name.indexOf("party_GB") !== 0){
          var select_el = $(escapeID("#" + el.dataset["select2Id"]));
          setSelect2Visibility(select_el, false);
      }
    });
  }

}

$(document).on('focus', '.select2', function (e) {
  if (e.originalEvent) {
    $(this).siblings('select').select2('open');
  }
});

/* Make all the post drop-downs into Select2 widgets */

function setUpPostSelect2s() {
  $('.post-select').each(function(i) {
    var postSelect = $(this),
      hidden = postSelect.prop('tagName') == 'INPUT' &&
         postSelect.attr('type') == 'hidden';
    /* If it's a real select box (not a hidden input) make it into a
     * Select2 box; also, don't try to reinitialize a select that's
     * already a Select2 */
    if (!(hidden || $(postSelect).data('select2'))) {
        var select_config = {
        placeholder: 'Post',
        allowClear: true,
        width: '100%'
      }
      if (postSelect.prop('show_load_more')) {
          var load_more_option = {
              id: 0,
              text: 'Load more parties…'
          }
          postSelect.append(load_more_option)
          // select_config.
      }
      postSelect.select2(select_config);
    }
    postSelect.on('change', function (e) {
      updateFields();
    });
    updateFields();
  });
}

/* Set the visibility of an input element and any label for it */

function setVisibility(plainInputElement, newVisiblity) {
  var inputElement = $(plainInputElement),
      inputElementID = escapeID(plainInputElement.id),
      labelElement = $('label[for=' + inputElementID + ']');
  inputElement.toggle(newVisiblity);
  labelElement.toggle(newVisiblity);
}

/* Update the visibility of the party and post drop-downs for a particular
   election */

function updateSelectsForElection(show, election) {
  /* Whether we should show the party and post selects is
     determined by the boolean 'show'. */
  var partySelectToShowID,
      partyPositionToShowID,
      postID = $('#id_constituency_' + escapeID(election)).val(),
      partySet;
  if (postID) {
    partySet = postIDToPartySet[postID].toUpperCase();
  }
  if (show) {
    if (postID) {
      partySelectToShowID = 'id_party_' + partySet + '_' + election;
      partyPositionToShowID = 'id_party_list_position_' + partySet + '_' + election;
      $('.party-select-' + escapeID(election)).each(function(i) {
        setSelect2Visibility(
          $(this),
          $(this).attr('id') == partySelectToShowID
        );
      });
      $('.party-position-' + escapeID(election)).each(function(i) {
        setVisibility(this, $(this).attr('id') == partyPositionToShowID);
      });
    }
  } else {
    $('.party-select-' + escapeID(election)).each(function(i) {
      setSelect2Visibility($(this), false);
    });
    $('.party-position-' + escapeID(election)).each(function() {
      setVisibility(this, false);
    });
  }
  setSelect2Visibility($('#id_constituency_' + escapeID(election)), show);
}

/* Make sure that the party and constituency select boxes are updated
   when you choose whether the candidate is standing in that election
   or not. */

function setUpStandingCheckbox() {
  $('#person-details select.standing-select').on('change', function() {
    updateFields();
  });
}

/* This should be called whenever the select drop-downs for party
   and post that have to be shown might have to be shown.  */

function updateFields() {
  $('#person-details select.standing-select').each(function(i) {
    var standing = $(this).val() == 'standing',
        match = /^id_standing_(.*)/.exec($(this).attr('id')),
        election = match[1];
    updateSelectsForElection(standing, election); });
}

/* This is called to display a new election form on the edit person
   page, if the dynamic "add new election" button is being used. */

function showElectionsForm() {
  $.getJSON("/api/current-elections/?future=1").done(function( data ) {
    var select_data = $.map(data, function(obj, key) {
      return { id: key, text: obj.name + ' (' + obj.election_date + ')' };
    })
    $('#add_more_elections').select2({
      data: select_data,
    }).on('select2:select', function(e) {
      var data = e.params.data;
      var url = window.location.pathname + '/single_election_form/' + data.id;
      $.get(url, function(data) {
        $('.extra_elections_forms').html(data);
        setUpStandingCheckbox();
        setUpPartySelect2s();
        setUpPostSelect2s();
        updateFields();
      });
    });
    $('.add_more_elections_field').show();
    $('#add_election_button').hide();
  });
}

function toTitleCase(str) {
    return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

suggest_correction = function(el, suggestion) {

    suggestion_el = $('Change to ' + suggestion + '?');
    suggestion_el.click(function(clicked_el) {
        var this_link = $(this);
        this_link.prev('input').val($(this_link).find('span').text());
        $('.suggested').remove();
    })
    $('.suggested').remove();
    $(el).after(suggestion_el);

};

function checkNameFormat(e) {
    var name = e.target.value;
    var upper_first_matcher = /([A-Z]+,? [A-Za-z]+)/g;
    var match = upper_first_matcher.exec(name);
    if (match) {
        var name_parts = name.split(' ');
        var last_name = name_parts.shift();
        var name = name_parts.join(' ') + ' ' + toTitleCase(last_name);
        suggest_correction(e.target, name);
    }
}

$(document).ready(function() {
  $.getJSON('/post-id-to-party-set.json', function(data) {
      window.postIDToPartySet = data;
      setUpPartySelect2s();
      setUpPostSelect2s();
      setUpStandingCheckbox();
      updateFields();
      /* Now enable the "add an extra election" button if it's present */
      $('#add_election_button').on('click', showElectionsForm);
      $('.add_more_elections_field').hide();
      $('[name=name]').on('paste keyup', checkNameFormat);
      $('[name*=-name]').on('paste keyup', checkNameFormat);
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import { c } from 'ttag';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { USER_ROLES } from 'proton-shared/lib/constants';

const { MEMBER_ROLE, ADMIN_ROLE } = USER_ROLES;

import { formatPlans } from '../payments/subscription/helpers';

const Rows = ({ subscription, user }) => {
    const { mailPlan = {}, vpnPlan = {} } = formatPlans(subscription.Plans);

    if (user.hasPaidMail && mailPlan.Name === 'visionary') {
        return (

ProtonMail plan

Visionary

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

        );
    }

    return (
        <>

ProtonMail plan

                    {user.hasPaidMail ? mailPlan.Name : c('Plan').t`Free`}

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

ProtonVPN plan

                    {user.hasPaidVpn ? vpnPlan.Name : c('Plan').t`Free`}

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

        </>
    );
};

Rows.propTypes = {
    subscription: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired
};

const SummarySection = ({ subscription, user, userSettings }) => {
    const ROLES = {
        [MEMBER_ROLE]: c('Role').t`Member`,
        [ADMIN_ROLE]: c('Role').t`Administrator`
    };
    return (

{c('Label').t`Username`}

{user.Name}

{c('Label').t`Recovery email`}

                        {userSettings.Email.Status ? c('Status').t`Active` : c('Status').t`Not set`}

                        <Link to="/settings/account">{c('Link').t`Edit`}</Link>

{c('Label').t`Two factor authentication`}

                        {userSettings['2FA'].Enabled ? c('Status').t`Enabled` : c('Status').t`Disabled`}

                        <Link to="/settings/account">{c('Link').t`Edit`}</Link>

                <Rows subscription={subscription} user={user} />
                {subscription.MaxMembers > 1 ? (

{c('Label').t`Role`}

{ROLES[user.Role]}

                ) : null}

    );
};

SummarySection.propTypes = {
    subscription: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired,
    userSettings: PropTypes.object.isRequired
};

export default SummarySection;
<commit_msg>Show recovery email if it is set (#312)<commit_after>import React from 'react';
import { c } from 'ttag';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { USER_ROLES } from 'proton-shared/lib/constants';

const { MEMBER_ROLE, ADMIN_ROLE } = USER_ROLES;

import { formatPlans } from '../payments/subscription/helpers';

const Rows = ({ subscription, user }) => {
    const { mailPlan = {}, vpnPlan = {} } = formatPlans(subscription.Plans);

    if (user.hasPaidMail && mailPlan.Name === 'visionary') {
        return (

ProtonMail plan

Visionary

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

        );
    }

    return (
        <>

ProtonMail plan

                    {user.hasPaidMail ? mailPlan.Name : c('Plan').t`Free`}

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

ProtonVPN plan

                    {user.hasPaidVpn ? vpnPlan.Name : c('Plan').t`Free`}

                    <Link to="/settings/subscription">{c('Link').t`Manage`}</Link>

        </>
    );
};

Rows.propTypes = {
    subscription: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired
};

const SummarySection = ({ subscription, user, userSettings }) => {
    const ROLES = {
        [MEMBER_ROLE]: c('Role').t`Member`,
        [ADMIN_ROLE]: c('Role').t`Administrator`
    };

    return (

{c('Label').t`Username`}

{user.Name}

{c('Label').t`Recovery email`}

{userSettings.Email.Value || c('Status').t`Not set`}

                        <Link to="/settings/account">{c('Link').t`Edit`}</Link>

{c('Label').t`Two factor authentication`}

                        {userSettings['2FA'].Enabled ? c('Status').t`Enabled` : c('Status').t`Disabled`}

                        <Link to="/settings/account">{c('Link').t`Edit`}</Link>

                <Rows subscription={subscription} user={user} />
                {subscription.MaxMembers > 1 ? (

{c('Label').t`Role`}

{ROLES[user.Role]}

                ) : null}

    );
};

SummarySection.propTypes = {
    subscription: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired,
    userSettings: PropTypes.object.isRequired
};

export default SummarySection;
<|endoftext|>