Merge branch 'vrfs1008' into develop

This commit is contained in:
Jonathan Kolyer 2014-01-14 02:31:48 -06:00
commit d2f71dd874
11 changed files with 306 additions and 185 deletions

View File

@ -7,81 +7,19 @@
var logger = context.JK.logger;
var rest = context.JK.Rest();
var realtimeMessaging = context.JK.JamServer;
var friendSelectorDialog = null;
var invitationDialog = null;
var autoComplete = null;
var userNames = [];
var userIds = [];
var userPhotoUrls = [];
var inviteMusiciansUtil = null;
var MAX_GENRES = 1;
var selectedFriendIds = {};
var sessionSettings = {};
function beforeShow(data) {
userNames = [];
userIds = [];
userPhotoUrls = [];
inviteMusiciansUtil.clearSelections();
context.JK.GenreSelectorHelper.render('#create-session-genre');
resetForm();
}
function afterShow(data) {
friendSelectorDialog.setCallback(friendSelectorCallback);
var friends = rest.getFriends({ id: context.JK.currentUserId })
.done(function(friends) {
$.each(friends, function() {
userNames.push(this.name);
userIds.push(this.id);
userPhotoUrls.push(this.photo_url);
});
var autoCompleteOptions = {
lookup: { suggestions: userNames, data: userIds },
onSelect: addInvitation
};
$('#friend-input').attr("placeholder", "Type a friend\'s name").prop('disabled', false);
if (!autoComplete) {
autoComplete = $('#friend-input').autocomplete(autoCompleteOptions);
}
else {
autoComplete.setOptions(autoCompleteOptions);
}
$(".autocomplete").width("150px");
})
.fail(function() {
$('#friend-input').attr("placeholder", "Unable to lookup friends");
app.ajaxError(arguments);
});
}
function friendSelectorCallback(newSelections) {
var keys = Object.keys(newSelections);
for (var i=0; i < keys.length; i++) {
addInvitation(newSelections[keys[i]].userName, newSelections[keys[i]].userId);
}
}
function addInvitation(value, data) {
if ($('#selected-friends div[user-id=' + data + ']').length === 0) {
var template = $('#template-added-invitation').html();
var invitationHtml = context.JK.fillTemplate(template, {userId: data, userName: value});
$('#selected-friends').append(invitationHtml);
$('#friend-input').select();
selectedFriendIds[data] = true;
}
else {
$('#friend-input').select();
context.alert('Invitation already exists for this musician.');
}
}
function removeInvitation(evt) {
delete selectedFriendIds[$(evt.currentTarget).parent().attr('user-id')];
$(evt.currentTarget).closest('.invitation').remove();
inviteMusiciansUtil.loadFriends();
}
function resetForm() {
@ -226,7 +164,7 @@
data: jsonData,
success: function(response) {
var newSessionId = response.id;
var invitationCount = createInvitations(newSessionId, function() {
var invitationCount = inviteMusiciansUtil.createInvitations(newSessionId, function() {
context.location = '#/session/' + newSessionId;
});
// Re-loading the session settings will cause the form to reset with the right stuff in it.
@ -248,49 +186,12 @@
return false;
}
function createInvitations(sessionId, onComplete) {
var callCount = 0;
var totalInvitations = 0;
$('#selected-friends .invitation').each(function(index, invitation) {
callCount++;
totalInvitations++;
var invite_id = $(invitation).attr('user-id');
var invite = {
music_session: sessionId,
receiver: invite_id
};
$.ajax({
type: "POST",
url: "/api/invitations",
data: invite
}).done(function(response) {
callCount--;
}).fail(app.ajaxError);
});
// TODO - this is the second time I've used this pattern.
// refactor to make a common utility for this.
function checker() {
if (callCount === 0) {
onComplete();
} else {
context.setTimeout(checker, 10);
}
}
checker();
return totalInvitations;
}
function events() {
$('#create-session-form').on('submit', submitForm);
$('#btn-create-session').on("click", submitForm);
$('#selected-friends').on("click", ".invitation a", removeInvitation);
$('#musician-access').change(toggleMusicianAccess);
$('#fan-access').change(toggleFanAccess);
$('#btn-choose-friends').click(function() {
friendSelectorDialog.showDialog(selectedFriendIds);
});
$('div[layout-id="createSession"] .btn-email-invitation').click(function() {
invitationDialog.showEmailDialog();
});
@ -373,38 +274,10 @@
});
}
function searchFriends(query) {
if (query.length < 2) {
$('#friend-search-results').empty();
return;
}
var url = "/api/search?query=" + query + "&userId=" + context.JK.currentUserId;
$.ajax({
type: "GET",
url: url,
success: friendSearchComplete
});
}
function friendSearchComplete(response) {
// reset search results each time
$('#friend-search-results').empty();
// loop through each
$.each(response.friends, function() {
// only show friends who are musicians
if (this.musician === true) {
var template = $('#template-friend-search-results').html();
var searchResultHtml = context.JK.fillTemplate(template, {userId: this.id, name: this.first_name + ' ' + this.last_name});
$('#friend-search-results').append(searchResultHtml);
$('#friend-search-results').attr('style', 'display:block');
}
});
}
function initialize(invitationDialogInstance, friendSelectorDialogInstance) {
friendSelectorDialog = friendSelectorDialogInstance;
function initialize(invitationDialogInstance, inviteMusiciansUtilInstance) {
invitationDialog = invitationDialogInstance;
inviteMusiciansUtil = inviteMusiciansUtilInstance;
inviteMusiciansUtil.inviteSessionCreate('#create-session-invite-musicians');
events();
loadBands();
loadSessionSettings();
@ -419,8 +292,6 @@
this.submitForm = submitForm;
this.validateForm = validateForm;
this.loadBands = loadBands;
this.searchFriends = searchFriends;
this.addInvitation = addInvitation;
return this;
};

View File

@ -0,0 +1,208 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.InviteMusiciansUtil = function(app) {
var logger = context.JK.logger;
var userNames = [];
var userIds = [];
var userPhotoUrls = [];
var friendSelectorDialog = null;
var invitedFriends = [];
var existingInvites = [];
var autoComplete = null;
var rest = context.JK.Rest();
var inviteAction = 'create'; // create/update
var updateSessionID = null;
this.inviteSessionCreate = function(elemSelector) {
inviteAction = 'create';
_appendFriendSelector($(elemSelector));
};
this.inviteSessionUpdate = function(elemSelector, sessionId) {
this.clearSelections();
updateSessionID = sessionId;
friendSelectorDialog.setCallback(friendSelectorCallback);
inviteAction = 'update';
if (0 == $(elemSelector + ' .friendbox').length) {
_appendFriendSelector($(elemSelector));
$('#btn-save-invites').click(function() {
createInvitations(updateSessionID);
});
}
$.ajax({
ajax: false,
url: "/api/invitations",
data: { session_id: sessionId, sender: context.JK.currentUserId }
}).done(function(response) {
response.map(function(item) {
var dd = item['receiver'];
existingInvites.push(dd.id);
addInvitation(dd.name, dd.id);
});
}).fail(app.ajaxError);
}
this.clearSelections = function() {
userNames = [];
userIds = [];
userPhotoUrls = [];
invitedFriends = [];
existingInvites = [];
updateSessionID = null;
$('.selected-friends').empty();
};
this.loadFriends = function() {
friendSelectorDialog.setCallback(friendSelectorCallback);
var friends = rest.getFriends({ id: context.JK.currentUserId })
.done(function(friends) {
$.each(friends, function() {
userNames.push(this.name);
userIds.push(this.id);
userPhotoUrls.push(this.photo_url);
});
var autoCompleteOptions = {
lookup: { suggestions: userNames, data: userIds },
onSelect: addInvitation
};
$('#friend-input').attr("placeholder", "Type a friend\'s name").prop('disabled', false);
if (!autoComplete) {
autoComplete = $('#friend-input').autocomplete(autoCompleteOptions);
}
else {
autoComplete.setOptions(autoCompleteOptions);
}
$(".autocomplete").width("150px");
})
.fail(function() {
$('#friend-input').attr("placeholder", "Unable to lookup friends");
app.ajaxError(arguments);
});
}
function friendSelectorCallback(newSelections) {
var keys = Object.keys(newSelections);
for (var i=0; i < keys.length; i++) {
var dd = newSelections[keys[i]];
addInvitation(dd.userName, dd.userId);
}
}
function _inviteExists(userID) {
return 0 <= existingInvites.indexOf(userID);
}
function addInvitation(value, data) {
if (0 > invitedFriends.indexOf(data)) {
var template = $('#template-added-invitation').html();
var imgStyle = _inviteExists(data) ? 'display:none' : '';
var invitationHtml = context.JK.fillTemplate(template,
{userId: data,
userName: value,
imageStyle: imgStyle});
$('.selected-friends').append(invitationHtml);
$('#friend-input').select();
invitedFriends.push(data);
} else {
$('#friend-input').select();
context.alert('Invitation already exists for this musician.');
}
}
function removeInvitation(evt) {
var idx = invitedFriends.indexOf($(evt.currentTarget).parent().attr('user-id'));
if (0 <= idx) invitedFriends.splice(idx, 1);
$(evt.currentTarget).closest('.invitation').remove();
}
function createInvitations(sessionId, onComplete) {
var callCount = 0;
var totalInvitations = invitedFriends.length - existingInvites.length;
invitedFriends.map(function(invite_id) {
if (!_inviteExists(invite_id)) {
callCount++;
var invite = {
music_session: sessionId,
receiver: invite_id
};
$.ajax({
type: "POST",
url: "/api/invitations",
data: invite
}).done(function(response) {
callCount--;
}).fail(app.ajaxError);
}
});
// TODO - this is the second time I've used this pattern.
// refactor to make a common utility for this.
function checker() {
callCount === 0 ? onComplete() : context.setTimeout(checker, 10);
}
if (onComplete) checker();
return totalInvitations;
}
this.createInvitations = createInvitations;
function searchFriends(query) {
if (query.length < 2) {
$('#friend-search-results').empty();
return;
}
var url = "/api/search?query=" + query + "&userId=" + context.JK.currentUserId;
$.ajax({
type: "GET",
url: url,
success: friendSearchComplete
});
}
function friendSearchComplete(response) {
// reset search results each time
$('#friend-search-results').empty();
// loop through each
$.each(response.friends, function() {
// only show friends who are musicians
if (this.musician === true) {
var template = $('#template-friend-search-results').html();
var searchResultHtml = context.JK.fillTemplate(template, {userId: this.id, name: this.first_name + ' ' + this.last_name});
$('#friend-search-results').append(searchResultHtml);
$('#friend-search-results').attr('style', 'display:block');
}
});
}
function _friendSelectorHTML() {
return context.JK.fillTemplate($('#template-session-invite-musicians').html(),
{choose_friends_id: 'btn-choose-friends-'+inviteAction,
selected_friends_id: 'selected-friends-'+inviteAction});
}
function _appendFriendSelector(elemSelector) {
elemSelector.append(_friendSelectorHTML());
$('#selected-friends-'+inviteAction).on("click", ".invitation a", removeInvitation);
$('#btn-choose-friends-'+inviteAction).click(function(){
var obj = {};
invitedFriends.map(function(uid) { obj[uid] = true; });
friendSelectorDialog.showDialog(obj);
});
};
this.initialize = function(friendSelectorDialogInstance) {
friendSelectorDialog = friendSelectorDialogInstance;
};
return this;
};
})(window,jQuery);

View File

@ -14,6 +14,8 @@
var addNewGearDialog;
var localRecordingsDialog = null;
var recordingFinishedDialog = null;
var friendSelectorDialog = null;
var inviteMusiciansUtil = null;
var screenActive = false;
var currentMixerRangeMin = null;
var currentMixerRangeMax = null;
@ -1302,12 +1304,17 @@
}
}
function inviteMusicians() {
inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', sessionId);
}
function events() {
$('#session-resync').on('click', sessionResync);
$('#session-contents').on("click", '[action="delete"]', deleteSession);
$('#tracks').on('click', 'div[control="mute"]', toggleMute);
$('#recording-start-stop').on('click', startStopRecording);
$('#open-a-recording').on('click', openRecording);
$('#session-invite-musicians').on('click', inviteMusicians);
$('#track-settings').click(function() {
configureTrackDialog.showVoiceChatPanel(true);
configureTrackDialog.showMusicAudioPanel(true);
@ -1319,9 +1326,10 @@
.on('change-position', onChangePlayPosition);
}
this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance) {
this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance, inviteMusiciansUtilInstance) {
localRecordingsDialog = localRecordingsDialogInstance;
recordingFinishedDialog = recordingFinishedDialogInstance;
inviteMusiciansUtil = inviteMusiciansUtilInstance;
context.jamClient.SetVURefreshRate(150);
playbackControls = new context.JK.PlaybackControls($('.session-recordings .recording-controls'));
events();

View File

@ -207,7 +207,6 @@
.friendbox {
padding:5px;
width:100%;
height:60px;
}

View File

@ -11,7 +11,7 @@
}
}
#btn-choose-friends {
.btn-choose-friends {
margin:0;
}
#create-session-genre select, #create-session-band select {

View File

@ -716,3 +716,6 @@ table.vu td {
}
#update-session-invite-musicians {
margin: 10px;
}

View File

@ -14,8 +14,11 @@ class ApiInvitationsController < ApiController
if current_user.id != sender_id
raise PermissionError, "You can only ask for your own sent invitations"
end
@invitations = Invitation.where(:sender_id => current_user.id)
if session_id = params[:session_id]
@invitations = Invitation.where(:sender_id => sender_id, :music_session_id => session_id)
else
@invitations = Invitation.where(:sender_id => current_user.id)
end
elsif !receiver_id.nil?
if current_user.id != receiver_id
raise PermissionError, "You can only ask for your own received invitations"
@ -34,25 +37,33 @@ class ApiInvitationsController < ApiController
sender = current_user
join_request = JoinRequest.find(params[:join_request]) unless params[:join_request].nil?
@invitation = Invitation.new
@invitation.music_session = music_session
@invitation.sender = sender
@invitation.receiver = receiver
@invitation.join_request = join_request
@invitation.save
unless @invitation.errors.any?
User.save_session_settings(current_user, music_session)
# send notification
Notification.send_session_invitation(receiver, current_user, music_session.id)
@invitation = Invitation.limit(1)
.where(:receiver_id => params[:receiver],
:sender_id => current_user.id,
:music_session_id => params[:music_session])
.first
if @invitation
respond_with @invitation, :responder => ApiResponder, :location => api_invitation_detail_url(@invitation)
else
# we have to do this because api_invitation_detail_url will fail with a bad @invitation
response.status = :unprocessable_entity
respond_with @invitation
@invitation = Invitation.new
@invitation.music_session = music_session
@invitation.sender = sender
@invitation.receiver = receiver
@invitation.join_request = join_request
@invitation.save
unless @invitation.errors.any?
User.save_session_settings(current_user, music_session)
# send notification
Notification.send_session_invitation(receiver, current_user, music_session.id)
respond_with @invitation, :responder => ApiResponder, :location => api_invitation_detail_url(@invitation)
else
# we have to do this because api_invitation_detail_url will fail with a bad @invitation
response.status = :unprocessable_entity
respond_with @invitation
end
end
end

View File

@ -84,22 +84,7 @@
<h2>invite musicians</h2>
<br />
<div>
<div class="right" layout-link="select-friends">
<a href="#" id="btn-choose-friends" class="button-grey">CHOOSE FRIENDS</a>
</div>
<div style="margin-right:140px;">
Start typing friends' names or:
</div>
<div class="clearall"></div>
</div>
<br />
<!-- friend invitation box -->
<div class="friendbox">
<div id="selected-friends"></div>
<input id="friend-input" type="text" placeholder="Looking up friends..." />
</div>
<div id="create-session-invite-musicians"></div>
<div class="mt35 mb15">
Invite friends and contacts to join you on JamKazam from:
@ -171,13 +156,6 @@
</div>
</div>
<!-- Added Invitation Template -->
<script type="text/template" id="template-added-invitation">
<div user-id="{userId}" class="invitation">{userName}
<a><%= image_tag "shared/icon_delete_sm.png", :size => "13x13" %></a>
</div>
</script>
<!-- Band option template -->
<script type="text/template" id="template-band-option">
<option value="{value}">{label}</option>

View File

@ -0,0 +1,38 @@
<!-- Session Update Invite Musicians Dialog -->
<div class="dialog invitemusicians-overlay" layout="dialog" layout-id="select-invites">
<div class="invitemusicians-inner" id="update-session-invite-musicians">
</div>
<br clear="all" />
<div class="left">
<a id="btn-cancel-invites" layout-action="close" class="button-grey">CANCEL</a>&nbsp;
</div>
<div class="right">
<a id="btn-save-invites" layout-action="close" class="button-orange">INVITE</a>
</div>
</div>
<!-- invite musician friend selector template -->
<script type="text/template" id="template-session-invite-musicians">
<div>
<div class="right" layout-link="select-friends">
<a href="#" class="btn-choose-friends button-grey" id="{choose_friends_id}">CHOOSE FRIENDS</a>
</div>
<div style="margin-right:140px;">
Start typing friends' names or:
</div>
<div class="clearall"></div>
</div>
<br />
<!-- friend invitation box -->
<div class="friendbox">
<div class="selected-friends" id="{selected_friends_id}"></div>
<input id="friend-input" type="text" placeholder="Looking up friends..." />
</div>
</script>
<!-- Added Invitation Template -->
<script type="text/template" id="template-added-invitation">
<div user-id="{userId}" class="invitation">{userName}
<a><%= image_tag "shared/icon_delete_sm.png", :size => "13x13", :style => "{imageStyle}" %></a>
</div>
</script>

View File

@ -69,8 +69,8 @@
<!-- live tracks -->
<div class="session-livetracks">
<h2>live tracks</h2>
<div class="session-add">
<a>
<div class="session-add" layout-link="select-invites">
<a href="#" id="session-invite-musicians">
<%= image_tag "content/icon_add.png", {:width => 19, :height => 19, :align => "texttop"} %>&nbsp;&nbsp;Invite Musicians
</a>
</div>
@ -178,3 +178,4 @@
<script type="text/template" id="template-genre-option">
<option value="{value}">{label}</option>
</script>

View File

@ -35,6 +35,7 @@
<%= render "account_profile_avatar" %>
<%= render "account_audio_profile" %>
<%= render "invitationDialog" %>
<%= render "inviteMusicians" %>
<%= render "whatsNextDialog" %>
<%= render "recordingFinishedDialog" %>
<%= render "localRecordingsDialog" %>
@ -105,6 +106,9 @@
var friendSelectorDialog = new JK.FriendSelectorDialog(JK.app);
friendSelectorDialog.initialize();
var inviteMusiciansUtil = new JK.InviteMusiciansUtil(JK.app);
inviteMusiciansUtil.initialize(friendSelectorDialog);
var userDropdown = new JK.UserDropdown(JK.app);
JK.UserDropdown = userDropdown;
userDropdown.initialize(invitationDialog);
@ -148,7 +152,7 @@
JK.Banner.initialize();
var createSessionScreen = new JK.CreateSessionScreen(JK.app);
createSessionScreen.initialize(invitationDialog, friendSelectorDialog);
createSessionScreen.initialize(invitationDialog, inviteMusiciansUtil);
var bandSetupScreen = new JK.BandSetupScreen(JK.app);
bandSetupScreen.initialize(invitationDialog, friendSelectorDialog);
@ -170,7 +174,7 @@
findBandScreen.initialize();
var sessionScreen = new JK.SessionScreen(JK.app);
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog);
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, inviteMusiciansUtil);
var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen);
sessionSettingsDialog.initialize();