<commit_before>/*
	Playah Javascript Plugin for MetroUI
	Requires jQuery and MetroUI Bootstrap.

	Copyright (c)2015 Kekesed. All rights reserved.
	https://app.kekesed.gq/run/Playah/
*/
$.widget("kekesed.playah", {
	options: {
		theme:'blue',
		autoplay:false,
		random:false,
		loop:true,
		android_mode:true,
		playlist: [],
		header:{
			height: '150px',
			color:'darkBlue',
		},
		callback:{
			onNext:function(SongData) {},
			onPrev:function(SongData) {},
			onState:function(Status, SongData) {},
			onError:function(Err, SongData) {},
			onLoad:function() {},
		},
	},
	vars: {
		btn:{
			ply:null,
			rew:null,
			fwd:null
		},
		icn: {
			ply:null,
			pau:null
		},
		songId:0,
		state:'pause',
		kontrol: {
			img:null,
			judul:null,
			pbar:null
		},
		statis :{
			player:null,
			temp:null,
		}
	},
	_create: function() {
		if(!(window.location.host.search("sndbox.ga") || window.location.host.search("kekesed.gq"))) {
			console.info("This site uses Playah HTML5 Audio Player\nhttps://app.kekesed.gq/run/Playah");
		}
		var elemen = this.element;
		var pict = $('
', {class:'playah-picture bg-' + this.options.header.color}).css({overflow:'hidden', height: this.options.header.height});
		var pbar = $('
', {class:'playah-progressbar progress-bar no-margin bg-dark'}).progressbar({
			value:100,
			color: "bg-" + this.options.theme,
			animate:false
		});
		var konten = $('
', {class:'playah-konten bg-white padding15'});

		var kondisi = 'stop';

		// konstruk konten:
		var ply_btn = $("<button/>", {class:"large bg-" + this.options.theme + " fg-white"});
		var rew_btn = $("<button/>", {class:"fg-" + this.options.theme});
		var fwd_btn = $("<button/>", {class:"fg-" + this.options.theme});

		var ply_icn = $("", {class:"icon-play-2"}).appendTo(ply_btn);
		var rew_icn = $("",{class:"icon-previous"}).appendTo(rew_btn);
		var fwd_icn = $("", {class:"icon-next"}).appendTo(fwd_btn);
		var pau_icn = $("", {class:"icon-pause-2"});

		// Wrapper kontrol
		var ply_judul = $('
', {class:'playah-judulan text-center'});
		var ply_control = $('
', {class:'playah-control text-center margin10'});
		//create ui
			// kontrol
			rew_btn.appendTo(ply_control);
			ply_btn.appendTo(ply_control);
			fwd_btn.appendTo(ply_control);

			//Judulisasi
			ply_judul.appendTo(konten);
			// Kontrol Final
			ply_control.appendTo(konten);

		// Finalization
		pict.appendTo(elemen);
		pbar.appendTo(elemen);
		konten.appendTo(elemen);

		//Simpan ke memori
		this.vars.btn.ply = ply_btn;
		this.vars.btn.rew = rew_btn;
		this.vars.btn.fwd = fwd_btn;
		this.vars.icn.ply = ply_icn;
		this.vars.icn.pau = pau_icn;
		this.vars.kontrol.img = pict;
		this.vars.kontrol.judul = ply_judul;
		this.vars.kontrol.pbar = pbar;
		$("", {class:"place-right text-muted"}).append('Playah HTML5 Audio Player').appendTo(this.element);
		//SMART CHOOSANT Playlist:
		if(this.options.playlist.length == 0) {
			//None
			this._ganti_judul({title:'Playlist unloaded', artist:'Playah', album:'Ganteng dan Tamvan'});
			this._navRefresh();
		} else if(this.options.playlist.length > 0) {
			this._navRefresh();
		}

		//LOAD THE G*D-DAMN SONG:
		if(this.options.random) this.options.playlist = this._fliptable(this.options.playlist);
		this._play();

		if(this.options.autoplay) this._triggerplay();

		//PLAY-PAUSE:
		var Ortu = this;
		ply_btn.click(function() {
			Ortu._triggerplay();
		});

		//REWIND
		rew_btn.click(function() {
			Ortu.pref();
		});
		//FORWARD
		fwd_btn.click(function() {
			Ortu.next();
		});
		//CALLBACK:
		this.options.callback.onLoad();
	},
	_audioRefresh: function() {
		var pemuter = this.vars.statis.player;
		//RESTART
		pemuter.prop('currentTime', '0');
		if(this.vars.state == 'pause') {
			//lagi pause:
			$(this.vars.btn.ply).html('');
			this.vars.icn.ply.appendTo(this.vars.btn.ply);
			pemuter.trigger('pause');
		} else {
			//Play:
			$(this.vars.btn.ply).html('');
			this.vars.icn.pau.appendTo(this.vars.btn.ply);
			pemuter.trigger('play');
		}
	},
	next:function() {
		var Ortu = this;
		Ortu._plop();
		Ortu._play();
		Ortu._audioRefresh();
		//CALLBACK:
		this.options.callback.onNext(this.options.playlist[this.vars.songId]);
	},
	pref:function() {
		var Ortu = this;
		if(Ortu.options.android_mode && (Ortu.vars.statis.player.prop('currentTime') >= 5)) {
			//ANTI BUFFER: TAMVAN MODE
			Ortu.vars.statis.player.prop('currentTime',0);
		} else {
			Ortu._glop();
			Ortu._play();
		}
		Ortu._audioRefresh();
		this.options.callback.onPrev(this.options.playlist[this.vars.songId]);
	},
	_navRefresh: function() {
		if(this.options.playlist.length <= 1) {
			this.vars.btn.rew.attr('disabled','disabled');
			this.vars.btn.fwd.attr('disabled','disabled');
			if(this.options.playlist.length == 0) {
				this.vars.btn.ply.attr('disabled', 'disabled');
			} else {
				this.vars.btn.ply.removeAttr('disabled','disabled');
			}
		} else {
			this.vars.btn.rew.removeAttr('disabled');
			this.vars.btn.fwd.removeAttr('disabled');
			this.vars.btn.ply.removeAttr('disabled');
		}
	},
	_plop: function() {
		if(this.vars.songId >= this.options.playlist.length-1) {
			if(this.options.loop) {
				this.vars.songId = 0;
			} else {
				this.vars.songId = this.options.playlist.length-1;
			}
		} else {
			this.vars.songId += 1;
		}
	},
	_glop: function() {
		if(this.vars.songId == 0) {
			if(this.options.loop) {
				this.vars.songId = this.options.playlist.length-1;
			} else {
				this.vars.songId = 0;
			}
		} else {
			this.vars.songId -= 1;
		}
	},
	_play: function() {
		//detroy object
		if(typeof(this.vars.statis.player) != 'undefined' && this.vars.statis.player!= null)
			this.vars.statis.temp.remove();

		//geting index
		var idx = this.vars.songId;
		this._ganti_judul(this.options.playlist[idx].meta);
		var Audioer = this._audiofuck(this.options.playlist[idx].src);
		if(typeof(this.options.playlist[idx].meta.image) != "undefined" && this.options.playlist[idx].meta.image != null)
			this._imgchew(this.options.playlist[idx].meta.image);
		//appending to temp element
		var Temp = $("
", {class:'playah-temp'}).appendTo(this.element).css({display:'none'});
		this.vars.statis.temp = Temp;
		Audioer.appendTo(Temp);
		Audioer.trigger('load');
		this.vars.kontrol.pbar.progressbar('value', 0);
		var pbar =this.vars.kontrol.pbar;
		var Ortu = this;
		Audioer.bind('timeupdate', function() {
			var durasi = $(this).prop('duration');
			var cdur = $(this).prop('currentTime');
			pbar.progressbar('value', cdur/durasi*100);
		});
		Audioer.bind('ended', function() {
			Ortu.next();
		});

		this.vars.kontrol.pbar.click(function(e) {
			//SEEK:
			var x = e.pageX - $(this).offset().left;
			var persen = x / $(this).innerWidth();
			Audioer.prop('currentTime', Audioer.prop('duration') * persen);
		});
		this.vars.statis.player = Audioer;
	},
	_triggerplay:function() {
		var pemuter = this.vars.statis.player;
		//PLAY PAUSE:
		if(this.vars.state == 'pause') {
			//lagi pause:
			$(this.vars.btn.ply).html('');
			this.vars.icn.pau.appendTo(this.vars.btn.ply);
			pemuter.trigger('play');
			this.vars.state = 'play';
		} else {
			//Play:
			$(this.vars.btn.ply).html('');
			this.vars.icn.ply.appendTo(this.vars.btn.ply);
			pemuter.trigger('pause');
			this.vars.state = 'pause';
		}
		this.options.callback.onState(this.vars.state, this.options.playlist[this.vars.songId]);
	},
	_ganti_judul: function (props) {
		this.vars.kontrol.judul.html('');
		if(typeof(props.title) != 'undefined' && props.title != null)
			var Judul = $("", {class:"playah-judul"}).text(props.title);
		 else var Judul = $("", {class:"playah-judul"}).text('Untitled Song');
		Judul.appendTo(this.vars.kontrol.judul);
		this.vars.kontrol.judul.append('
');

		if(typeof(props.artist) != 'undefined' && props.artist != null) {
			var Artis = $("",{class:'playah-artist text-bold fg-' + this.options.theme}).text(props.artist);
			Artis.appendTo(this.vars.kontrol.judul);
			this.vars.kontrol.judul.append(' ');
		}
		if(typeof(props.album) != 'undefined' && props.album != null) {
			var Album = $("", {class:"playah-album"}).text(props.album);
			Album.appendTo(this.vars.kontrol.judul);
		}
	},
	_audiofuck: function(source) {
		var player = $('<audio/>', {'preload':'none'});
		var mp3 = $('<source/>', {src: source.mp3, type:'audio/mpeg'});
		mp3.appendTo(player);

		if(typeof(source.ogg) != "undefined" && source.ogg !== null ) {
			var ogg = $('<source/>', {src: source.ogg, type:'audio/ogg'});
			ogg.appendTo(player);
		}
		return player;
	},
	_imgchew: function(prop) {
		var gambar = $('', {src:prop});
		this.vars.kontrol.img.html('');
		gambar.appendTo(this.vars.kontrol.img);
	},
	_fliptable: function (array) {
		for (var i = array.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = array[i];
			array[i] = array[j];
			array[j] = temp;
		}
		return array;
	}
});<commit_msg>Playah mark<commit_after>/*
	Playah Javascript Plugin for MetroUI
	Requires jQuery and MetroUI Bootstrap.

	Copyright (c)2015 Kekesed. All rights reserved.
	https://app.kekesed.gq/run/Playah/
*/
$.widget("kekesed.playah", {
	options: {
		theme:'blue',
		autoplay:false,
		random:false,
		loop:true,
		android_mode:true,
		playlist: [],
		header:{
			height: '150px',
			color:'darkBlue',
		},
		callback:{
			onNext:function(SongData) {},
			onPrev:function(SongData) {},
			onState:function(Status, SongData) {},
			onError:function(Err, SongData) {},
			onLoad:function() {},
		},
	},
	vars: {
		btn:{
			ply:null,
			rew:null,
			fwd:null
		},
		icn: {
			ply:null,
			pau:null
		},
		songId:0,
		state:'pause',
		kontrol: {
			img:null,
			judul:null,
			pbar:null
		},
		statis :{
			player:null,
			temp:null,
		}
	},
	_create: function() {
		var elemen = this.element;
		var pict = $('
', {class:'playah-picture bg-' + this.options.header.color}).css({overflow:'hidden', height: this.options.header.height});
		var pbar = $('
', {class:'playah-progressbar progress-bar no-margin bg-dark'}).progressbar({
			value:100,
			color: "bg-" + this.options.theme,
			animate:false
		});
		var konten = $('
', {class:'playah-konten bg-white padding15'});

		var kondisi = 'stop';

		// konstruk konten:
		var ply_btn = $("<button/>", {class:"large bg-" + this.options.theme + " fg-white"});
		var rew_btn = $("<button/>", {class:"fg-" + this.options.theme});
		var fwd_btn = $("<button/>", {class:"fg-" + this.options.theme});

		var ply_icn = $("", {class:"icon-play-2"}).appendTo(ply_btn);
		var rew_icn = $("",{class:"icon-previous"}).appendTo(rew_btn);
		var fwd_icn = $("", {class:"icon-next"}).appendTo(fwd_btn);
		var pau_icn = $("", {class:"icon-pause-2"});

		// Wrapper kontrol
		var ply_judul = $('
', {class:'playah-judulan text-center'});
		var ply_control = $('
', {class:'playah-control text-center margin10'});
		//create ui
			// kontrol
			rew_btn.appendTo(ply_control);
			ply_btn.appendTo(ply_control);
			fwd_btn.appendTo(ply_control);

			//Judulisasi
			ply_judul.appendTo(konten);
			// Kontrol Final
			ply_control.appendTo(konten);

		// Finalization
		pict.appendTo(elemen);
		pbar.appendTo(elemen);
		konten.appendTo(elemen);

		//Simpan ke memori
		this.vars.btn.ply = ply_btn;
		this.vars.btn.rew = rew_btn;
		this.vars.btn.fwd = fwd_btn;
		this.vars.icn.ply = ply_icn;
		this.vars.icn.pau = pau_icn;
		this.vars.kontrol.img = pict;
		this.vars.kontrol.judul = ply_judul;
		this.vars.kontrol.pbar = pbar;
		//SMART CHOOSANT Playlist:
		if(this.options.playlist.length == 0) {
			//None
			this._ganti_judul({title:'Playlist unloaded', artist:'Playah', album:'Ganteng dan Tamvan'});
			this._navRefresh();
		} else if(this.options.playlist.length > 0) {
			this._navRefresh();
		}

		//LOAD THE G*D-DAMN SONG:
		if(this.options.random) this.options.playlist = this._fliptable(this.options.playlist);
		this._play();

		if(this.options.autoplay) this._triggerplay();

		//PLAY-PAUSE:
		var Ortu = this;
		ply_btn.click(function() {
			Ortu._triggerplay();
		});

		//REWIND
		rew_btn.click(function() {
			Ortu.pref();
		});
		//FORWARD
		fwd_btn.click(function() {
			Ortu.next();
		});
		//CALLBACK:
		this.options.callback.onLoad();
	},
	_audioRefresh: function() {
		var pemuter = this.vars.statis.player;
		//RESTART
		pemuter.prop('currentTime', '0');
		if(this.vars.state == 'pause') {
			//lagi pause:
			$(this.vars.btn.ply).html('');
			this.vars.icn.ply.appendTo(this.vars.btn.ply);
			pemuter.trigger('pause');
		} else {
			//Play:
			$(this.vars.btn.ply).html('');
			this.vars.icn.pau.appendTo(this.vars.btn.ply);
			pemuter.trigger('play');
		}
	},
	next:function() {
		var Ortu = this;
		Ortu._plop();
		Ortu._play();
		Ortu._audioRefresh();
		//CALLBACK:
		this.options.callback.onNext(this.options.playlist[this.vars.songId]);
	},
	pref:function() {
		var Ortu = this;
		if(Ortu.options.android_mode && (Ortu.vars.statis.player.prop('currentTime') >= 5)) {
			//ANTI BUFFER: TAMVAN MODE
			Ortu.vars.statis.player.prop('currentTime',0);
		} else {
			Ortu._glop();
			Ortu._play();
		}
		Ortu._audioRefresh();
		this.options.callback.onPrev(this.options.playlist[this.vars.songId]);
	},
	_navRefresh: function() {
		if(this.options.playlist.length <= 1) {
			this.vars.btn.rew.attr('disabled','disabled');
			this.vars.btn.fwd.attr('disabled','disabled');
			if(this.options.playlist.length == 0) {
				this.vars.btn.ply.attr('disabled', 'disabled');
			} else {
				this.vars.btn.ply.removeAttr('disabled','disabled');
			}
		} else {
			this.vars.btn.rew.removeAttr('disabled');
			this.vars.btn.fwd.removeAttr('disabled');
			this.vars.btn.ply.removeAttr('disabled');
		}
	},
	_plop: function() {
		if(this.vars.songId >= this.options.playlist.length-1) {
			if(this.options.loop) {
				this.vars.songId = 0;
			} else {
				this.vars.songId = this.options.playlist.length-1;
			}
		} else {
			this.vars.songId += 1;
		}
	},
	_glop: function() {
		if(this.vars.songId == 0) {
			if(this.options.loop) {
				this.vars.songId = this.options.playlist.length-1;
			} else {
				this.vars.songId = 0;
			}
		} else {
			this.vars.songId -= 1;
		}
	},
	_play: function() {
		//detroy object
		if(typeof(this.vars.statis.player) != 'undefined' && this.vars.statis.player!= null)
			this.vars.statis.temp.remove();

		//geting index
		var idx = this.vars.songId;
		this._ganti_judul(this.options.playlist[idx].meta);
		var Audioer = this._audiofuck(this.options.playlist[idx].src);
		if(typeof(this.options.playlist[idx].meta.image) != "undefined" && this.options.playlist[idx].meta.image != null)
			this._imgchew(this.options.playlist[idx].meta.image);
		//appending to temp element
		var Temp = $("
", {class:'playah-temp'}).appendTo(this.element).css({display:'none'});
		this.vars.statis.temp = Temp;
		Audioer.appendTo(Temp);
		Audioer.trigger('load');
		this.vars.kontrol.pbar.progressbar('value', 0);
		var pbar =this.vars.kontrol.pbar;
		var Ortu = this;
		Audioer.bind('timeupdate', function() {
			var durasi = $(this).prop('duration');
			var cdur = $(this).prop('currentTime');
			pbar.progressbar('value', cdur/durasi*100);
		});
		Audioer.bind('ended', function() {
			Ortu.next();
		});

		this.vars.kontrol.pbar.click(function(e) {
			//SEEK:
			var x = e.pageX - $(this).offset().left;
			var persen = x / $(this).innerWidth();
			Audioer.prop('currentTime', Audioer.prop('duration') * persen);
		});
		this.vars.statis.player = Audioer;
	},
	_triggerplay:function() {
		var pemuter = this.vars.statis.player;
		//PLAY PAUSE:
		if(this.vars.state == 'pause') {
			//lagi pause:
			$(this.vars.btn.ply).html('');
			this.vars.icn.pau.appendTo(this.vars.btn.ply);
			pemuter.trigger('play');
			this.vars.state = 'play';
		} else {
			//Play:
			$(this.vars.btn.ply).html('');
			this.vars.icn.ply.appendTo(this.vars.btn.ply);
			pemuter.trigger('pause');
			this.vars.state = 'pause';
		}
		this.options.callback.onState(this.vars.state, this.options.playlist[this.vars.songId]);
	},
	_ganti_judul: function (props) {
		this.vars.kontrol.judul.html('');
		if(typeof(props.title) != 'undefined' && props.title != null)
			var Judul = $("", {class:"playah-judul"}).text(props.title);
		 else var Judul = $("", {class:"playah-judul"}).text('Untitled Song');
		Judul.appendTo(this.vars.kontrol.judul);
		this.vars.kontrol.judul.append('
');

		if(typeof(props.artist) != 'undefined' && props.artist != null) {
			var Artis = $("",{class:'playah-artist text-bold fg-' + this.options.theme}).text(props.artist);
			Artis.appendTo(this.vars.kontrol.judul);
			this.vars.kontrol.judul.append(' ');
		}
		if(typeof(props.album) != 'undefined' && props.album != null) {
			var Album = $("", {class:"playah-album"}).text(props.album);
			Album.appendTo(this.vars.kontrol.judul);
		}
	},
	_audiofuck: function(source) {
		var player = $('<audio/>', {'preload':'none'});
		var mp3 = $('<source/>', {src: source.mp3, type:'audio/mpeg'});
		mp3.appendTo(player);

		if(typeof(source.ogg) != "undefined" && source.ogg !== null ) {
			var ogg = $('<source/>', {src: source.ogg, type:'audio/ogg'});
			ogg.appendTo(player);
		}
		return player;
	},
	_imgchew: function(prop) {
		var gambar = $('', {src:prop});
		this.vars.kontrol.img.html('');
		gambar.appendTo(this.vars.kontrol.img);
	},
	_fliptable: function (array) {
		for (var i = array.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = array[i];
			array[i] = array[j];
			array[j] = temp;
		}
		return array;
	}
});<|endoftext|>


<commit_before>'use strict';

var allUsers = [];
// var winnerCircle = [];
// var winnerScore = [];

function myEpiphany (a,b) {
  return b.score - a.score;
}

function retrieveUsers() {
  var retrievedUsers = localStorage.getItem('userData');
  allUsers = JSON.parse(retrievedUsers);
}

// function winners() {
//   for (var i = 0; i < allUsers.length; i++) {
//     winnerScore.push(allUsers[i].score);
//   }
//   winnerScore.sort();
//   for (var j = 0; j < winnerScore.length; j++) {
//     console.log(winnerScore[j]);
//     for (var k = 0; k < allUsers.length; k++) {
//       if (winnerScore[j] === allUsers[k].score) {
//         winnerCircle.push(allUsers[k]);

//       }
//     }
//   }
// }

// Run initial functions to populate user data
retrieveUsers();
// winners();
allUsers.sort(myEpiphany);

//Display Results in Table
var tableName = document.getElementById('table-name');
var tableResults = document.getElementById('table-points');

function onFinal() {
  for (var i = 0; i < allUsers.length; i++) {
    var winnerName = document.createElement('th');
    winnerName.textContent = allUsers[i].name;
    tableName.appendChild(winnerName);

    var winnerPoints = document.createElement('td');
    winnerPoints.textContent = allUsers[i].score;
    tableResults.appendChild(winnerPoints);
  }
}

onFinal();<commit_msg>results diplayed from high score to low<commit_after>'use strict';

var allUsers = [];

function myEpiphany (a,b) {
  return b.score - a.score;
}

function retrieveUsers() {
  var retrievedUsers = localStorage.getItem('userData');
  allUsers = JSON.parse(retrievedUsers);
}

// Run initial functions to populate user data
retrieveUsers();

allUsers.sort(myEpiphany);

//Display Results in Table
var tableName = document.getElementById('table-name');
var tableResults = document.getElementById('table-points');

function onFinal() {
  for (var i = 0; i < allUsers.length; i++) {
    var winnerName = document.createElement('th');
    winnerName.textContent = allUsers[i].name;
    tableName.appendChild(winnerName);

    var winnerPoints = document.createElement('td');
    winnerPoints.textContent = allUsers[i].score;
    tableResults.appendChild(winnerPoints);
  }
}

onFinal();<|endoftext|>


<commit_before>angular.module('replyFactory', ['firebase'])

.factory('Replies', ['$firebaseArray', function ($firebaseArray) {

  var repliesFactory = {};

  // Gets the replies for the current message from the db.
  repliesFactory.getReplies = function (index, roomname, org) {
    var url = 'https://bizgramer.firebaseio.com/'+org+'/rooms/' + roomname + '/' + index + '/replies';
    var ref = new Firebase(url);
    var replies = $firebaseArray(ref);
    return replies;
  };

  // Adds the reply message to replies of the current message in the db.
  repliesFactory.addReply = function (username, profileImg, text, index, roomname, org) {
    var url = 'https://bizgramer.firebaseio.com/'+org+'/rooms/' + roomname + '/' + index + '/replies';
    console.log('url ', url);
    var ref = new Firebase(url);
    var replies = $firebaseArray(ref);
    replies.$add({
      username: username,
      img: profileImg,
      text: text,
      createdAt: Firebase.ServerValue.TIMESTAMP
    });
  };

  // Gets the reply messages for the current message from the db.
  repliesFactory.getVisualReplies = function (index, org) {
    var ref = new Firebase('https://bizgramer.firebaseio.com/'+org+'/visualizations/messages/' + index);
    var replyRef = ref.child('replies');
    var replies = $firebaseArray(replyRef);
    return replies;
  };

  // Adds a reply to the current message in the db.
  repliesFactory.addVisualReply = function (username, profileImg, text, index, org) {
    var ref = new Firebase('https://bizgramer.firebaseio.com/'+org+'/visualizations/messages/' + index);
    var replyRef = ref.child('replies');
    var replies = $firebaseArray(replyRef);
    replies.$add({
      username: username,
      img: profileImg,
      text: text,
      createdAt: Firebase.ServerValue.TIMESTAMP
    });
  };

  return repliesFactory;
}]);

<commit_msg>(fix) reply message bug<commit_after>angular.module('replyFactory', ['firebase'])

.factory('Replies', ['$firebaseArray', function ($firebaseArray, $stateParams) {

  var repliesFactory = {};

  // Gets the replies for the current message from the db.
  repliesFactory.getReplies = function (index, roomname, org) {
    var url = 'https://bizgramer.firebaseio.com/'+org+'/rooms/' + roomname + '/' + index + '/replies';
    var ref = new Firebase(url);
    var replies = $firebaseArray(ref);
    return replies;
  };

  // Adds the reply message to replies of the current message in the db.
  repliesFactory.addReply = function (username, profileImg, text, index, roomname, org) {
    var url = 'https://bizgramer.firebaseio.com/'+org+'/rooms/' + roomname + '/' + index + '/replies';
    console.log($stateParams)
    // console.log(roomname);
    console.log('url ', url);
    if (org && roomname && index) {
      var ref = new Firebase(url);
      var replies = $firebaseArray(ref);
      replies.$add({
        username: username,
        img: profileImg,
        text: text,
        createdAt: Firebase.ServerValue.TIMESTAMP
      });
    } else {
      console.log('not posting a reply because mising parameter(s)');
    }
  };

  // Gets the reply messages for the current message from the db.
  repliesFactory.getVisualReplies = function (index, org) {
    var ref = new Firebase('https://bizgramer.firebaseio.com/'+org+'/visualizations/messages/' + index);
    var replyRef = ref.child('replies');
    var replies = $firebaseArray(replyRef);
    return replies;
  };

  // Adds a reply to the current message in the db.
  repliesFactory.addVisualReply = function (username, profileImg, text, index, org) {
    var ref = new Firebase('https://bizgramer.firebaseio.com/'+org+'/visualizations/messages/' + index);
    var replyRef = ref.child('replies');
    var replies = $firebaseArray(replyRef);
    replies.$add({
      username: username,
      img: profileImg,
      text: text,
      createdAt: Firebase.ServerValue.TIMESTAMP
    });
  };

  return repliesFactory;
}]);

<|endoftext|>


<commit_before>import angular from 'angular';

const template = `

    <ui-select
      ng-model="vm.selected"
      ng-change="vm.modelChanged()"
      ng-disabled="vm.ngDisabled"
      theme="select2"
      class="form-control"
      search-enabled="vm.searchEnabled">
      <ui-select-match placeholder="{{ vm.placeholder }}">
        {{ vm.getMappedItem($item || $select.selected) }}
      </ui-select-match>
      <ui-select-choices
        repeat="item in vm.items | filter: $select.search"
        refresh="vm.searchItems()"
        refresh-delay="vm.refreshDelay || 200"
        group-by="vm.groupBy">

      </ui-select-choices>
    </ui-select>

      <button
        title="Adds all available options"
        ng-click="vm.selectAll()"
        class="btn btn-default"
        type="button"
        style="height: calc(100% + 14px)">

      </button>
      <button
        title="Removes all options"
        ng-click="vm.deselectAll()"
        class="btn btn-default"
        type="button"
        style="height: calc(100% + 14px)">

      </button>

`;

export default function scSelect() {

  'ngInject';

  return {
    restrict: 'E',
    require: 'ngModel',
    template: '

',
    controller: function($attrs, $element, $compile, $parse, $scope, $q, $timeout, scSelectParser) {

      'ngInject';

      const vm = this;
      const loadingDelay = angular.isDefined(vm.loadingDelay) ? vm.loadingDelay : 0;
      vm.currentPage = 1;
      vm.canToggleAll = vm.multiple && !vm.pageLimit;

      const selectElm = angular.element(template);
      if (vm.multiple) {
        selectElm.find('ui-select').attr('multiple', 'multiple');
      }
      $compile(selectElm)($scope);
      $element.append(selectElm);

      vm.items = [];

      let oldSearchText;

      vm.searchItems = function() {
        if (vm.uiSelectCtrl) {
          //reset page if the search text has changed
          if (oldSearchText !== vm.uiSelectCtrl.search) {
            vm.currentPage = 1;
          }

          oldSearchText = vm.uiSelectCtrl.search;
          const setLoadingTimeout = $timeout(() => {
            vm.loading = true;
            vm.items = [];
          }, loadingDelay);

          return $q.when(vm.parsedOptions.source(vm.optionScope, {
            page: vm.currentPage,
            searchText: vm.uiSelectCtrl.search
          })).then((items) => {
            vm.items = items;
          }).finally(() => {
            vm.loading = false;
            $timeout.cancel(setLoadingTimeout);
          });

        }
      };

      vm.changePage = function(newPage) {
        vm.currentPage = newPage;
        vm.searchItems();
      };

      vm.parsedOptions = scSelectParser.parse($attrs.scOptions);

      vm.setOptionScope = function(scope) {
        vm.optionScope = scope; //expose for testing
        vm.changePage(vm.currentPage);
      };

      vm.setNgModelCtrl = function(ngModelCtrl) {
        vm.ngModelCtrl = ngModelCtrl;

        ngModelCtrl.$render = function() {
          if (!ngModelCtrl.$viewValue) {
            return;
          }
          //var cc = vm.multiple ? ngModelCtrl.$viewValue : vm.items;
          var items;
          if (vm.multiple) {
            items = ngModelCtrl.$viewValue;
          } else {
            items = vm.items;
          }
          var matchingItems = [];
          if (angular.isArray(items)) {
            matchingItems = items.filter((item) => {
              var itemValue;
              if (!angular.isArray(item)) {
                itemValue = item;
              } else {
                itemValue = vm.parsedOptions.modelMapper({
                  [vm.parsedOptions.itemName]: item
                });
              }
              if (vm.multiple) {
                var found = false;
                if (typeof ngModelCtrl.$viewValue === 'object') {

                  angular.forEach(ngModelCtrl.$viewValue, function(val) {
                    if (typeof val === 'string') {
                      if (val.indexOf(itemValue) > -1) {
                        found = true;
                      }
                    }
                    if (val && itemValue && val.id === itemValue.id) {
                      found = true;
                    }
                  });
                } else if (ngModelCtrl.$viewValue.indexOf(itemValue) > -1) {
                  found = true;
                }
                return found;
              } else {
                if (typeof itemValue === 'object') {
                  return ngModelCtrl.$viewValue === itemValue.id || ngModelCtrl.$viewValue === itemValue.label || ngModelCtrl.$viewValue.id === itemValue.id;
                }
                return ngModelCtrl.$viewValue === itemValue;
              }
            });
          }

          if (matchingItems.length === 0 && typeof ngModelCtrl.$viewValue === 'object') {
            matchingItems = [ngModelCtrl.$viewValue];
          }

          if (vm.multiple) {
            vm.selected = matchingItems;
          } else {
            vm.selected = matchingItems[0];
          }
        };

        //Ensure items array has been populated first - as it uses $q.when it will be after the first digest
        $timeout(function() {
          vm.ngModelCtrl.$render();
        });

      };

      vm.modelChanged = function() {
        let modelValue;
        if (vm.multiple) {
          modelValue = vm.selected.map((item) => {
            return vm.parsedOptions.modelMapper({
              [vm.parsedOptions.itemName]: item
            });
          });
        } else {
          modelValue = vm.parsedOptions.modelMapper({
            [vm.parsedOptions.itemName]: vm.selected
          });
        }
        vm.ngModelCtrl.$setViewValue(modelValue);
      };

      vm.getMappedItem = function(localItem) {
        return vm.parsedOptions.viewMapper({
          [vm.parsedOptions.itemName]: localItem
        });
      };

      vm.selectAll = function() {
        vm.selected = vm.items;
        vm.modelChanged();
      };

      vm.deselectAll = function() {
        vm.selected = [];
        vm.modelChanged();
      };

      $scope.$watch(function() {
        return vm.ngModelCtrl.$modelValue;
      }, function(selected) {
        if (!selected) {
          vm.selected = vm.multiple ? [] : '';
        }
      }, true);

      if (!angular.isDefined(vm.pageLimit)) {
        $scope.$watch(function() {
          return vm.parsedOptions.source(vm.optionScope);
        }, function(items) {
          if (items) {
            vm.items = items;
          }
        });
      }

      if (angular.isUndefined(vm.groupBy) && angular.isDefined($attrs.groupBy)) {
        const getGroupBy = $parse($attrs.groupBy);
        vm.groupBy = function(item) {
          return getGroupBy(item);
        };
      }

    },
    controllerAs: 'vm',
    bindToController: true,
    scope: {
      pageLimit: '=',
      totalItems: '=',
      placeholder: '@',
      multiple: '=?',
      ngDisabled: '=',
      searchEnabled: '=',
      refreshDelay: '=',
      loadingDelay: '=',
      groupBy: '='
    },
    link: (scope, elm, attrs, ngModelCtrl) => {
      scope.vm.setNgModelCtrl(ngModelCtrl);
    }
  };

}
<commit_msg>Extract in-line scSelect controller<commit_after>import angular from 'angular';

const template = `

    <ui-select
      ng-model="vm.selected"
      ng-change="vm.modelChanged()"
      ng-disabled="vm.ngDisabled"
      theme="select2"
      class="form-control"
      search-enabled="vm.searchEnabled">
      <ui-select-match placeholder="{{ vm.placeholder }}">
        {{ vm.getMappedItem($item || $select.selected) }}
      </ui-select-match>
      <ui-select-choices
        repeat="item in vm.items | filter: $select.search"
        refresh="vm.searchItems()"
        refresh-delay="vm.refreshDelay || 200"
        group-by="vm.groupBy">

      </ui-select-choices>
    </ui-select>

      <button
        title="Adds all available options"
        ng-click="vm.selectAll()"
        class="btn btn-default"
        type="button"
        style="height: calc(100% + 14px)">

      </button>
      <button
        title="Removes all options"
        ng-click="vm.deselectAll()"
        class="btn btn-default"
        type="button"
        style="height: calc(100% + 14px)">

      </button>

`;

export default function scSelect() {

  'ngInject';

  return {
    restrict: 'E',
    require: 'ngModel',
    template: '

',
    controller: controller,
    controllerAs: 'vm',
    bindToController: true,
    scope: {
      pageLimit: '=',
      totalItems: '=',
      placeholder: '@',
      multiple: '=?',
      ngDisabled: '=',
      searchEnabled: '=',
      refreshDelay: '=',
      loadingDelay: '=',
      groupBy: '='
    },
    link: (scope, elm, attrs, ngModelCtrl) => {
      scope.vm.setNgModelCtrl(ngModelCtrl);
    }
  };

  function controller($attrs, $element, $compile, $parse, $scope, $q, $timeout, scSelectParser) {

    'ngInject';

    const vm = this;
    const loadingDelay = angular.isDefined(vm.loadingDelay) ? vm.loadingDelay : 0;
    vm.currentPage = 1;
    vm.canToggleAll = vm.multiple && !vm.pageLimit;

    const selectElm = angular.element(template);
    if (vm.multiple) {
      selectElm.find('ui-select').attr('multiple', 'multiple');
    }
    $compile(selectElm)($scope);
    $element.append(selectElm);

    vm.items = [];

    let oldSearchText;

    vm.searchItems = function() {
      if (vm.uiSelectCtrl) {
        //reset page if the search text has changed
        if (oldSearchText !== vm.uiSelectCtrl.search) {
          vm.currentPage = 1;
        }

        oldSearchText = vm.uiSelectCtrl.search;
        const setLoadingTimeout = $timeout(() => {
          vm.loading = true;
          vm.items = [];
        }, loadingDelay);

        return $q.when(vm.parsedOptions.source(vm.optionScope, {
          page: vm.currentPage,
          searchText: vm.uiSelectCtrl.search
        })).then((items) => {
          vm.items = items;
        }).finally(() => {
          vm.loading = false;
          $timeout.cancel(setLoadingTimeout);
        });

      }
    };

    vm.changePage = function(newPage) {
      vm.currentPage = newPage;
      vm.searchItems();
    };

    vm.parsedOptions = scSelectParser.parse($attrs.scOptions);

    vm.setOptionScope = function(scope) {
      vm.optionScope = scope; //expose for testing
      vm.changePage(vm.currentPage);
    };

    vm.setNgModelCtrl = function(ngModelCtrl) {
      vm.ngModelCtrl = ngModelCtrl;

      ngModelCtrl.$render = function() {
        if (!ngModelCtrl.$viewValue) {
          return;
        }
        //var cc = vm.multiple ? ngModelCtrl.$viewValue : vm.items;
        var items;
        if (vm.multiple) {
          items = ngModelCtrl.$viewValue;
        } else {
          items = vm.items;
        }
        var matchingItems = [];
        if (angular.isArray(items)) {
          matchingItems = items.filter((item) => {
            var itemValue;
            if (!angular.isArray(item)) {
              itemValue = item;
            } else {
              itemValue = vm.parsedOptions.modelMapper({
                [vm.parsedOptions.itemName]: item
              });
            }
            if (vm.multiple) {
              var found = false;
              if (typeof ngModelCtrl.$viewValue === 'object') {

                angular.forEach(ngModelCtrl.$viewValue, function(val) {
                  if (typeof val === 'string') {
                    if (val.indexOf(itemValue) > -1) {
                      found = true;
                    }
                  }
                  if (val && itemValue && val.id === itemValue.id) {
                    found = true;
                  }
                });
              } else if (ngModelCtrl.$viewValue.indexOf(itemValue) > -1) {
                found = true;
              }
              return found;
            } else {
              if (typeof itemValue === 'object') {
                return ngModelCtrl.$viewValue === itemValue.id || ngModelCtrl.$viewValue === itemValue.label || ngModelCtrl.$viewValue.id === itemValue.id;
              }
              return ngModelCtrl.$viewValue === itemValue;
            }
          });
        }

        if (matchingItems.length === 0 && typeof ngModelCtrl.$viewValue === 'object') {
          matchingItems = [ngModelCtrl.$viewValue];
        }

        if (vm.multiple) {
          vm.selected = matchingItems;
        } else {
          vm.selected = matchingItems[0];
        }
      };

      //Ensure items array has been populated first - as it uses $q.when it will be after the first digest
      $timeout(function() {
        vm.ngModelCtrl.$render();
      });

    };

    vm.modelChanged = function() {
      let modelValue;
      if (vm.multiple) {
        modelValue = vm.selected.map((item) => {
          return vm.parsedOptions.modelMapper({
            [vm.parsedOptions.itemName]: item
          });
        });
      } else {
        modelValue = vm.parsedOptions.modelMapper({
          [vm.parsedOptions.itemName]: vm.selected
        });
      }
      vm.ngModelCtrl.$setViewValue(modelValue);
    };

    vm.getMappedItem = function(localItem) {
      return vm.parsedOptions.viewMapper({
        [vm.parsedOptions.itemName]: localItem
      });
    };

    vm.selectAll = function() {
      vm.selected = vm.items;
      vm.modelChanged();
    };

    vm.deselectAll = function() {
      vm.selected = [];
      vm.modelChanged();
    };

    $scope.$watch(function() {
      return vm.ngModelCtrl.$modelValue;
    }, function(selected) {
      if (!selected) {
        vm.selected = vm.multiple ? [] : '';
      }
    }, true);

    if (!angular.isDefined(vm.pageLimit)) {
      $scope.$watch(function() {
        return vm.parsedOptions.source(vm.optionScope);
      }, function(items) {
        if (items) {
          vm.items = items;
        }
      });
    }

    if (angular.isUndefined(vm.groupBy) && angular.isDefined($attrs.groupBy)) {
      const getGroupBy = $parse($attrs.groupBy);
      vm.groupBy = function(item) {
        return getGroupBy(item);
      };
    }

  }

}
<|endoftext|>


<commit_before>var typeahead_helper = (function () {

var exports = {};

// Loosely based on Bootstrap's default highlighter, but with escaping added.
exports.highlight_with_escaping = function (query, item) {
    // query: The text currently in the searchbox
    // item: The string we are trying to appropriately highlight
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(' + query + ')', 'ig');
    // The result of the split will include the query term, because our regex
    // has parens in it.
    // (as per https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split)
    // However, "not all browsers support this capability", so this is a place to look
    // if we have an issue here in, e.g. IE.
    var pieces = item.split(regex);
    // We need to assemble this manually (as opposed to doing 'join') because we need to
    // (1) escape all the pieces and (2) the regex is case-insensitive, and we need
    // to know the case of the content we're replacing (you can't just use a bolded
    // version of 'query')
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_with_escaping_and_regex = function (regex, item) {
    var pieces = item.split(regex);
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_query_in_phrase = function (query, phrase) {
    var i;
    query = query.toLowerCase();
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(^' + query + ')', 'ig');

    var result = "";
    var parts = phrase.split(' ');
    for (i = 0; i < parts.length; i += 1) {
        if (i > 0) {
            result += " ";
        }
        result += exports.highlight_with_escaping_and_regex(regex, parts[i]);
    }
    return result;
};

exports.render_person = function (person) {
    if (person.special_item_text) {
        return person.special_item_text;
    }
    return person.full_name + " <" + person.email + ">";
};

exports.render_stream = function (token, stream) {
    var desc = stream.description;
    var short_desc = desc.substring(0, 35);

    if (desc === short_desc) {
        desc = exports.highlight_with_escaping(token, desc);
    } else {
        desc = exports.highlight_with_escaping(token, short_desc) + "...";
    }

    var name = exports.highlight_with_escaping(token, stream.name);

    return name + '  ' + desc + '';
};

function prefix_sort(query, objs, get_item) {
    // Based on Bootstrap typeahead's default sorter, but taking into
    // account case sensitivity on "begins with"
    var beginswithCaseSensitive = [];
    var beginswithCaseInsensitive = [];
    var noMatch = [];

    var obj = objs.shift();
    while (obj) {
        var item;
        if (get_item) {
            item = get_item(obj);
        } else {
            item = obj;
        }
        if (item.indexOf(query) === 0) {
            beginswithCaseSensitive.push(obj);
        } else if (item.toLowerCase().indexOf(query.toLowerCase()) === 0) {
            beginswithCaseInsensitive.push(obj);
        } else {
            noMatch.push(obj);
        }
        obj = objs.shift();
    }
    return { matches: beginswithCaseSensitive.concat(beginswithCaseInsensitive),
             rest:    noMatch };

}

function split_by_subscribers(people, current_stream) {
    var subscribers = [];
    var non_subscribers = [];

    if (!stream_data.get_sub(current_stream)) {
        // If there is no stream specified, everyone is considered as a subscriber.
        return {subs: people, non_subs: []};
    }

    _.each(people, function (person) {
        if (person.email === "all" || person.email === "everyone") {
            subscribers.push(person);
        } else if (stream_data.user_is_subscribed(current_stream, person.email)) {
            subscribers.push(person);
        } else {
            non_subscribers.push(person);
        }
    });

    return {subs: subscribers, non_subs: non_subscribers};
}

exports.sorter = function (query, objs, get_item) {
   var results = prefix_sort(query, objs, get_item);
   return results.matches.concat(results.rest);
};

exports.compare_by_pms = function (user_a, user_b) {
    var count_a = people.get_recipient_count(user_a);
    var count_b = people.get_recipient_count(user_b);

    if (count_a > count_b) {
        return -1;
    } else if (count_a < count_b) {
        return 1;
    }

    if (!user_a.is_bot && user_b.is_bot) {
        return -1;
    } else if (user_a.is_bot && !user_b.is_bot) {
        return 1;
    }

    // We use alpha sort as a tiebreaker, which might be helpful for
    // new users.
    if (user_a.full_name < user_b.full_name) {
        return -1;
    } else if (user_a === user_b) {
        return 0;
    }
    return 1;
};

exports.sort_for_at_mentioning = function (objs, current_stream) {
    var objs_split = split_by_subscribers(objs, current_stream);

    var subs_sorted = objs_split.subs.sort(exports.compare_by_pms);
    var non_subs_sorted = objs_split.non_subs.sort(exports.compare_by_pms);
    return subs_sorted.concat(non_subs_sorted);
};

exports.sort_recipients = function (matches, query, current_stream) {
    var name_results =  prefix_sort(query, matches, function (x) { return x.full_name; });
    var email_results = prefix_sort(query, name_results.rest, function (x) { return x.email; });

    var matches_sorted = exports.sort_for_at_mentioning(
        name_results.matches.concat(email_results.matches),
        current_stream
    );
    var rest_sorted = exports.sort_for_at_mentioning(
        email_results.rest,
        current_stream
    );
    return matches_sorted.concat(rest_sorted);
};

exports.sort_emojis = function (matches, query) {
    // TODO: sort by category in v2
    var results = prefix_sort(query, matches, function (x) { return x.emoji_name; });
    return results.matches.concat(results.rest);
};

exports.compare_by_sub_count = function (stream_a, stream_b) {
    return stream_a.subscribers.num_items() < stream_b.subscribers.num_items();
};

exports.sort_streams = function (matches, query) {
    var name_results = prefix_sort(query, matches, function (x) { return x.name; });
    var desc_results
        = prefix_sort(query, name_results.rest, function (x) { return x.description; });

    // Streams that start with the query.
    name_results.matches = name_results.matches.sort(exports.compare_by_sub_count);
    // Streams with descriptions that start with the query.
    desc_results.matches = desc_results.matches.sort(exports.compare_by_sub_count);
    // Streams with names and descriptions that don't start with the query.
    desc_results.rest = desc_results.rest.sort(exports.compare_by_sub_count);

    return name_results.matches.concat(desc_results.matches.concat(desc_results.rest));
};

exports.sort_recipientbox_typeahead = function (query, matches, current_stream) {
    // input_text may be one or more pm recipients
    var cleaned = composebox_typeahead.get_cleaned_pm_recipients(query);
    query = cleaned[cleaned.length - 1];
    return exports.sort_recipients(matches, query, current_stream);
};

return exports;

}());
if (typeof module !== 'undefined') {
    module.exports = typeahead_helper;
}
<commit_msg>refactor: Rename fields for split_by_subscribers().<commit_after>var typeahead_helper = (function () {

var exports = {};

// Loosely based on Bootstrap's default highlighter, but with escaping added.
exports.highlight_with_escaping = function (query, item) {
    // query: The text currently in the searchbox
    // item: The string we are trying to appropriately highlight
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(' + query + ')', 'ig');
    // The result of the split will include the query term, because our regex
    // has parens in it.
    // (as per https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split)
    // However, "not all browsers support this capability", so this is a place to look
    // if we have an issue here in, e.g. IE.
    var pieces = item.split(regex);
    // We need to assemble this manually (as opposed to doing 'join') because we need to
    // (1) escape all the pieces and (2) the regex is case-insensitive, and we need
    // to know the case of the content we're replacing (you can't just use a bolded
    // version of 'query')
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_with_escaping_and_regex = function (regex, item) {
    var pieces = item.split(regex);
    var result = "";
    _.each(pieces, function (piece) {
        if (piece.match(regex)) {
            result += "" + Handlebars.Utils.escapeExpression(piece) + "";
        } else {
            result += Handlebars.Utils.escapeExpression(piece);
        }
    });
    return result;
};

exports.highlight_query_in_phrase = function (query, phrase) {
    var i;
    query = query.toLowerCase();
    query = query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
    var regex = new RegExp('(^' + query + ')', 'ig');

    var result = "";
    var parts = phrase.split(' ');
    for (i = 0; i < parts.length; i += 1) {
        if (i > 0) {
            result += " ";
        }
        result += exports.highlight_with_escaping_and_regex(regex, parts[i]);
    }
    return result;
};

exports.render_person = function (person) {
    if (person.special_item_text) {
        return person.special_item_text;
    }
    return person.full_name + " <" + person.email + ">";
};

exports.render_stream = function (token, stream) {
    var desc = stream.description;
    var short_desc = desc.substring(0, 35);

    if (desc === short_desc) {
        desc = exports.highlight_with_escaping(token, desc);
    } else {
        desc = exports.highlight_with_escaping(token, short_desc) + "...";
    }

    var name = exports.highlight_with_escaping(token, stream.name);

    return name + '  ' + desc + '';
};

function prefix_sort(query, objs, get_item) {
    // Based on Bootstrap typeahead's default sorter, but taking into
    // account case sensitivity on "begins with"
    var beginswithCaseSensitive = [];
    var beginswithCaseInsensitive = [];
    var noMatch = [];

    var obj = objs.shift();
    while (obj) {
        var item;
        if (get_item) {
            item = get_item(obj);
        } else {
            item = obj;
        }
        if (item.indexOf(query) === 0) {
            beginswithCaseSensitive.push(obj);
        } else if (item.toLowerCase().indexOf(query.toLowerCase()) === 0) {
            beginswithCaseInsensitive.push(obj);
        } else {
            noMatch.push(obj);
        }
        obj = objs.shift();
    }
    return { matches: beginswithCaseSensitive.concat(beginswithCaseInsensitive),
             rest:    noMatch };

}

function split_by_subscribers(people, current_stream) {
    var subscribers = [];
    var non_subscribers = [];

    if (!stream_data.get_sub(current_stream)) {
        // If there is no stream specified, everyone is considered as a subscriber.
        return {subscribers: people, non_subscribers: []};
    }

    _.each(people, function (person) {
        if (person.email === "all" || person.email === "everyone") {
            subscribers.push(person);
        } else if (stream_data.user_is_subscribed(current_stream, person.email)) {
            subscribers.push(person);
        } else {
            non_subscribers.push(person);
        }
    });

    return {subscribers: subscribers, non_subscribers: non_subscribers};
}

exports.sorter = function (query, objs, get_item) {
   var results = prefix_sort(query, objs, get_item);
   return results.matches.concat(results.rest);
};

exports.compare_by_pms = function (user_a, user_b) {
    var count_a = people.get_recipient_count(user_a);
    var count_b = people.get_recipient_count(user_b);

    if (count_a > count_b) {
        return -1;
    } else if (count_a < count_b) {
        return 1;
    }

    if (!user_a.is_bot && user_b.is_bot) {
        return -1;
    } else if (user_a.is_bot && !user_b.is_bot) {
        return 1;
    }

    // We use alpha sort as a tiebreaker, which might be helpful for
    // new users.
    if (user_a.full_name < user_b.full_name) {
        return -1;
    } else if (user_a === user_b) {
        return 0;
    }
    return 1;
};

exports.sort_for_at_mentioning = function (objs, current_stream) {
    var objs_split = split_by_subscribers(objs, current_stream);

    var subs_sorted = objs_split.subscribers.sort(exports.compare_by_pms);
    var non_subs_sorted = objs_split.non_subscribers.sort(exports.compare_by_pms);
    return subs_sorted.concat(non_subs_sorted);
};

exports.sort_recipients = function (matches, query, current_stream) {
    var name_results =  prefix_sort(query, matches, function (x) { return x.full_name; });
    var email_results = prefix_sort(query, name_results.rest, function (x) { return x.email; });

    var matches_sorted = exports.sort_for_at_mentioning(
        name_results.matches.concat(email_results.matches),
        current_stream
    );
    var rest_sorted = exports.sort_for_at_mentioning(
        email_results.rest,
        current_stream
    );
    return matches_sorted.concat(rest_sorted);
};

exports.sort_emojis = function (matches, query) {
    // TODO: sort by category in v2
    var results = prefix_sort(query, matches, function (x) { return x.emoji_name; });
    return results.matches.concat(results.rest);
};

exports.compare_by_sub_count = function (stream_a, stream_b) {
    return stream_a.subscribers.num_items() < stream_b.subscribers.num_items();
};

exports.sort_streams = function (matches, query) {
    var name_results = prefix_sort(query, matches, function (x) { return x.name; });
    var desc_results
        = prefix_sort(query, name_results.rest, function (x) { return x.description; });

    // Streams that start with the query.
    name_results.matches = name_results.matches.sort(exports.compare_by_sub_count);
    // Streams with descriptions that start with the query.
    desc_results.matches = desc_results.matches.sort(exports.compare_by_sub_count);
    // Streams with names and descriptions that don't start with the query.
    desc_results.rest = desc_results.rest.sort(exports.compare_by_sub_count);

    return name_results.matches.concat(desc_results.matches.concat(desc_results.rest));
};

exports.sort_recipientbox_typeahead = function (query, matches, current_stream) {
    // input_text may be one or more pm recipients
    var cleaned = composebox_typeahead.get_cleaned_pm_recipients(query);
    query = cleaned[cleaned.length - 1];
    return exports.sort_recipients(matches, query, current_stream);
};

return exports;

}());
if (typeof module !== 'undefined') {
    module.exports = typeahead_helper;
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

import {assert} from 'chai';
import htm from 'htm';
import vhtml from 'vhtml';
import td from 'testdouble';
import {
  strings,
  cssClasses,
  events,
} from '../../../packages/mdc-data-table/constants';
import {MDCDataTable} from '../../../packages/mdc-data-table/index';

const html = htm.bind(vhtml);

const classMap = (classesMap) => {
  return Object.keys(classesMap).filter((className) => {
    return classesMap[className];
  }).join(' ');
};

const mdcCheckboxTemplate = (props) => {
  return html`

  <input type="checkbox" class="mdc-checkbox__native-control" checked="${props.isChecked}"></input>

    <svg class="mdc-checkbox__checkmark" viewbox="0 0 24 24">
      <path class="mdc-checkbox__checkmark-path" fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59"></path>
    </svg>

`;
};

const mdcDataTableHeaderCellTemplate = (props) => {
  return html`

      ${props.content}

  `;
};

const mdcDataTableCellTemplate = (props) => {
  const classes = {
    [cssClasses.CELL_NUMERIC]: props.isNumeric,
  };
  return html`
    ${props.content}
  `;
};

const mdcDataTableRowTemplate = (props) => {
  const classes = {
    [cssClasses.ROW]: true,
    [cssClasses.ROW_SELECTED]: props.isSelected,
  };
  const ariaSelectedValue = props.isSelected ? 'true' : 'false';
  const rowCheckbox = mdcDataTableCellTemplate({
    content: mdcCheckboxTemplate({
      classNames: cssClasses.ROW_CHECKBOX,
      isChecked: props.isSelected,
    }),
  });

  return html`

      ${rowCheckbox} ${props.content}

  `;
};

const mdcDataTableData = {
  headers: ['Dessert', 'Calories', 'Fat', 'Carbs', 'Protein (g)'],
  rows: [
    ['Frozen yogurt', 159, 6.0, 24, 4.0],
    ['Ice cream sandwich', 237, 9.0, 37, 4.3],
    ['Eclair', 262, 16.0, 24, 6.0],
  ],
  selectedRowIndexes: [1],
};

/** @return {!HTMLElement} */
function renderComponent(props) {
  /* eslint-disable indent */
  const blobHtml = html`

            ${mdcDataTableHeaderCellTemplate({
              content: mdcCheckboxTemplate({
                classNames: cssClasses.HEADER_ROW_CHECKBOX,
              }),
            })}
            ${props.data.headers.map((header) =>
              mdcDataTableHeaderCellTemplate({content: header}),
            )}

          ${props.data.rows.map((row, index) => {
            const isSelected =
              props.data.selectedRowIndexes.indexOf(index) >= 0;
            return mdcDataTableRowTemplate({
              rowId: `u${index}`,
              isSelected: isSelected,
              content: row.map((cell) => {
                const isNumeric = typeof cell === 'number';
                return mdcDataTableCellTemplate({content: cell, isNumeric});
              }),
            });
          })}

  `;

  document.body.innerHTML = '';
  const container = document.createElement('div');
  container.innerHTML = blobHtml;
  document.body.appendChild(container);
  return document.querySelector(`.${cssClasses.ROOT}`);
}

function setupTest() {
  const root = renderComponent({data: mdcDataTableData});
  const component = new MDCDataTable(root);
  const adapter = component.getDefaultFoundation().adapter_;
  return {root, component, adapter};
}

suite('MDCDataTable');

test('#attachTo returns a component instance', () => {
  const root = renderComponent({data: mdcDataTableData});
  const component = MDCDataTable.attachTo(root);
  assert.instanceOf(component, MDCDataTable);
  component.destroy();
});

test('Checking at least 1 row checkbox sets header row checkbox to indeterminate', () => {
  const {root} = setupTest();

  const rowCheckbox = root
    .querySelector(strings.ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  rowCheckbox.click();

  const headerRowCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  assert.isTrue(headerRowCheckbox.indeterminate);
});

test('#setSelectedRowIds sets selected row ids', () => {
  const {component} = setupTest();

  component.setSelectedRowIds(['u1', 'u2']);
  assert.deepEqual(component.getSelectedRowIds(), ['u1', 'u2']);
  component.destroy();
});

test('#getSelectedRowIds returns empty array when no rows selected', () => {
  const {component} = setupTest();

  component.setSelectedRowIds([]);
  assert.deepEqual(component.getSelectedRowIds(), []);
  component.destroy();
});

test('adapter#isHeaderRowCheckboxChecked returns true if header row checkbox is checked', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');

  nativeCheckbox.checked = false;
  assert.isFalse(adapter.isHeaderRowCheckboxChecked());

  nativeCheckbox.checked = true;
  assert.isTrue(adapter.isHeaderRowCheckboxChecked());

  component.destroy();
});

test('adapter#addClassAtRowIndex adds class name at given row index ', () => {
  const {component, adapter} = setupTest();

  adapter.addClassAtRowIndex(1, 'test-class-name');
  assert.isTrue(component.getRows()[1].classList.contains('test-class-name'));

  component.destroy();
});

test('adapter#removeClassAtRowIndex removes class name from given row index ', () => {
  const {component, adapter} = setupTest();

  adapter.addClassAtRowIndex(1, 'test-remove-class-name');
  adapter.removeClassAtRowIndex(1, 'test-remove-class-name');
  assert.isFalse(
    component.getRows()[1].classList.contains('test-remove-class-name'),
  );

  component.destroy();
});

test('adapter#setAttributeAtRowIndex', () => {
  const {component, adapter} = setupTest();

  adapter.setAttributeAtRowIndex(1, 'data-test-set-attr', 'test-val-1');
  assert.equal(
    adapter.getRowElements()[1].getAttribute('data-test-set-attr'),
    'test-val-1',
  );

  component.destroy();
});

test('adapter#getRowElements', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowElements().length, 3);
  component.destroy();
});

test('adapter#isRowsSelectable', () => {
  const {component, adapter} = setupTest();

  assert.isTrue(adapter.isRowsSelectable());

  component.destroy();
});

test('adapter#getRowIndexByChildElement', () => {
  const {component, root, adapter} = setupTest();

  const rows = [].slice.call(root.querySelectorAll(strings.ROW_SELECTOR));
  const inputEl = rows[2].querySelector('input');
  assert.equal(adapter.getRowIndexByChildElement(inputEl), 2);

  component.destroy();
});

test('adapter#getRowCount calls foundation.getRows() method', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowCount(), 3);

  component.destroy();
});

test('adapter#getSelectedRowCount', () => {
  const {component, adapter} = setupTest();

  assert.equal(
    adapter.getSelectedRowCount(),
    mdcDataTableData.selectedRowIndexes.length,
  );

  component.destroy();
});

test('adapter#notifyRowSelectionChanged', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifyRowSelectionChangedHandler');

  component.listen(events.ROW_SELECTION_CHANGED, handler);
  adapter.notifyRowSelectionChanged({rowIndex: 1, rowId: 'u1', selected: true});
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.ROW_SELECTION_CHANGED, handler);
  component.destroy();
});

test('adapter#setHeaderRowCheckboxIndeterminate', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');

  nativeCheckbox.indeterminate = false;
  adapter.setHeaderRowCheckboxIndeterminate(true);
  assert.isTrue(nativeCheckbox.indeterminate);

  component.destroy();
});

test('adapter#setHeaderRowCheckboxChecked', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  assert.isFalse(nativeCheckbox.checked);
  adapter.setHeaderRowCheckboxChecked(true);
  assert.isTrue(nativeCheckbox.checked);

  component.destroy();
});

test('adapter#getRowIdAtIndex', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowIdAtIndex(1), 'u1');
  component.destroy();
});

test('adapter#setRowCheckboxCheckedAtIndex', () => {
  const {component, root, adapter} = setupTest();
  const nativeCheckbox = [].slice
    .call(root.querySelectorAll(strings.ROW_CHECKBOX_SELECTOR))[0]
    .querySelector('input');

  assert.isFalse(nativeCheckbox.checked);
  adapter.setRowCheckboxCheckedAtIndex(0, true);
  assert.isTrue(nativeCheckbox.checked);

  component.destroy();
});

test('adapter#notifySelectedAll', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifySelectedAll');

  component.listen(events.SELECTED_ALL, handler);
  adapter.notifySelectedAll();
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.SELECTED_ALL, handler);
  component.destroy();
});

test('adapter#notifyUnselectedAll', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifyUnselectedAll');

  component.listen(events.UNSELECTED_ALL, handler);
  adapter.notifyUnselectedAll();
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.UNSELECTED_ALL, handler);
  component.destroy();
});
<commit_msg>test(data-table): don't clear karma html page when debugging (#5350)<commit_after>/**
 * @license
 * Copyright 2019 Google Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

import {assert} from 'chai';
import htm from 'htm';
import vhtml from 'vhtml';
import td from 'testdouble';
import {
  strings,
  cssClasses,
  events,
} from '../../../packages/mdc-data-table/constants';
import {MDCDataTable} from '../../../packages/mdc-data-table/index';

const html = htm.bind(vhtml);

const classMap = (classesMap) => {
  return Object.keys(classesMap).filter((className) => {
    return classesMap[className];
  }).join(' ');
};

const mdcCheckboxTemplate = (props) => {
  return html`

  <input type="checkbox" class="mdc-checkbox__native-control" checked="${props.isChecked}"></input>

    <svg class="mdc-checkbox__checkmark" viewbox="0 0 24 24">
      <path class="mdc-checkbox__checkmark-path" fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59"></path>
    </svg>

`;
};

const mdcDataTableHeaderCellTemplate = (props) => {
  return html`

      ${props.content}

  `;
};

const mdcDataTableCellTemplate = (props) => {
  const classes = {
    [cssClasses.CELL_NUMERIC]: props.isNumeric,
  };
  return html`
    ${props.content}
  `;
};

const mdcDataTableRowTemplate = (props) => {
  const classes = {
    [cssClasses.ROW]: true,
    [cssClasses.ROW_SELECTED]: props.isSelected,
  };
  const ariaSelectedValue = props.isSelected ? 'true' : 'false';
  const rowCheckbox = mdcDataTableCellTemplate({
    content: mdcCheckboxTemplate({
      classNames: cssClasses.ROW_CHECKBOX,
      isChecked: props.isSelected,
    }),
  });

  return html`

      ${rowCheckbox} ${props.content}

  `;
};

const mdcDataTableData = {
  headers: ['Dessert', 'Calories', 'Fat', 'Carbs', 'Protein (g)'],
  rows: [
    ['Frozen yogurt', 159, 6.0, 24, 4.0],
    ['Ice cream sandwich', 237, 9.0, 37, 4.3],
    ['Eclair', 262, 16.0, 24, 6.0],
  ],
  selectedRowIndexes: [1],
};

/** @return {!HTMLElement} */
function renderComponent(props) {
  /* eslint-disable indent */
  const blobHtml = html`

            ${mdcDataTableHeaderCellTemplate({
              content: mdcCheckboxTemplate({
                classNames: cssClasses.HEADER_ROW_CHECKBOX,
              }),
            })}
            ${props.data.headers.map((header) =>
              mdcDataTableHeaderCellTemplate({content: header}),
            )}

          ${props.data.rows.map((row, index) => {
            const isSelected =
              props.data.selectedRowIndexes.indexOf(index) >= 0;
            return mdcDataTableRowTemplate({
              rowId: `u${index}`,
              isSelected: isSelected,
              content: row.map((cell) => {
                const isNumeric = typeof cell === 'number';
                return mdcDataTableCellTemplate({content: cell, isNumeric});
              }),
            });
          })}

  `;

  const prevTable = document.querySelector(`.${cssClasses.ROOT}`);
  if (prevTable) {
    document.body.removeChild(prevTable.parentElement);
  }

  const container = document.createElement('div');
  container.innerHTML = blobHtml;
  document.body.appendChild(container);
  return document.querySelector(`.${cssClasses.ROOT}`);
}

function setupTest() {
  const root = renderComponent({data: mdcDataTableData});
  const component = new MDCDataTable(root);
  const adapter = component.getDefaultFoundation().adapter_;
  return {root, component, adapter};
}

suite('MDCDataTable');

test('#attachTo returns a component instance', () => {
  const root = renderComponent({data: mdcDataTableData});
  const component = MDCDataTable.attachTo(root);
  assert.instanceOf(component, MDCDataTable);
  component.destroy();
});

test('Checking at least 1 row checkbox sets header row checkbox to indeterminate', () => {
  const {root} = setupTest();

  const rowCheckbox = root
    .querySelector(strings.ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  rowCheckbox.click();

  const headerRowCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  assert.isTrue(headerRowCheckbox.indeterminate);
});

test('#setSelectedRowIds sets selected row ids', () => {
  const {component} = setupTest();

  component.setSelectedRowIds(['u1', 'u2']);
  assert.deepEqual(component.getSelectedRowIds(), ['u1', 'u2']);
  component.destroy();
});

test('#getSelectedRowIds returns empty array when no rows selected', () => {
  const {component} = setupTest();

  component.setSelectedRowIds([]);
  assert.deepEqual(component.getSelectedRowIds(), []);
  component.destroy();
});

test('adapter#isHeaderRowCheckboxChecked returns true if header row checkbox is checked', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');

  nativeCheckbox.checked = false;
  assert.isFalse(adapter.isHeaderRowCheckboxChecked());

  nativeCheckbox.checked = true;
  assert.isTrue(adapter.isHeaderRowCheckboxChecked());

  component.destroy();
});

test('adapter#addClassAtRowIndex adds class name at given row index ', () => {
  const {component, adapter} = setupTest();

  adapter.addClassAtRowIndex(1, 'test-class-name');
  assert.isTrue(component.getRows()[1].classList.contains('test-class-name'));

  component.destroy();
});

test('adapter#removeClassAtRowIndex removes class name from given row index ', () => {
  const {component, adapter} = setupTest();

  adapter.addClassAtRowIndex(1, 'test-remove-class-name');
  adapter.removeClassAtRowIndex(1, 'test-remove-class-name');
  assert.isFalse(
    component.getRows()[1].classList.contains('test-remove-class-name'),
  );

  component.destroy();
});

test('adapter#setAttributeAtRowIndex', () => {
  const {component, adapter} = setupTest();

  adapter.setAttributeAtRowIndex(1, 'data-test-set-attr', 'test-val-1');
  assert.equal(
    adapter.getRowElements()[1].getAttribute('data-test-set-attr'),
    'test-val-1',
  );

  component.destroy();
});

test('adapter#getRowElements', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowElements().length, 3);
  component.destroy();
});

test('adapter#isRowsSelectable', () => {
  const {component, adapter} = setupTest();

  assert.isTrue(adapter.isRowsSelectable());

  component.destroy();
});

test('adapter#getRowIndexByChildElement', () => {
  const {component, root, adapter} = setupTest();

  const rows = [].slice.call(root.querySelectorAll(strings.ROW_SELECTOR));
  const inputEl = rows[2].querySelector('input');
  assert.equal(adapter.getRowIndexByChildElement(inputEl), 2);

  component.destroy();
});

test('adapter#getRowCount calls foundation.getRows() method', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowCount(), 3);

  component.destroy();
});

test('adapter#getSelectedRowCount', () => {
  const {component, adapter} = setupTest();

  assert.equal(
    adapter.getSelectedRowCount(),
    mdcDataTableData.selectedRowIndexes.length,
  );

  component.destroy();
});

test('adapter#notifyRowSelectionChanged', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifyRowSelectionChangedHandler');

  component.listen(events.ROW_SELECTION_CHANGED, handler);
  adapter.notifyRowSelectionChanged({rowIndex: 1, rowId: 'u1', selected: true});
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.ROW_SELECTION_CHANGED, handler);
  component.destroy();
});

test('adapter#setHeaderRowCheckboxIndeterminate', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');

  nativeCheckbox.indeterminate = false;
  adapter.setHeaderRowCheckboxIndeterminate(true);
  assert.isTrue(nativeCheckbox.indeterminate);

  component.destroy();
});

test('adapter#setHeaderRowCheckboxChecked', () => {
  const {component, root, adapter} = setupTest();

  const nativeCheckbox = root
    .querySelector(strings.HEADER_ROW_CHECKBOX_SELECTOR)
    .querySelector('input');
  assert.isFalse(nativeCheckbox.checked);
  adapter.setHeaderRowCheckboxChecked(true);
  assert.isTrue(nativeCheckbox.checked);

  component.destroy();
});

test('adapter#getRowIdAtIndex', () => {
  const {component, adapter} = setupTest();

  assert.equal(adapter.getRowIdAtIndex(1), 'u1');
  component.destroy();
});

test('adapter#setRowCheckboxCheckedAtIndex', () => {
  const {component, root, adapter} = setupTest();
  const nativeCheckbox = [].slice
    .call(root.querySelectorAll(strings.ROW_CHECKBOX_SELECTOR))[0]
    .querySelector('input');

  assert.isFalse(nativeCheckbox.checked);
  adapter.setRowCheckboxCheckedAtIndex(0, true);
  assert.isTrue(nativeCheckbox.checked);

  component.destroy();
});

test('adapter#notifySelectedAll', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifySelectedAll');

  component.listen(events.SELECTED_ALL, handler);
  adapter.notifySelectedAll();
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.SELECTED_ALL, handler);
  component.destroy();
});

test('adapter#notifyUnselectedAll', () => {
  const {component, adapter} = setupTest();
  const handler = td.func('notifyUnselectedAll');

  component.listen(events.UNSELECTED_ALL, handler);
  adapter.notifyUnselectedAll();
  td.verify(handler(td.matchers.anything()));

  component.unlisten(events.UNSELECTED_ALL, handler);
  component.destroy();
});
<|endoftext|>


<commit_before>const request = require('request');
const fs = require('fs-extra');
import Submission from '../models/Submission'

var openURL = 'http://localhost:3000/open/test/';
var uploadURL = 'http://localhost:3000/upload/test/';
var addJobURL = 'http://localhost:3000/addJob/test/';

var lastLine = require('last-line');

function openTango(course_num, assignment_num) {
    var success = true;
    request.get(openURL + course_num + '-' + assignment_num + '/', function(err, response, body){
        if (err) {
            success = false;
        }
        else {
            success = true;
        }
    });
    console.log("Success: " + success);
    return success;
}

function uploadToTango(filename, filepath, url) {
    var file = fs.readFileSync(filepath);
    var success = true;
    var tangoReq = request({
        uri: url,
        method: 'POST',
        headers: {
            'filename': filename,
        },
        body: file
    }, function (err, response, body) {
        console.log(body);
        if (err) {
            success = false;
        }
        else {
            success = true;
        }
    });
    return success;
}

export function sendToTango(submission, assignment, course){
    if (!openTango(course.course_num, assignment.assignment_num)){
        console.log("Couldn't open Tango!");
        return false;
    }
    else {
        var url = uploadURL + course.course_num + '-' + assignment.assignment_num + '/';
        var submissionFile = `./uploads/${submission.course_num}/${submission.assignment_num}/submissions/${submission.file_name}`;
        var autogradeFile = `./uploads/${submission.course_num}/${submission.assignment_num}/Tango/autograde.tar`;
        var makeFile = `./uploads/${submission.course_num}/${submission.assignment_num}/Tango/autograde-Makefile`;
        var prefix = submission.user_email + '_' + submission.version + '_';
        if (!uploadToTango(submission.file_name, submissionFile, url)){
            return false;
        }
        console.log("Uploaded student file to Tango");
        if (!uploadToTango(prefix + 'Makefile', makeFile, url)){
            return false;
        }
        console.log("Uploaded Makefile to Tango");
        if (!uploadToTango(prefix + 'autograde.tar', autogradeFile, url)){
            return false;
        }
        console.log("Uploaded autograde.tar to Tango");

        console.log("Trying to add job!");
        var success = true;
        var addJob = request({
            uri: addJobURL + course.course_num + '-' + assignment.assignment_num + '/',
            method: 'POST',
            body: JSON.stringify({
                "image": "autograding_image",
                "files": [
                    {
                        "localFile": submission.file_name,
                        "destFile": assignment.form.file_name
                    },
                    {
                        "localFile": prefix + 'Makefile',
                        "destFile": 'Makefile'
                    },
                    {
                        "localFile": prefix + 'autograde.tar',
                        "destFile": 'autograde.tar'
                    }
                ],
                "jobName": prefix + "job",
                "output_file": prefix + "feedback.txt",
                "timeout": 180,
                "max_kb": 1024,
                "callback_url": 'http://localhost:8000/api/Tango/callback/' + course.course_num + '/' + assignment.assignment_num + '/' + submission._id
            })
        }, function (err, response, body) {
            console.log(body);
            if (err) {
                success = false;
            }
            else {
                success = true;
            }
        });
        console.log("Submitted job: " + success);
    }
}

export function callbackTango(req, res){
    Submission.findById(req.params.submission_id, function(err, submission){
        var file = fs.readFileSync(`./uploads/${submission.course_num}/${submission.assignment_num}/feedback/${submission.user_email}_${submission.version}_feedback.txt`, 'utf8');
        submission.feedback = file;
        var scoresList = []
        lastLine(`./uploads/${submission.course_num}/${submission.assignment_num}/feedback/${submission.user_email}_${submission.version}_feedback.txt`, function (err, temp) {
           try {
            var output = JSON.parse(temp);
            var scoresJson = output.scores;
            for (var problem_name in scoresJson) {
                if (scoresJson.hasOwnProperty(problem_name)) {
                   scoresList.push({
                     "problem_name" : problem_name,
                     "score"        : scoresJson[problem_name]
                   });
                }
             }
             submission.set('scores', scoresList);

             submission.save((err, updatedSubmission) => {
                 if (err) res.status(500).send(err);
                 else res.status(200).send({});
             });
           } catch(e){
                Course.findOne({'course_num': submission.course_num}, (err, course) => {
                    if (err){
                        res.status(500).send(err);
                    } else {
                        course.assignments.forEach((assignment) => {
                            if(assignment.assignment_num == submission.assignment_num){
                                console.log(assignment.problems);
                            }
                        });
                    }
                });
                submission.save((err, updatedSubmission) => {
                    if (err) res.status(500).send(err);
                    else res.status(200).send({});
                });
           }
        });
    });
}<commit_msg>added try/catch block to handle JSON that can't be parsed from Tango<commit_after>const request = require('request');
const fs = require('fs-extra');
import Submission from '../models/Submission'
import Course from '../models/Course'

var openURL = 'http://localhost:3000/open/test/';
var uploadURL = 'http://localhost:3000/upload/test/';
var addJobURL = 'http://localhost:3000/addJob/test/';

var lastLine = require('last-line');
var async = require('async');

function openTango(course_num, assignment_num) {
    var success = true;
    request.get(openURL + course_num + '-' + assignment_num + '/', function(err, response, body){
        if (err) {
            success = false;
        }
        else {
            success = true;
        }
    });
    console.log("Success: " + success);
    return success;
}

function uploadToTango(filename, filepath, url) {
    var file = fs.readFileSync(filepath);
    var success = true;
    var tangoReq = request({
        uri: url,
        method: 'POST',
        headers: {
            'filename': filename,
        },
        body: file
    }, function (err, response, body) {
        console.log(body);
        if (err) {
            success = false;
        }
        else {
            success = true;
        }
    });
    return success;
}

export function sendToTango(submission, assignment, course){
    if (!openTango(course.course_num, assignment.assignment_num)){
        console.log("Couldn't open Tango!");
        return false;
    }
    else {
        var url = uploadURL + course.course_num + '-' + assignment.assignment_num + '/';
        var submissionFile = `./uploads/${submission.course_num}/${submission.assignment_num}/submissions/${submission.file_name}`;
        var autogradeFile = `./uploads/${submission.course_num}/${submission.assignment_num}/Tango/autograde.tar`;
        var makeFile = `./uploads/${submission.course_num}/${submission.assignment_num}/Tango/autograde-Makefile`;
        var prefix = submission.user_email + '_' + submission.version + '_';
        if (!uploadToTango(submission.file_name, submissionFile, url)){
            return false;
        }
        console.log("Uploaded student file to Tango");
        if (!uploadToTango(prefix + 'Makefile', makeFile, url)){
            return false;
        }
        console.log("Uploaded Makefile to Tango");
        if (!uploadToTango(prefix + 'autograde.tar', autogradeFile, url)){
            return false;
        }
        console.log("Uploaded autograde.tar to Tango");

        console.log("Trying to add job!");
        var success = true;
        var addJob = request({
            uri: addJobURL + course.course_num + '-' + assignment.assignment_num + '/',
            method: 'POST',
            body: JSON.stringify({
                "image": "autograding_image",
                "files": [
                    {
                        "localFile": submission.file_name,
                        "destFile": assignment.form.file_name
                    },
                    {
                        "localFile": prefix + 'Makefile',
                        "destFile": 'Makefile'
                    },
                    {
                        "localFile": prefix + 'autograde.tar',
                        "destFile": 'autograde.tar'
                    }
                ],
                "jobName": prefix + "job",
                "output_file": prefix + "feedback.txt",
                "timeout": 180,
                "max_kb": 1024,
                "callback_url": 'http://localhost:8000/api/Tango/callback/' + course.course_num + '/' + assignment.assignment_num + '/' + submission._id
            })
        }, function (err, response, body) {
            console.log(body);
            if (err) {
                success = false;
            }
            else {
                success = true;
            }
        });
        console.log("Submitted job: " + success);
    }
}

export function callbackTango(req, res){
    Submission.findById(req.params.submission_id, function(err, submission){
        var file = fs.readFileSync(`./uploads/${submission.course_num}/${submission.assignment_num}/feedback/${submission.user_email}_${submission.version}_feedback.txt`, 'utf8');
        submission.feedback = file;
        var scoresList = []
        lastLine(`./uploads/${submission.course_num}/${submission.assignment_num}/feedback/${submission.user_email}_${submission.version}_feedback.txt`, function (err, temp) {
           try {
            var output = JSON.parse(temp);
            var scoresJson = output.scores;
            for (var problem_name in scoresJson) {
                if (scoresJson.hasOwnProperty(problem_name)) {
                   scoresList.push({
                     "problem_name" : problem_name,
                     "score"        : scoresJson[problem_name]
                   });
                }
             }
             submission.set('scores', scoresList);

             submission.save((err, updatedSubmission) => {
                 if (err) res.status(500).send(err);
                 else res.status(200).send({});
             });
           } catch(e){
                Course.findOne({'course_num': submission.course_num}, (err, course) => {
                    if (err){
                        res.status(500).send(err);
                    } else {

                        course.assignments.forEach((assignment) => {
                            if(assignment.assignment_num == submission.assignment_num){
                                assignment.problems.forEach((prob) => {
                                    scoresList.push({
                                        "problem_name" : prob.problem_name,
                                        "score"        : 0
                                    });
                                });
                                submission.set('scores', scoresList);

                                submission.save((err, updatedSubmission) => {
                                    if (err) res.status(500).send(err);
                                    else res.status(200).send({});
                                });
                            }
                        });
                    }
                });
           }
        });
    });
}<|endoftext|>


<commit_before>chrome.runtime.onMessage.addListener(function(req) {
  switch (req.action) {
    case 'COMMIT_TIME':
      document.querySelector('textarea[name=comment\\[body\\]]').value = 'Time spent: ' + req.time;
      document.querySelector('#partial-new-comment-form-actions button').click()
      break;
    case 'SHOW_REPORTS':
      $('.report').remove();
      $('body').append(req.content);
      $('#reports').modal('show');
      var milestoneTotalHours = milestoneTotalMinutes = 0;
      $('select[name=milestone]').change(function() {
        var milestoneHref = $(this).val();
        $.get(
          'https://github.com' + milestoneHref,
          function(html) {
            html = $(html);
            $('.time-items').html('');
            $('.milestoneTotal').text('');
            milestoneTotalHours = milestoneTotalMinutes = 0;
            $('a.issue-title-link', html).each(function() {
              var issueTitle = $(this).text();
              var issueHref = $(this).attr('href');
              $.get(
                'https://github.com' + issueHref,
                function(html) {
                  var regex = /
Time spent: \d+:\d+<\/p>/g
                  var matches = html.match(regex);
                  if (matches) {
                    var totalHours = totalMinutes = 0;
                    $.each(matches, function(index, value) {
                      regex = /Time spent: (\d+):(\d+)/
                      matches2 = value.match(regex);
                      totalHours += parseInt(matches2[1]);
                      totalMinutes += parseInt(matches2[2]);
                    });
                    totalHours += Math.floor(totalMinutes / 60);
                    totalMinutes = totalMinutes % 60;
                    milestoneTotalHours += totalHours;
                    milestoneTotalMinutes = parseInt(milestoneTotalMinutes) + totalMinutes;
                    if (totalMinutes < 10) {
                      totalMinutes = "0" + totalMinutes;
                    }
                    $('#reports .time-items').append('
' + issueTitle + '	' + totalHours + ':' + totalMinutes + '
');
                    milestoneTotalHours += Math.floor(milestoneTotalMinutes / 60);
                    milestoneTotalMinutes = milestoneTotalMinutes % 60;
                    if (milestoneTotalMinutes < 10) {
                      milestoneTotalMinutes = "0" + milestoneTotalMinutes;
                    }
                    $('.milestoneTotal').text(milestoneTotalHours + ':' + milestoneTotalMinutes);
                  }
                }
              );
            });
          }
        );
      });

      $('#sendBill').click(function() {
        var rate = window.prompt('Please enter hourly rate for this project:');
        var recipient = window.prompt('Please enter email recipient:');
        var subject = "Invoice for project " + req.project;
        var amount = milestoneTotalHours * rate + milestoneTotalMinutes / 60 * rate;
        $('#reports .milestoneAmount').text("$" + parseFloat(amount).toFixed(2));

        var body = '';
        $('#reports tbody tr').each(function() {
          body += 'Task: "' + $('td:first', this).text().trim() + '"\r\n'
               + 'Time spent: ' + $('td:nth-child(2)', this).text().trim() + "\r\n\r\n";
        });

        body += '\r\nTotal Time: ' + $('#reports .milestoneTotal').text().trim();
        body += '\r\n\r\nAmount Due: ' + $('#reports .milestoneAmount').text().trim();

        body = "Reference milestone: " + $('select[name=milestone] option:selected').text()
          + "\r\n\r\n"
          + body;

        window.location.href = 'mailto:' + recipient + '?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body);
      });

      break;
  }
});
<commit_msg>fixed report<commit_after>chrome.runtime.onMessage.addListener(function(req) {
  switch (req.action) {
    case 'COMMIT_TIME':
      document.querySelector('textarea[name=comment\\[body\\]]').value = 'Time spent: ' + req.time;
      document.querySelector('#partial-new-comment-form-actions button').click()
      break;
    case 'SHOW_REPORTS':
      $('.report').remove();
      $('body').append(req.content);
      $('#reports').modal('show');
      var milestoneTotalHours = milestoneTotalMinutes = 0;
      $('select[name=milestone]').change(function() {
        var milestoneHref = $(this).val();
        var parts = milestoneHref.split('/');
        var milestoneLabel = parts[parts.length - 1];
        $.get(
          'https://github.com/' + parts[1] + '/' + parts[2] + '/issues?q=milestone%3A' + encodeURIComponent(milestoneLabel),
          function(html) {
            html = $(html);
            $('.time-items').html('');
            $('.milestoneTotal').text('');
            milestoneTotalHours = milestoneTotalMinutes = 0;
            $('a.issue-title-link', html).each(function() {
              var issueTitle = $(this).text();
              var issueHref = $(this).attr('href');
              $.get(
                'https://github.com' + issueHref,
                function(html) {
                  var regex = /
Time spent: \d+:\d+<\/p>/g
                  var matches = html.match(regex);
                  if (matches) {
                    var totalHours = totalMinutes = 0;
                    $.each(matches, function(index, value) {
                      regex = /Time spent: (\d+):(\d+)/
                      matches2 = value.match(regex);
                      totalHours += parseInt(matches2[1]);
                      totalMinutes += parseInt(matches2[2]);
                    });
                    totalHours += Math.floor(totalMinutes / 60);
                    totalMinutes = totalMinutes % 60;
                    milestoneTotalHours += totalHours;
                    milestoneTotalMinutes = parseInt(milestoneTotalMinutes) + totalMinutes;
                    if (totalMinutes < 10) {
                      totalMinutes = "0" + totalMinutes;
                    }
                    $('#reports .time-items').append('
' + issueTitle + '	' + totalHours + ':' + totalMinutes + '
');
                    milestoneTotalHours += Math.floor(milestoneTotalMinutes / 60);
                    milestoneTotalMinutes = milestoneTotalMinutes % 60;
                    if (milestoneTotalMinutes < 10) {
                      milestoneTotalMinutes = "0" + milestoneTotalMinutes;
                    }
                    $('.milestoneTotal').text(milestoneTotalHours + ':' + milestoneTotalMinutes);
                  }
                }
              );
            });
          }
        );
      });

      $('#sendBill').click(function() {
        var rate = window.prompt('Please enter hourly rate for this project:');
        var recipient = window.prompt('Please enter email recipient:');
        var subject = "Invoice for project " + req.project;
        var amount = milestoneTotalHours * rate + milestoneTotalMinutes / 60 * rate;
        $('#reports .milestoneAmount').text("$" + parseFloat(amount).toFixed(2));

        var body = '';
        $('#reports tbody tr').each(function() {
          body += 'Task: "' + $('td:first', this).text().trim() + '"\r\n'
               + 'Time spent: ' + $('td:nth-child(2)', this).text().trim() + "\r\n\r\n";
        });

        body += '\r\nTotal Time: ' + $('#reports .milestoneTotal').text().trim();
        body += '\r\n\r\nAmount Due: ' + $('#reports .milestoneAmount').text().trim();

        body = "Reference milestone: " + $('select[name=milestone] option:selected').text()
          + "\r\n\r\n"
          + body;

        window.location.href = 'mailto:' + recipient + '?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body);
      });

      break;
  }
});
<|endoftext|>