jam-cloud/web/app/assets/javascripts/sessionList.js

620 lines
24 KiB
JavaScript

(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.SessionList = function(app) {
var EVENTS = context.JK.EVENTS;
var gearUtils = context.JK.GearUtils;
var sessionUtils = context.JK.SessionUtils;
var helpBubble = context.JK.HelpBubbleHelper;
var logger = context.JK.logger;
var rest = context.JK.Rest();
var ui = new context.JK.UIHelper(app);
var $activeSessionTemplate = $('#template-active-session-row');
var $inactiveSessionTemplate = $('#template-inactive-session-row');
var $notationFileTemplate = $('#template-notation-files');
var $openSlotsTemplate = $('#template-open-slots');
var $latencyTemplate = $('#template-latency');
var $musicianTemplate = $('#template-musician-info');
var showJoinLink = true;
var showListenLink = true;
var MAX_MINUTES_SHOW_START = 15;
// related to listen
function stateChange(e, data) {
var $listenLink = data.element;
var $parent = $listenLink.closest('.action-links')
//console.log(e,$(this))
var $listenText = $('.listen-link-text', $parent);
var $listenDetails = $('.listen-link-details', $parent);
if(data.displayText)
{
if(data.state == 'playing') {
$listenText.text('Stop Listening')
}
else {
$listenText.text(context.JK.toTitleCase(data.displayText))
$listenDetails.addClass('statusing')
}
}
if(data.isEnd) {
//$listenDetails.removeClass('statusing')
//$listenText.text('Listen')
stopPlay($listenLink);
}
if(data.isSessionOver) {
$listenLink.removeClass('inprogress').addClass('ended')
}
}
function startPlay($listenLink) {
$listenLink.find('img').attr('src', '/assets/content/pause-icon.jpg');
$listenLink.trigger('play.listenBroadcast');
}
function stopPlay($listenLink) {
$listenLink.find('img').attr('src', '/assets/content/listen-icon.jpg');
$listenLink.trigger('pause.listenBroadcast');
}
function togglePlay() {
var $listenLink = $(this)
var $parent = $listenLink.closest('.action-links');
var $listenText = $('.listen-link-text', $parent);
var $listenDetails = $('.listen-link-details', $parent);
if (true) {
context.JK.Banner.showAlert('Disabled Due to High Demand', 'JamKazam has been under very high demand recently.<br/><br/>This feature is disabled while we scale up the backend servers and technology.')
}
else {
if ($listenLink.data('listenbroadcast-playstate') == 'playing') {
$listenText.text('Listen')
$listenDetails.removeClass('statusing')
stopPlay($listenLink);
}
else {
startPlay($listenLink);
}
}
return false;
}
function renderActiveSession(session, tbGroup, myAudioLatency) {
var i = 0;
var inSessionUsersHtml = '', rsvpFirst3UsersHtml = '', rsvpRemainingUsersHtml = '', openSlotsFirst3Html = '', openSlotsRemainingHtml = '', latencyInSessionHtml = '', latencyFirst3Html = '', latencyRemainingHtml = '', notationFileHtml = '';
// this is used to track which users are already in the session so we can exclude them from the
// "RSVPs" section
var inSessionUsers = [];
showJoinLink = session.musician_access;
showListenLink = session.fan_access && session.active_music_session && session.active_music_session.mount;
// render musicians who are already in the session
if (session.active_music_session && "participants" in session.active_music_session && session.active_music_session.participants.length > 0) {
for (i=0; i < session.active_music_session.participants.length; i++) {
inSessionUsers.push(session.active_music_session.participants[i].user.id);
var inSessionUserInfo = createInSessionUser(session.active_music_session.participants[i]);
inSessionUsersHtml += inSessionUserInfo[0];
latencyInSessionHtml += inSessionUserInfo[1];
}
}
// this provides a buffer at the top to shift the first latency tag down in the event there are NO in-session musicians
else {
latencyInSessionHtml += "<div style='height:15px;'>&nbsp;</div>";
}
// render users who have approved RSVPs
if (session.approved_rsvps) {
var approvedRsvpCount = session.approved_rsvps.length;
for (i=0; i < approvedRsvpCount; i++) {
// do not show the user in this section if he is already in the session
if ($.inArray(session.approved_rsvps[i].id, inSessionUsers) === -1) {
if (session.approved_rsvps[i].id === context.JK.currentUserId) {
showJoinLink = true;
}
var rsvpUserInfo = createRsvpUser(session.approved_rsvps[i], session, approvedRsvpCount, i);
if (i < 3) {
rsvpFirst3UsersHtml += rsvpUserInfo[0];
latencyFirst3Html += rsvpUserInfo[1];
}
else {
rsvpRemainingUsersHtml += rsvpUserInfo[0];
latencyRemainingHtml += rsvpUserInfo[1];
}
}
else {
showJoinLink = true;
}
}
}
// render if anyone interested
if(session['is_unstructured_rsvp?']) {
openSlotsFirst3Html += sessionUtils.createOpenSlot($openSlotsTemplate, {description: 'Any Instrument'});
}
// render open slots
if (session.open_slots) {
var openSlotCount = session.open_slots.length;
for (i=0; i < openSlotCount; i++) {
if (i < 3) {
openSlotsFirst3Html += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i], openSlotCount, i);
}
else {
openSlotsRemainingHtml += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i], openSlotCount, i);
}
}
}
// notation files
if (session.music_notations) {
for (i=0; i < session.music_notations.length; i++) {
notationFileHtml += createNotationFile(session.music_notations[i]);
}
}
var sessionVals = buildSessionObject(session, notationFileHtml, rsvpFirst3UsersHtml, rsvpRemainingUsersHtml, openSlotsFirst3Html, openSlotsRemainingHtml, latencyFirst3Html, latencyRemainingHtml, latencyInSessionHtml);
sessionVals.in_session_musicians = inSessionUsersHtml.length > 0 ? inSessionUsersHtml : 'N/A';
sessionVals.join_link_display_style = showJoinLink ? "block" : "none";
sessionVals.listen_link_display_style = showListenLink ? "inline-block" : "none";
if (!session.fan_access) {
sessionVals.listen_link_text = '';
}
else if (session.active_music_session && session.active_music_session.mount) {
sessionVals.listen_link_text = 'Listen';
}
else {
sessionVals.listen_link_text = '';
}
var $row = $(context.JK.fillTemplate($activeSessionTemplate.html(), sessionVals));
var $offsetParent = $(tbGroup).closest('.content');
var $latencyBadges = $row.find('.latency-value');
context._.each($latencyBadges, function(latencyBadge) {
var $latencyBadge = $(latencyBadge);
var full_score = $latencyBadge.attr('data-full-score') || null;
var internet_score = $latencyBadge.attr('data-internet-score') || null;
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
var scoreOptions = {offsetParent: $offsetParent};
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
});
$(tbGroup).append($row);
var $parentRow = $('tr[data-session-id=' + session.id + ']', tbGroup);
// wire up "more" links
$('a.more.slots', $parentRow).click(toggleSlots);
$('a.more.rsvps', $parentRow).click(toggleRsvps);
$('.notation-link').click(function(evt) {
rest.getMusicNotation($(this).attr('data-notation-id'))
.done(function(result) {
window.open(result, '_blank');
})
.fail(function(xhr, textStatus, errorMessage) {
if (xhr.status === 403) {
app.ajaxError(xhr, textStatus, errorMessage);
}
});
});
// enable listen button
if(showListenLink) {
var $listenLink = $('.listen-link', $parentRow)
var $listenText = $('.listen-link-text', $parentRow)
var $listenDetailHover = $('.listen-detail-hover', $parentRow)
$listenLink.parent().hoverIntent({
over: function() {
$listenDetailHover.show();
},
out: function() {
$listenDetailHover.hide();
}
})
$listenLink.attr('data-music-session', session.id).attr('fan-access', session.fan_access).attr('data-audio-src', session.active_music_session.mount.url).attr('data-audio-type', session.active_music_session.mount.mime_type)
$listenLink.listenBroadcast({lazyAudioInit:true, hoverOptions: {offsetParent: $offsetParent}, detailHelper: $listenDetailHover});
$listenLink.bind('statechange.listenBroadcast', stateChange);
$listenLink.click(togglePlay);
}
if (showJoinLink) {
// wire up the Join Link to the T&Cs dialog
$('.join-link', $parentRow).click(function(evt) {
sessionUtils.ensureValidClient(app, gearUtils, function() {
sessionUtils.joinSession(session.id);
});
});
}
}
function renderInactiveSession(session, tbGroup, $rowToUpdate, myAudioLatency) {
var openSlots = false;
var hasInvitation = false;
var approvedRsvpId = null; // if set, the user has an accepted RSVP
var pendingRsvpId = null; // if set, the user has a pending RSVP
var hasPendingOrDeclinedRsvp = false;
var openRsvps = session.open_rsvps;
var i = 0;
var rsvpFirst3UsersHtml = '', rsvpRemainingUsersHtml = '', openSlotsFirst3Html = '', openSlotsRemainingHtml = '', latencyFirst3Html = '', latencyRemainingHtml = '', notationFileHtml = '';
context._.each(session.pending_rsvp_requests, function(pending_rsvp_request) {
if(pending_rsvp_request.user_id === context.JK.currentUserId) {
pendingRsvpId = pending_rsvp_request.id;
}
});
// render users who have approved RSVPs
if (session.approved_rsvps && session.approved_rsvps.length > 0) {
var approvedRsvpCount = session.approved_rsvps.length;
context._.each(session.approved_rsvps, function(approved_rsvp) {
if (approved_rsvp.id === context.JK.currentUserId) {
approvedRsvpId = approved_rsvp.rsvp_request_id;
}
var rsvpUserInfo = createRsvpUser(approved_rsvp, session, approvedRsvpCount, i);
if (i < 3) {
rsvpFirst3UsersHtml += rsvpUserInfo[0];
latencyFirst3Html += rsvpUserInfo[1];
}
else {
rsvpRemainingUsersHtml += rsvpUserInfo[0];
latencyRemainingHtml += rsvpUserInfo[1];
}
i++;
});
}
// this provides a buffer at the top to shift the first latency tag down in the event there are NO RSVP musicians
else {
latencyFirst3Html += "<div style='height:15px;'>&nbsp;</div>";
}
if(session['is_unstructured_rsvp?']) {
openSlots = true; // unstructured RSVP means there are always open slots
openSlotsFirst3Html += sessionUtils.createOpenSlot($openSlotsTemplate, {description: 'Any Instrument'});
}
// render open slots
if (session.open_slots) {
var openSlotCount = session.open_slots.length;
for (i=0; i < openSlotCount; i++) {
openSlots = true;
if (i < 3) {
openSlotsFirst3Html += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i], openSlotCount, i);
}
else {
openSlotsRemainingHtml += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i], openSlotCount, i);
}
}
}
// render pending invitations
if (session.pending_invitations) {
for (i=0; i < session.pending_invitations.length; i++) {
if (session.pending_invitations[i].id === context.JK.currentUserId) {
hasInvitation = true;
}
}
}
// notation files
if (session.music_notations) {
for (i=0; i < session.music_notations.length; i++) {
notationFileHtml += createNotationFile(session.music_notations[i]);
}
}
var sessionVals = buildSessionObject(session, notationFileHtml, rsvpFirst3UsersHtml, rsvpRemainingUsersHtml,
openSlotsFirst3Html, openSlotsRemainingHtml, latencyFirst3Html, latencyRemainingHtml, '');
sessionVals.scheduled_start = session.pretty_scheduled_start_with_timezone;
var $row = $(context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals));
var $offsetParent = $(tbGroup).closest('.content');
var $latencyBadges = $row.find('.latency-value');
context._.each($latencyBadges, function(latencyBadge) {
var $latencyBadge = $(latencyBadge);
var full_score = $latencyBadge.attr('data-full-score') || null;
var internet_score = $latencyBadge.attr('data-internet-score') || null;
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
var scoreOptions = {offsetParent: $offsetParent};
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
})
// initial page load
if (!$rowToUpdate) {
$(tbGroup).append($row);
}
// inline update after an RSVP submission / cancellation
else {
$rowToUpdate.replaceWith($row);
}
var $parentRow = $('tr[data-session-id=' + session.id + ']', tbGroup);
// wire up "more" links
$('a.more.slots', $parentRow).click(toggleSlots);
$('a.more.rsvps', $parentRow).click(toggleRsvps);
var showRsvpLink = true;
var sessionLinkText = '';
$('.rsvp-link-text', $parentRow).hide();
function showStartSessionButton(scheduledStart) {
var now = new Date();
var scheduledDate = new Date(scheduledStart);
var minutesFromStart = (scheduledDate.getTime() - now.getTime()) / (1000 * 60);
return minutesFromStart <= MAX_MINUTES_SHOW_START;
};
if (session.creator.id === context.JK.currentUserId) {
showRsvpLink = false;
sessionLinkText = $('<span class="text"><a class="start" style="color: #fc0">Start session now?</a></span>');
sessionLinkText.find('a').click(function() {
ui.launchSessionStartDialog(session);
return false;
});
}
else if (approvedRsvpId) {
showRsvpLink = false;
if (session.scheduled_start && showStartSessionButton(session.scheduled_start)) {
sessionLinkText = $('<span class="text"><a class="start" style="color: #fc0">Start session now?</a>&nbsp;|&nbsp;<a class="cancel" style="color: #fc0">Cancel RSVP</a></span>');
sessionLinkText.find('a.start').click(function() {
ui.launchSessionStartDialog(session);
return false;
});
}
else {
sessionLinkText = $('<span class="text"><a class="cancel" style="color: #fc0">Cancel RSVP</a></span>');
}
// wire cancel link
sessionLinkText.find('a.cancel').click(function() {
ui.launchRsvpCancelDialog(session.id, approvedRsvpId)
.one(EVENTS.RSVP_CANCELED, function() {
rest.getSessionHistory(session.id)
.done(function(response) {
renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency);
});
})
.one(EVENTS.DIALOG_CLOSED, function() {
$(this).unbind(EVENTS.RSVP_CANCELED);
});
return false;
});
}
else if (hasInvitation) {
showRsvpLink = false;
if (session.scheduled_start && showStartSessionButton(session.scheduled_start)) {
sessionLinkText = $('<span class="text"><a class="start" style="color: #fc0">Start session now?</a></span>');
sessionLinkText.find('a').click(function() {
ui.launchSessionStartDialog(session);
return false;
});
}
}
else if (pendingRsvpId) {
showRsvpLink = false;
sessionLinkText = $('<span class="text"><a class="cancel" style="color: #fc0">Cancel RSVP</a></span>');
sessionLinkText.find('a').click(function() {
ui.launchRsvpCancelDialog(session.id, pendingRsvpId)
.one(EVENTS.RSVP_CANCELED, function() {
rest.getSessionHistory(session.id)
.done(function(response) {
renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency);
});
})
.one(EVENTS.DIALOG_CLOSED, function() {
$(this).unbind(EVENTS.RSVP_CANCELED);
});
return false;
});
}
else if (!openSlots) {
showRsvpLink = false;
sessionLinkText = '<span class="text">No more openings in this session.</span>';
}
else if (!openRsvps && !hasInvitation) {
showRsvpLink = false;
sessionLinkText = '<span class="text">You need an invitation to RSVP to this session.</span>';
}
if (showRsvpLink) {
$('.rsvp-msg', $parentRow).hide();
$('.rsvp-link', $parentRow).show();
$('.rsvp-link-text', $parentRow).show();
$('.rsvp-link', $parentRow).click(function(evt) {
ui.launchRsvpSubmitDialog(session.id)
.one(EVENTS.RSVP_SUBMITTED, function() {
rest.getSessionHistory(session.id)
.done(function(response) {
renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency);
});
})
.one(EVENTS.DIALOG_CLOSED, function() {
$(this).unbind(EVENTS.RSVP_SUBMITTED);
});
return false;
});
}
else {
$('.rsvp-msg', $parentRow).html(sessionLinkText).show();
$('.rsvp-link', $parentRow).hide();
}
}
function buildSessionObject(session, notationFileHtml, rsvpFirst3UsersHtml, rsvpRemainingUsersHtml, openSlotsFirst3Html, openSlotsRemainingHtml, latencyFirst3Html, latencyRemainingHtml, latencyInSessionHtml) {
return {
id: session.id,
name: session.name,
description: session.description || "(No description)",
notation_files: notationFileHtml.length > 0 ? notationFileHtml : 'N/A',
genres: session.genres.join (', '),
rsvp_musicians_first_3: rsvpFirst3UsersHtml.length > 0 ? rsvpFirst3UsersHtml : 'N/A',
rsvp_musicians_remaining: rsvpRemainingUsersHtml.length > 0 ? rsvpRemainingUsersHtml : 'N/A',
open_slots_first_3: openSlotsFirst3Html.length > 0 ? openSlotsFirst3Html : 'No slots available',
open_slots_remaining: openSlotsRemainingHtml.length > 0 ? openSlotsRemainingHtml : 'No slots available',
latency_first_3: latencyFirst3Html,
latency_remaining: latencyRemainingHtml,
latency_in_session: latencyInSessionHtml,
language: session.language_description,
musician_access: session.musician_access_description,
fan_access: session.fan_access_description,
legal_policy: session.legal_policy
};
}
function createInSessionUser(participant) {
var instrumentLogoHtml = '';
var j;
var existingTracks = [];
// loop through the tracks to get the instruments
for (j=0; j < participant.tracks.length; j++) {
var track = participant.tracks[j];
if (existingTracks.indexOf(track.instrument_id) < 0) {
existingTracks.push(track.instrument_id);
logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks);
var inst = context.JK.getInstrumentIcon24(track.instrument_id);
instrumentLogoHtml += '<img title="' + context.JK.getInstrumentId(track.instrument_id) + '" hoveraction="instrument" data-instrument-id="' + track.instrument_id + '" src="' + inst + '" width="24" height="24" />&nbsp;';
}
}
var id = participant.user.id;
var name = participant.user.name;
var musicianVals = {
userId: id,
avatar_url: context.JK.resolveAvatarUrl(participant.user.photo_url),
profile_url: "/client#/profile/" + id,
musician_name: name,
instruments: instrumentLogoHtml,
more_link: ''
};
var musicianHtml = context.JK.fillTemplate($musicianTemplate.html(), musicianVals);
var latencyHtml = context._.template($latencyTemplate.html(), $.extend(sessionUtils.createLatency(participant.user), participant.user), { variable: 'data' });
return [musicianHtml, latencyHtml];
}
function createRsvpUser(user, session, rsvpCount, currentIndex) {
var instrumentLogoHtml = '';
var j;
// loop through the tracks to get the instruments
if ("instrument_list" in user) {
for (j=0; j < user.instrument_list.length; j++) {
var instrument = user.instrument_list[j];
var inst = context.JK.getInstrumentIcon24(instrument.id);
instrumentLogoHtml += '<img title="' + context.JK.getInstrumentId(instrument.id) + '" hoveraction="instrument" data-instrument-id="' + instrument.id + '" src="' + inst + '" width="24" height="24" />&nbsp;';
}
}
var moreLinkHtml = '';
if (rsvpCount > 3 && currentIndex === 2) {
moreLinkHtml = '<a class="rsvps more">more</a><a class="details-arrow arrow-down-orange"></a>';
}
var id = user.id;
var name = user.name;
var musicianVals = {
userId: id,
avatar_url: context.JK.resolveAvatarUrl(user.photo_url),
profile_url: "/client#/profile/" + id,
musician_name: name,
instruments: instrumentLogoHtml,
more_link: moreLinkHtml
};
var musicianHtml = context.JK.fillTemplate($musicianTemplate.html(), musicianVals);
var latencyHtml = context._.template($latencyTemplate.html(), $.extend(sessionUtils.createLatency(user), user), { variable: 'data' });
return [musicianHtml, latencyHtml];
}
function createNotationFile(notation) {
var notationVals = {
notation_id: notation.id,
file_url: notation.viewable ? notation.file_url + '?target=_blank' : '#',
file_name: notation.file_name,
link_class: notation.viewable ? '' : 'notation-link'
};
return context.JK.fillTemplate($notationFileTemplate.html(), notationVals);
}
function toggleSlots() {
var $div = $(this).closest('table').next();
var $arrow = $(this).next();
if ($div.is(":visible")) {
$(this).text('more');
$arrow.removeClass('arrow-up-orange');
$arrow.addClass('arrow-down-orange');
$div.hide();
}
else {
$(this).text('less');
$arrow.addClass('arrow-up-orange');
$arrow.removeClass('arrow-down-orange');
$div.show();
}
}
function toggleRsvps() {
var sessionId = $(this).closest('tr[data-session-id]').attr('data-session-id');
// musicians
var $musicians = $(this).closest('table').next();
// latency indicators that need expanding / collapsing
var $extraLatencies = $("#latency-extra-" + sessionId);
var $arrow = $(this).next();
if ($musicians.is(":visible")) {
$(this).text('more');
$arrow.removeClass('arrow-up-orange');
$arrow.addClass('arrow-down-orange');
$musicians.hide();
$extraLatencies.hide();
}
else {
$(this).text('less');
$arrow.addClass('arrow-up-orange');
$arrow.removeClass('arrow-down-orange');
$musicians.show();
$extraLatencies.show();
}
}
this.renderActiveSession = renderActiveSession;
this.renderInactiveSession = renderInactiveSession;
return this;
}})(window,jQuery);