Merge branch 'develop' of https://bitbucket.org/jamkazam/jam-cloud into develop

This commit is contained in:
Bert Owen 2014-07-02 15:57:55 +02:00
commit 421d183ba3
94 changed files with 1385 additions and 876 deletions

View File

@ -16,6 +16,6 @@ class MusicNotationUploader < CarrierWave::Uploader::Base
end
def extension_white_list
%w(pdf png jpg jpeg git xml mxl txt)
%w(pdf png jpg jpeg gif xml mxl txt)
end
end

View File

@ -29,7 +29,7 @@ module JamRuby
start = start.to_i
time_range = params[:time_range]
time_range ||= 'month'
time_range ||= 'all'
raise "not valid time_range #{time_range}" unless TIME_RANGES.has_key?(time_range)
type_filter = params[:type]

View File

@ -226,7 +226,6 @@ module JamRuby
def self.scheduled user
query = MusicSession.where("music_sessions.user_id = '#{user.id}'")
query = query.where("music_sessions.scheduled_start IS NOT NULL AND music_sessions.scheduled_start < NOW() + '12 hour'::INTERVAL")
query = query.where("music_sessions.scheduled_start > NOW() - '12 hour'::INTERVAL")
query = query.where("music_session_id IS NULL")
query = query.order("music_sessions.scheduled_start ASC")
@ -394,7 +393,7 @@ module JamRuby
end
def legal_policy_url
# TODO: move to DB or config file
# TODO: move to DB or config file or helper
case legal_policy
when "standard"
return "http://www.jamkazam.com/session-legal-policies/standard"
@ -443,6 +442,10 @@ module JamRuby
end
end
def scheduled_end_time
end
def timezone_description
self.get_timezone.to_s
end

View File

@ -1,7 +1,5 @@
module JamRuby
class ShareToken < ActiveRecord::Base
belongs_to :shareable, :polymorphic => true
end
end

View File

@ -150,7 +150,7 @@ describe Feed do
claimed_recording1.recording.feed.created_at = 32.days.ago
claimed_recording1.recording.feed.save!
feeds, start = Feed.index(user1, :type => 'recording')
feeds, start = Feed.index(user1, :type => 'recording', time_range: 'month')
feeds.length.should == 0
end

View File

@ -209,6 +209,36 @@ describe MusicSession do
end
end
describe "scheduled" do
it "excludes based on time-range" do
session = FactoryGirl.create(:music_session, scheduled_start: Time.now)
sessions = MusicSession.scheduled(session.creator)
sessions.length.should == 1
session.scheduled_start = 11.hours.ago
session.save!
sessions = MusicSession.scheduled(session.creator)
sessions.length.should == 1
session.scheduled_start = 13.hours.ago
session.save!
sessions = MusicSession.scheduled(session.creator)
sessions.length.should == 0
session.scheduled_start = 13.hours.from_now
session.save!
sessions = MusicSession.scheduled(session.creator)
sessions.length.should == 1
session.scheduled_start = 300.days.from_now
session.save!
sessions = MusicSession.scheduled(session.creator)
sessions.length.should == 1
end
end
def sms(user, params)
ActiveRecord::Base.transaction do
return MusicSession.sms_index(user, params)

View File

@ -29,7 +29,6 @@
function renderAudioProfileScreen() {
if (!gon.isNativeClient) {
// app.layout.showDialog('launch-app-dialog', {d1: 'gear'});
context.JK.guardAgainstBrowser(app, {d1: 'gear'});
}
else {

View File

@ -114,11 +114,13 @@
if(options.buttons) {
var $buttons = $banner.find('.buttons')
context._.each(options.buttons, function(button) {
context._.each(options.buttons, function(button, i) {
if(!button.name) throw "button.name must be specified";
if(!button.click) throw "button.click must be specified";
var $btn = $('<a class="button-orange user-btn">' + button.name + '</a>');
var buttonStyle = options.buttons.length == i + 1 ? 'button-orange' : 'button-grey';
var $btn = $('<a class="' + buttonStyle + ' user-btn">' + button.name + '</a>');
$btn.click(function() {
button.click();
hide();

View File

@ -153,7 +153,9 @@
.css('min-width', '')
}
function loadChannels(forceInputsToUnassign) {
// inputChannelFilter is an optional argument that is used by the Gear Wizard.
// basically, if an input channel isn't in there, it's not going to be displayed
function loadChannels(forceInputsToUnassign, inputChannelFilter) {
var musicPorts = jamClient.FTUEGetChannels();
$unassignedInputsHolder.empty();
@ -172,6 +174,12 @@
//inputChannels = inputChannels.concat(inputChannels.concat(inputChannels.concat(inputChannels)))
context._.each(inputChannels, function (inputChannel) {
if(inputChannelFilter && !(inputChannelFilter.indexOf(inputChannel.id) > -1)) {
// skipping input channel because it's not in the filter
return;
}
var $channel = $(context._.template($templateAssignablePort.html(), inputChannel, { variable: 'data' }));
$channel.hover(
@ -431,8 +439,8 @@
return saved;
}
function reset(forceInputsToUnassign) {
loadChannels(forceInputsToUnassign);
function reset(forceInputsToUnassign, inputChannelFilter) {
loadChannels(forceInputsToUnassign, inputChannelFilter);
loadTrackInstruments(forceInputsToUnassign);
}

View File

@ -774,6 +774,10 @@
logger.debug("SessionLiveBroadcastStop requested");
}
function RegisterQuitCallback() {
}
// Javascript Bridge seems to camel-case
// Set the instance functions:
this.AbortRecording = AbortRecording;
@ -804,6 +808,7 @@
this.IsMyNetworkWireless = IsMyNetworkWireless;
this.SetNetworkTestScore = SetNetworkTestScore;
this.GetNetworkTestScore = GetNetworkTestScore;
this.RegisterQuitCallback = RegisterQuitCallback;
this.connected = true;
// FTUE (round 3)

View File

@ -145,7 +145,7 @@
}
function beforeShow(data) {
context.JK.GenreSelectorHelper.render('#find-session-genre');
context.JK.GenreSelectorHelper.render('#find-session-genre', 'Any Genre');
}
function afterShow(data) {

View File

@ -70,7 +70,6 @@
newSelections = {};
loadFriends();
// HACK TO OVERRIDE PADDING SET SOMEWHERE ELSE
$('.choosefriends-overlay').css({"padding":"8px"});
}
this.initialize = function() {

View File

@ -27,9 +27,12 @@
});
}
function render(parentSelector) {
function render(parentSelector, notSelectedString) {
if(!notSelectedString) {
notSelectedString = 'Unspecified'
}
$('select', parentSelector).empty();
$('select', parentSelector).append('<option value="">Unspecified</option>');
$('select', parentSelector).append('<option value="">' + notSelectedString + '</option>');
var template = $('#template-genre-option').html();
$.each(_genres, function(index, value) {
// value will be a dictionary entry from _genres:

View File

@ -28,7 +28,9 @@
};
context.JK.EVENTS = {
DIALOG_CLOSED : 'dialog_closed'
DIALOG_CLOSED : 'dialog_closed',
SHOW_SIGNUP : 'show_signup',
SHOW_SIGNIN : 'show_signin'
}
context.JK.ALERT_NAMES = {

View File

@ -215,6 +215,16 @@
});
}
function updateRsvpRequest(rsvpRequestId, responses) {
return $.ajax({
url: '/api/rsvp_requests/' + rsvpRequestId,
type: "POST",
data : responses,
dataType : 'json',
contentType: 'application/json'
});
}
function cancelRsvpRequest(sessionId, rsvpRequestId, cancelAll) {
var cancel = "yes";
if (cancelAll) {
@ -1226,6 +1236,7 @@
this.addSessionLike = addSessionLike;
this.getRsvpRequests = getRsvpRequests;
this.submitRsvpRequest = submitRsvpRequest;
this.updateRsvpRequest = updateRsvpRequest;
this.cancelRsvpRequest = cancelRsvpRequest;
this.getOpenSessionSlots = getOpenSessionSlots;
this.addRecordingComment = addRecordingComment;

View File

@ -1,13 +1,35 @@
//= require jquery
//= require jquery.monkeypatch
//= require jquery_ujs
//= require jquery.ui.draggable
//= require jquery.queryparams
//= require jquery.hoverIntent
//= require jquery.cookie
//= require jquery.clipboard
//= require jquery.easydropdown
//= require jquery.carousel-1.1
//= require jquery.mousewheel-3.1.9
//= require jquery.timeago
//= require jquery.dotdotdot
//= require jquery.listenbroadcast
//= require jquery.listenRecording
//= require jquery.browser
//= require jquery.custom-protocol
//= require jquery.ba-bbq
//= require AAA_Log
//= require AAC_underscore
//= require globals
//= require AAB_message_factory
//= require facebook_helper
//= require layout
//= require jamkazam
//= require utils
//= require ui_helper
//= require ga
//= require jam_rest
//= require web/signup_helper
//= require web/signin_helper
//= require web/signin
//= require landing/init
//= require landing/signup
//= require shareDialog

View File

@ -45,7 +45,9 @@
$.ajax('/api/regions', {
data : { country: selected_country },
dataType : 'json'
}).done(regions_done).fail(regions_fail).always(function() { region_select.attr('disabled', false).easyDropDown('enable') })
}).done(regions_done)
.fail(function(err) { regions_done([]) })
.always(function() { region_select.attr('disabled', false).easyDropDown('enable') })
}
})
@ -56,16 +58,13 @@
$(data.regions).each(function(index, item) {
var option = $('<option></option>');
option.text(item);
option.val(item);
option.text(item['name']);
option.val(item['region']);
region_select.append(option)
})
context.JK.dropdown(region_select);
}
function regions_fail() {
alert("something went wrong in looking up regions")
cities_done([]);
}
region_select.change(function() {
@ -80,7 +79,12 @@
$.ajax('/api/cities', {
data : { country: selected_country, region: selected_region },
dataType : 'json'
}).done(cities_done).fail(cities_fail).always(function() { city_select.attr('disabled', false).easyDropDown('enable') })
})
.done(cities_done)
.error(function(err) {
cities_done([]);
})
.always(function() { city_select.attr('disabled', false).easyDropDown('enable') })
}
})
@ -97,10 +101,6 @@
context.JK.dropdown(city_select);
}
function cities_fail() {
alert("something went wrong in looking up cities")
}
}
signup.handle_completion_submit = function handle_completion_submit() {

View File

@ -60,7 +60,6 @@
function handleBack() {
app.layout.closeDialog('launch-app-dialog');
window.location = '/client#/home';
return false;
}

View File

@ -20,6 +20,10 @@
unfreezeInteractions();
}
function networkTestCancel() {
unfreezeInteractions();
}
function networkTestStart() {
freezeInteractions();
}
@ -47,10 +51,10 @@
return false;
})
$btnHelp.on('click', function(e) {
/** $btnHelp.on('click', function(e) {
context.JK.Banner.showAlert('No help is yet available for the network test.');
return false;
})
})*/
}
function beforeShow() {
@ -81,6 +85,7 @@
$(networkTest)
.on(networkTest.NETWORK_TEST_DONE, networkTestDone)
.on(networkTest.NETWORK_TEST_FAIL, networkTestFail)
.on(networkTest.NETWORK_TEST_CANCEL, networkTestCancel)
.on(networkTest.NETWORK_TEST_START, networkTestStart)
events();

View File

@ -6,12 +6,12 @@
context.JK.NetworkTest = function (app) {
var NETWORK_TEST_TYPES = {
RestPhase : 0,
PktTest100NormalLatency : 1,
PktTest200MediumLatency : 2,
PktTest400LowLatency : 3,
PktTestRateSweep : 4,
RcvOnly : 5
RestPhase: 0,
PktTest100NormalLatency: 1,
PktTest200MediumLatency: 2,
PktTest400LowLatency: 3,
PktTestRateSweep: 4,
RcvOnly: 5
}
var STARTING_NUM_CLIENTS = 4;
var PAYLOAD_SIZE = 100;
@ -37,11 +37,13 @@
var $subscore = null;
var $watchVideo = null;
var backendGuardTimeout = null;
var primeGuardTimeout = null;
var primeDeferred = null;
var serverClientId = '';
var scoring = false;
var numClientsToTest = STARTING_NUM_CLIENTS;
var testSummary = {attempts : [], final:null}
var testSummary = {attempts: [], final: null}
var $self = $(this);
var scoringZoneWidth = 100;//px
var inGearWizard = false;
@ -52,36 +54,57 @@
var lastNetworkFailure = null;
var bandwidthSamples = [];
var NETWORK_TEST_START = 'network_test.start';
var NETWORK_TEST_DONE = 'network_test.done';
var NETWORK_TEST_FAIL = 'network_test.fail';
var NETWORK_TEST_START = 'network_test.start';
var NETWORK_TEST_DONE = 'network_test.done';
var NETWORK_TEST_FAIL = 'network_test.fail';
var NETWORK_TEST_CANCEL = 'network_test.cancel';
function createSuccessCallbackName() {
if(inGearWizard) {
return TEST_SUCCESS_CALLBACK + 'ForGearWizard';
function createSuccessCallbackName(priming) {
if (priming) {
if (inGearWizard) {
return TEST_SUCCESS_CALLBACK + 'ForPumpPrimingGW';
}
else {
return TEST_SUCCESS_CALLBACK + 'ForPumpPrimingDialog';
}
}
else {
return TEST_SUCCESS_CALLBACK + 'ForDialog';
if (inGearWizard) {
return TEST_SUCCESS_CALLBACK + 'ForGearWizard';
}
else {
return TEST_SUCCESS_CALLBACK + 'ForDialog';
}
}
}
function createTimeoutCallbackName() {
if(inGearWizard) {
return TEST_TIMEOUT_CALLBACK + 'ForGearWizard';
function createTimeoutCallbackName(priming) {
if (priming) {
if (inGearWizard) {
return TEST_TIMEOUT_CALLBACK + 'ForPumpPrimingGW';
}
else {
return TEST_TIMEOUT_CALLBACK + 'ForPumpPrimingDialog';
}
}
else {
return TEST_TIMEOUT_CALLBACK + 'ForDialog';
if (inGearWizard) {
return TEST_TIMEOUT_CALLBACK + 'ForGearWizard';
}
else {
return TEST_TIMEOUT_CALLBACK + 'ForDialog';
}
}
}
// this averages bandwidthSamples; this method is meant just for GA data
function avgBandwidth(num_others) {
if(bandwidthSamples.length == 0) {
if (bandwidthSamples.length == 0) {
return 0;
}
else {
var total = 0;
context._.each(bandwidthSamples, function(sample) {
context._.each(bandwidthSamples, function (sample) {
total += (sample * num_others * 400 * (100 + 28)); // sample is a percentage of 400. So sample * 400 gives us how many packets/sec. 100 is payload; 28 is UDP+ETHERNET overhead, to give us bandwidth
})
return total / bandwidthSamples.length;
@ -98,7 +121,7 @@
serverClientId = '';
scoring = false;
numClientsToTest = STARTING_NUM_CLIENTS;
testSummary = {attempts : []};
testSummary = {attempts: []};
configureStartButton();
$scoredClients.empty();
$testResults.removeClass('good acceptable bad testing');
@ -125,12 +148,12 @@
function postDiagnostic() {
rest.createDiagnostic({
type: 'NETWORK_TEST_RESULT',
data: {client_type: context.JK.clientType(), client_id: context.JK.JamServer.clientID, summary:testSummary}
data: {client_type: context.JK.clientType(), client_id: context.JK.JamServer.clientID, summary: testSummary}
});
}
function appendContextualStatement() {
if(inGearWizard) {
if (inGearWizard) {
return "You can skip this step for now."
}
else {
@ -143,37 +166,37 @@
}
function storeLastNetworkFailure(reason, data) {
if(!trackedPass) {
lastNetworkFailure = {reason:reason, data:data};
if (!trackedPass) {
lastNetworkFailure = {reason: reason, data: data};
}
}
function testFinished() {
var attempt = getCurrentAttempt();
if(!testSummary.final) {
testSummary.final = {reason : attempt.reason};
if (!testSummary.final) {
testSummary.final = {reason: attempt.reason};
}
var reason = testSummary.final.reason;
var success = false;
if(reason == "success") {
if (reason == "success") {
renderStopTest(attempt.num_clients, "Your router and Internet service will support sessions of up to " + attempt.num_clients + " JamKazam musicians.")
testedSuccessfully = true;
if(!testSummary.final.num_clients) {
if (!testSummary.final.num_clients) {
testSummary.final.num_clients = attempt.num_clients;
}
// context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before
if(inGearWizard || context.jamClient.GetNetworkTestScore() == 0) {
if (inGearWizard || context.jamClient.GetNetworkTestScore() == 0) {
trackedPass = true;
lastNetworkFailure = null;
context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients);
}
context.jamClient.SetNetworkTestScore(attempt.num_clients);
if(testSummary.final.num_clients == 2) {
if (testSummary.final.num_clients == 2) {
$testResults.addClass('acceptable');
}
else {
@ -181,63 +204,63 @@
}
success = true;
}
else if(reason == "minimum_client_threshold") {
else if (reason == "minimum_client_threshold") {
context.jamClient.SetNetworkTestScore(0);
renderStopTest('', "We're sorry, but your router and Internet service will not effectively support JamKazam sessions. Please click the HELP button for more information.")
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1));
}
else if(reason == "unreachable" || reason == "no-transmit") {
else if (reason == "unreachable" || reason == "no-transmit") {
context.jamClient.SetNetworkTestScore(0);
renderStopTest('', "We're sorry, but your router will not support JamKazam in its current configuration. Please click the HELP button for more information.");
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients);
}
else if(reason == "internal_error") {
else if (reason == "internal_error") {
context.JK.alertSupportedNeeded("The JamKazam client software had an unexpected problem while scoring your Internet connection.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == "remote_peer_cant_test") {
else if (reason == "remote_peer_cant_test") {
context.JK.alertSupportedNeeded("The JamKazam service is experiencing technical difficulties.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == "server_comm_timeout") {
else if (reason == "server_comm_timeout") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Communication with the JamKazam network service has timed out." + appendContextualStatement());
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == 'backend_gone') {
else if (reason == 'backend_gone') {
context.JK.alertSupportedNeeded("The JamKazam client is experiencing technical difficulties.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == "invalid_response") {
else if (reason == "invalid_response") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("The JamKazam client software had an unexpected problem while scoring your Internet connection.<br/><br/>Reason: " + attempt.backend_data.reason + '.');
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == 'no_servers') {
else if (reason == 'no_servers') {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("No network test servers are available." + appendContextualStatement());
renderStopTest('', '');
testedSuccessfully = true;
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == 'no_network') {
else if (reason == 'no_network') {
context.JK.Banner.showAlert("Please try again later. Your network appears down.");
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.noNetwork);
}
else if(reason == "rest_api_error") {
else if (reason == "rest_api_error") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Unable to acquire a network test server." + appendContextualStatement());
testedSuccessfully = true;
renderStopTest('', '');
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
}
else if(reason == "timeout") {
else if (reason == "timeout") {
gearUtils.skipNetworkTest();
context.JK.alertSupportedNeeded("Communication with the JamKazam network service timed out." + appendContextualStatement());
testedSuccessfully = true;
@ -256,7 +279,7 @@
configureStartButton();
postDiagnostic();
if(success) {
if (success) {
$self.triggerHandler(NETWORK_TEST_DONE)
}
else {
@ -268,6 +291,12 @@
return testSummary.attempts[testSummary.attempts.length - 1];
}
function primeTimedOut() {
logger.warn("backend never completed priming pump phase");
scoring = false;
primeDeferred.reject();
}
function backendTimedOut() {
testSummary.final = {reason: 'backend_gone'}
testFinished();
@ -278,15 +307,31 @@
}
function clearBackendGuard() {
if(backendGuardTimeout) {
if (backendGuardTimeout) {
clearTimeout(backendGuardTimeout);
backendGuardTimeout = null;
}
}
function clearPrimeGuard() {
if (primeGuardTimeout) {
clearTimeout(primeGuardTimeout);
primeGuardTimeout = null;
}
}
function setPrimeGuard() {
clearPrimeGuard();
primeGuardTimeout = setTimeout(function () {
primeTimedOut()
}, 2 * 1000);
}
function setBackendGuard() {
clearBackendGuard();
backendGuardTimeout = setTimeout(function(){backendTimedOut()}, (gon.ftue_network_test_duration + 1) * 1000);
backendGuardTimeout = setTimeout(function () {
backendTimedOut()
}, (gon.ftue_network_test_duration + 1) * 1000);
}
function attemptTestPass() {
@ -308,7 +353,7 @@
setBackendGuard();
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(), createTimeoutCallbackName(),
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false),
NETWORK_TEST_TYPES.PktTest400LowLatency,
gon.ftue_network_test_duration,
numClientsToTest,
@ -316,53 +361,78 @@
}
function startNetworkTest(checkWireless) {
// you have to score a little to 'prime' the logic to know whether it's on wireless or not
function primePump() {
scoring = true;
primeDeferred = new $.Deferred();
if(scoring) return false;
setPrimeGuard();
if(checkWireless) {
// check if on Wifi 1st
var isWireless = context.jamClient.IsMyNetworkWireless();
if(isWireless == -1) {
logger.warn("unable to determine if the user is on wireless or not for network test. skipping prompt.")
}
else if(isWireless == 1) {
context.JK.Banner.showAlert({buttons: [
{name: 'RUN NETWORK TEST ANYWAY', click: function() {startNetworkTest(false)}},
{name: 'CANCEL', click: function() {}}],
html: "<p>It appears that your computer is connected to your network using WiFi.</p>" +
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
"We recommend using a wired Ethernet connection from your computer to your router. " +
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
return false;
}
}
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(true), createTimeoutCallbackName(true),
NETWORK_TEST_TYPES.PktTest400LowLatency,
1, // minimum time needed to prime pump
2,
PAYLOAD_SIZE);
return primeDeferred;
}
function prepareNetworkTest() {
if (scoring) return false;
logger.info("starting network test");
resetTestState();
scoring = true;
$self.triggerHandler(NETWORK_TEST_START);
renderStartTest();
rest.getLatencyTester()
.done(function(response) {
.done(function (response) {
// ensure there are no tests ongoing
serverClientId = response.client_id;
testSummary.serverClientId = serverClientId;
logger.info("beginning network test against client_id: " + serverClientId);
attemptTestPass();
primePump()
.done(function () {
// check if on Wifi 1st
var isWireless = context.jamClient.IsMyNetworkWireless();
if (isWireless == -1) {
logger.warn("unable to determine if the user is on wireless or not for network test. skipping prompt.")
}
else if (isWireless == 1) {
context.JK.Banner.showAlert({buttons: [
{name: 'CANCEL', click: function () {
scoring = false;
configureStartButton();
renderStopTest();
$self.triggerHandler(NETWORK_TEST_CANCEL)
}},
{name: 'RUN NETWORK TEST ANYWAY', click: function () {
attemptTestPass();;
}}
],
html: "<p>It appears that your computer is connected to your network using WiFi.</p>" +
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
"We recommend using a wired Ethernet connection from your computer to your router. " +
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
}
})
.fail(function () {
context.JK.Banner.showAlert("Network Test Failure", "Unable to determine internet connection type.")
});
})
.fail(function(jqXHR) {
if(jqXHR.status == 404) {
.fail(function (jqXHR) {
if (jqXHR.status == 404) {
// means there are no network testers available.
// we have to skip this part of the UI
testSummary.final = {reason: 'no_servers'}
}
else {
if(context.JK.isNetworkError(arguments)) {
if (context.JK.isNetworkError(arguments)) {
testSummary.final = {reason: 'no_network'}
}
else {
@ -371,7 +441,7 @@
}
testFinished();
})
logger.info("starting network test");
return false;
}
@ -381,7 +451,7 @@
$currentScore.stop().data('showSubscore', showSubscore);
if(!showSubscore) {
if (!showSubscore) {
$subscore.text('');
}
@ -390,7 +460,7 @@
width: width + '%'
}, {
step: function (now, fx) {
if(showSubscore) {
if (showSubscore) {
var newWidth = ( 100 * parseFloat($currentScore.css('width')) / parseFloat($currentScore.parent().css('width')) );
$subscore.text((Math.round(newWidth * 10) / 10) + '%');
}
@ -399,12 +469,37 @@
;
}
function primePumpTimeout(data) {
clearPrimeGuard();
scoring = false;
primeDeferred.reject();
}
function primePumpComplete(data) {
if (data.progress === true) {
// waiting...
logger.debug("pump prime progress report");
setPrimeGuard();
}
else {
clearPrimeGuard();
// we could check for errors, but it's confusing to do so. we just want to let the backend figure out if
// the interface is wireless, or not
setTimeout(function () {
logger.debug("pump primed");
scoring = false;
primeDeferred.resolve();
}, 500); // give backend room to breath for timing/race issues
}
}
function networkTestComplete(data) {
var attempt = getCurrentAttempt();
function refineTest(up) {
if(up) {
if(numClientsToTest == gon.ftue_network_test_max_clients) {
if (up) {
if (numClientsToTest == gon.ftue_network_test_max_clients) {
attempt.reason = "success";
testFinished();
}
@ -416,15 +511,15 @@
}
else {
// reduce numclients if we can
if(numClientsToTest == MINIMUM_ACCEPTABLE_SESSION_SIZE) {
if (numClientsToTest == MINIMUM_ACCEPTABLE_SESSION_SIZE) {
// we are too low already. fail the user
attempt.reason = "minimum_client_threshold";
testFinished();
}
else if(numClientsToTest > STARTING_NUM_CLIENTS) {
else if (numClientsToTest > STARTING_NUM_CLIENTS) {
// this means we've gone up before... so don't go back down (i.e., creating a loop)
attempt.reason = "success";
testSummary.final = { reason:'success', num_clients: numClientsToTest - 1 }
testSummary.final = { reason: 'success', num_clients: numClientsToTest - 1 }
testFinished();
}
else {
@ -437,21 +532,21 @@
attempt.backend_data = data;
if(data.progress === true) {
if (data.progress === true) {
setBackendGuard();
var animate = true;
if(data.downthroughput && data.upthroughput) {
if (data.downthroughput && data.upthroughput) {
if(data.downthroughput > 0 || data.upthroughput > 0) {
if (data.downthroughput > 0 || data.upthroughput > 0) {
attempt.received_progress = true;
animate = true;
}
if(attempt.received_progress) {
if (attempt.received_progress) {
// take the lower
var throughput= data.downthroughput < data.upthroughput ? data.downthroughput : data.upthroughput;
var throughput = data.downthroughput < data.upthroughput ? data.downthroughput : data.upthroughput;
bandwidthSamples.push(data.upthroughput);
@ -463,36 +558,36 @@
clearBackendGuard();
logger.debug("network test pass success. data: ", data);
if(data.reason == "unreachable") {
if (data.reason == "unreachable") {
// STUN
logger.debug("network test: unreachable (STUN issue or similar)");
attempt.reason = data.reason;
testFinished();
}
else if(data.reason == "no-transmit") {
else if (data.reason == "no-transmit") {
logger.debug("network test: no-transmit (STUN issue or similar)");
attempt.reason = data.reason;
testFinished();
}
else if(data.reason == "internal_error") {
else if (data.reason == "internal_error") {
// oops
logger.debug("network test: internal_error (client had a unexpected problem)");
attempt.reason = data.reason;
testFinished();
}
else if(data.reason == "remote_peer_cant_test") {
else if (data.reason == "remote_peer_cant_test") {
// old client
logger.debug("network test: remote_peer_cant_test (old client)")
attempt.reason = data.reason;
testFinished();
}
else if(data.reason == "server_comm_timeout") {
else if (data.reason == "server_comm_timeout") {
logger.debug("network test: server_comm_timeout (communication with server problem)")
attempt.reason = data.reason;
testFinished();
}
else {
if(!data.downthroughput || !data.upthroughput) {
if (!data.downthroughput || !data.upthroughput) {
// we have to assume this is bad. just not a reason we know about in code
logger.debug("network test: no test data (unknown issue? " + data.reason + ")")
attempt.reason = "invalid_response";
@ -500,11 +595,11 @@
}
else {
// success... but we still have to verify if this data is within threshold
if(data.downthroughput < gon.ftue_packet_rate_treshold) {
if (data.downthroughput < gon.ftue_packet_rate_treshold) {
logger.debug("network test: downthroughput too low. downthroughput: " + data.downthroughput + ", threshold: " + gon.ftue_packet_rate_treshold);
refineTest(false);
}
else if(data.upthroughput < gon.ftue_packet_rate_treshold) {
else if (data.upthroughput < gon.ftue_packet_rate_treshold) {
logger.debug("network test: upthroughput too low. upthroughput: " + data.upthroughput + ", threshold: " + gon.ftue_packet_rate_treshold);
refineTest(false);
}
@ -538,7 +633,7 @@
}
function configureStartButton() {
if(scoring) {
if (scoring) {
$startNetworkTestBtn.text('NETWORK TEST RUNNING...').removeClass('button-orange').addClass('button-grey')
}
else {
@ -560,48 +655,75 @@
}
function initializeVideoWatchButton() {
if(operatingSystem == "Win32") {
if (operatingSystem == "Win32") {
$watchVideo.attr('href', 'https://www.youtube.com/watch?v=rhAdCVuwhBc');
}
else {
$watchVideo.attr('href', 'https://www.youtube.com/watch?v=0r1py0AYJ4Y');
}
}
function initialize(_$step, _inGearWizard) {
$step = _$step;
inGearWizard = _inGearWizard;
$startNetworkTestBtn = $step.find('.start-network-test');
if($startNetworkTestBtn.length == 0) throw 'no start network test button found in network-test'
if ($startNetworkTestBtn.length == 0) throw 'no start network test button found in network-test'
$testResults = $step.find('.network-test-results');
$testScore = $step.find('.network-test-score');
$testText = $step.find('.network-test-text');
$scoringBar = $step.find('.scoring-bar');
$goodMarker = $step.find('.good-marker');
$goodLine =$step.find('.good-line');
$goodLine = $step.find('.good-line');
$currentScore = $step.find('.current-score');
$scoredClients= $step.find('.scored-clients');
$scoredClients = $step.find('.scored-clients');
$subscore = $step.find('.subscore');
$watchVideo = $step.find('.watch-video');
$startNetworkTestBtn.on('click', startNetworkTest);
$startNetworkTestBtn.on('click', function () {
prepareNetworkTest();
});
operatingSystem = context.JK.GetOSAsString();
initializeVideoWatchButton();
// if this network test is instantiated anywhere else than the gearWizard, or a dialog, then this will have to be expanded
if(inGearWizard) {
context.JK.HandleNetworkTestSuccessForGearWizard = function(data) { networkTestComplete(data)}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForGearWizard = function(data) { networkTestTimeout(data)}; // pin to global for bridge callback
if (inGearWizard) {
context.JK.HandleNetworkTestSuccessForPumpPrimingGW = function (data) {
primePumpComplete(data)
};
context.JK.HandleNetworkTestTimeoutForPumpPrimingGW = function (data) {
primePumpTimeout(data)
};
context.JK.HandleNetworkTestSuccessForGearWizard = function (data) {
networkTestComplete(data)
}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForGearWizard = function (data) {
networkTestTimeout(data)
}; // pin to global for bridge callback
}
else {
context.JK.HandleNetworkTestSuccessForDialog = function(data) { networkTestComplete(data)}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForDialog = function(data) { networkTestTimeout(data)}; // pin to global for bridge callback
context.JK.HandleNetworkTestSuccessForPumpPrimingDialog = function (data) {
primePumpComplete(data)
};
context.JK.HandleNetworkTestTimeoutForPumpPrimingDialog = function (data) {
primePumpTimeout(data)
};
context.JK.HandleNetworkTestSuccessForDialog = function (data) {
networkTestComplete(data)
}; // pin to global for bridge callback
context.JK.HandleNetworkTestTimeoutForDialog = function (data) {
networkTestTimeout(data)
}; // pin to global for bridge callback
}
}
this.isScoring = function () { return scoring; };
this.isScoring = function () {
return scoring;
};
this.hasScoredNetworkSuccessfully = hasScoredNetworkSuccessfully;
this.initialize = initialize;
this.reset = reset;
@ -611,6 +733,7 @@
this.NETWORK_TEST_START = NETWORK_TEST_START;
this.NETWORK_TEST_DONE = NETWORK_TEST_DONE;
this.NETWORK_TEST_FAIL = NETWORK_TEST_FAIL;
this.NETWORK_TEST_CANCEL = NETWORK_TEST_CANCEL;
return this;
}

View File

@ -20,9 +20,13 @@
.done(function(response) {
if (response) {
$('.session-name', $screen).html(response.name);
$('.scheduled-start', $screen).html(response.scheduled_start);
if (response.recurring_mode !== null) {
var timestamp = new Date(response.scheduled_start).toDateString() + ', ' +
context.JK.formatUtcTime(new Date(response.scheduled_start), false);
$('.scheduled-start', $screen).html(timestamp);
if (response.recurring_mode !== null && response.recurring_mode === 'weekly') {
$('.schedule-recurrence', $screen).html("Recurs " + response.recurring_mode + " on this day at this time");
}
}

View File

@ -98,7 +98,8 @@
context._.each(sessionList, function (session) {
session.scheduled_start = new Date(session.scheduled_start).toDateString() + ', ' +
getFormattedTime(new Date(session.scheduled_start), false);
context.JK.formatUtcTime(new Date(session.scheduled_start), false);
var options = {
id: session.id,
name: session.name,
@ -311,7 +312,7 @@
var moveToFinish = function() {
app.layout.closeDialog('confirm');
createSessionSettings.startDate = new Date(session.scheduled_start).toDateString();
createSessionSettings.startTime = getFormattedTime(new Date(session.scheduled_start), false);
createSessionSettings.startTime = context.JK.formatUtcTime(new Date(session.scheduled_start), false);
createSessionSettings.genresValues = session.genres;
createSessionSettings.genres = [session.genre_id];
createSessionSettings.timezone.label = session.timezone_description;
@ -547,7 +548,7 @@
data.legal_terms = true;
data.language = createSessionSettings.language.value;
if (createSessionSettings.createType == 'quick-start' || createSessionSettings.createType == 'immediately') {
data.start = new Date().toDateString() + ' ' + getFormattedTime(new Date(), false);
data.start = new Date().toDateString() + ' ' + context.JK.formatUtcTime(new Date(), false);
data.duration = "30";
}
else if (createSessionSettings.createType == 'rsvp') {
@ -746,10 +747,10 @@
}
if (step == STEP_SELECT_TYPE && createSessionSettings.createType == 'start-scheduled' && createSessionSettings.selectedSessionId == null) {
$btnNext.removeClass('button-orange').addClass('button-grey');
$btnNext.addClass('disabled');
}
else {
$btnNext.removeClass('button-grey').addClass('button-orange');
$btnNext.removeClass('disabled');
}
if (step == STEP_SELECT_CONFIRM) {
@ -770,7 +771,7 @@
event.preventDefault();
}
if ($(this).is('.button-grey')) return false;
if ($(this).is('.disabled')) return false;
if ($.inArray(createSessionSettings.createType, ['start-scheduled', 'quick-start']) > -1)
step = STEP_SELECT_TYPE;
else
@ -806,7 +807,7 @@
if (event) {
event.preventDefault();
}
if ($(this).is('.button-grey')) return false;
if ($(this).is('.disabled')) return false;
if ($.inArray(createSessionSettings.createType, ['start-scheduled', 'quick-start']) > -1)
step = STEP_SELECT_CONFIRM;
@ -856,30 +857,6 @@
}
function getFormattedTime(date, change) {
if (change) {
date.setMinutes(Math.ceil(date.getMinutes() / 30) * 30);
}
var h12h = date.getHours();
var m12h = date.getMinutes();
var ampm;
if (h12h >= 0 && h12h < 12) {
if (h12h === 0) {
h12h = 12; // 0 becomes 12
}
ampm = "AM";
}
else {
if (h12h > 12) {
h12h -= 12; // 13-23 becomes 1-11
}
ampm = "PM";
}
var timeString = ("00" + h12h).slice(-2) + ":" + ("00" + m12h).slice(-2) + " " + ampm;
return timeString;
}
function toggleDate() {
var selectedDate = new Date($('#session-start-date').val());
var currentDate = new Date();
@ -889,7 +866,7 @@
currentDate.getMonth() == selectedDate.getMonth() &&
currentDate.getDate() == selectedDate.getDate()) {
var timeString = getFormattedTime(currentDate, true);
var timeString = context.JK.formatUtcTime(currentDate, true);
startIndex = defaultTimeArray.indexOf(timeString);
}
$startTimeList.empty();
@ -903,14 +880,11 @@
$startTimeList.val(createSessionSettings.startTime);
toggleStartTime();
context.JK.dropdown($startTimeList);
context.JK.dropdown($endTimeList);
}
function toggleStartTime() {
var valueSelected = $startTimeList.find('option:selected').val();
var startIndex = defaultTimeArray.indexOf(valueSelected) + 1;
var startIndex = defaultTimeArray.indexOf(valueSelected) + 2;
var $endTimeList = $('#end-time-list');
$endTimeList.empty();
@ -923,9 +897,14 @@
$endTimeList.append($('<option value="' + strTime + '" class="label">' + strTime +'</option>'));
}
if (createSessionSettings.endTime != defaultTimeArray[startIndex])
if (createSessionSettings.endTime != defaultTimeArray[startIndex]) {
createSessionSettings.endTime = defaultTimeArray[startIndex];
}
$endTimeList.val(createSessionSettings.endTime);
context.JK.dropdown($startTimeList);
context.JK.dropdown($endTimeList);
}
function initializeControls() {
@ -971,7 +950,7 @@
}
if (error) {
app.notifyAlert("Error", "We're sorry, but we do not allow upload of that file type. Please upload only the file types listed in the Upload dialog box.");
app.notifyAlert("Error", "You can only upload images (.png .jpg .jpeg .gif), PDFs (.pdf), and XML files (.xml .mxl).");
$inputFiles.replaceWith($inputFiles.clone(true));
}
else {
@ -1072,10 +1051,10 @@
var $btnNext = $('#create-session-buttons .btn-next');
if (step == STEP_SELECT_TYPE && createSessionSettings.createType == 'start-scheduled' && createSessionSettings.selectedSessionId == null) {
$btnNext.removeClass('button-orange').addClass('button-grey');
$btnNext.addClass('disabled')
}
else {
$btnNext.removeClass('button-grey').addClass('button-orange');
$btnNext.removeClass('disabled');
}
toggleStepStatus();

View File

@ -184,6 +184,12 @@
}
var sessionVals = buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml);
// format scheduled start time
sessionVals.scheduled_start = new Date(session.scheduled_start).toDateString() + ', ' +
context.JK.formatUtcTime(new Date(session.scheduled_start), false);// + '-' +
//context.JK.formatUtcTime(new Date(session.scheduled_start + session.scheduled_duration), false);
sessionVals.rsvp_link_display_style = showRsvpLink ? "block" : "none";
var row = context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals);
@ -298,8 +304,6 @@
latencyStyle = LATENCY.UNKNOWN.style;
}
else {
latencyUsers++;
totalLatency += latency;
if (latency <= LATENCY.GOOD.max) {
latencyDescription = LATENCY.GOOD.description;
latencyStyle = LATENCY.GOOD.style;

View File

@ -0,0 +1,36 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.ShutdownDialog = function (app) {
var logger = context.JK.logger;
function show() {
context.JK.Banner.showAlert(
{ title: "Close JamKazam Application",
buttons: [
{name: 'Completely Shut Down the App', click: function() {context.jamClient.ShutdownApplication()}},
{name: 'Let App Run in Background', click: function() {context.jamClient.ShutdownApplication()}}
],
html: $('#template-shutdown-prompt').html()});
}
function initialize() {
//context.jamClient.RegisterQuitCallback("window.JK.ShutdownDialogCallback");
}
function quitCallback(options) {
logger.debug("oh hai");
show();
}
this.initialize = initialize;
context.JK.ShutdownDialogCallback = quitCallback;
return this;
}
})(window, jQuery);

View File

@ -85,7 +85,11 @@
function handleWhatsNext(userProfile) {
if (notYetShownWhatsNext && gon.isNativeClient && userProfile.show_whats_next) {
notYetShownWhatsNext = false;
app.layout.showDialog('whatsNext');
console.log("window.location.pathname", window.location.pathname, gon.client_path, window.location.pathname.indexOf(gon.client_url));
if(window.location.pathname.indexOf(gon.client_path) == 0) {
app.layout.showDialog('whatsNext');
}
}
}

View File

@ -11,6 +11,7 @@
var ALERT_NAMES = context.JK.ALERT_NAMES;
var ALERT_TYPES = context.JK.ALERT_TYPES;
var EVENTS = context.JK.EVENTS;
var days = new Array("Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat");
@ -520,6 +521,30 @@
return date.toLocaleTimeString();
}
context.JK.formatUtcTime = function(date, change) {
if (change) {
date.setMinutes(Math.ceil(date.getMinutes() / 30) * 30);
}
var h12h = date.getHours();
var m12h = date.getMinutes();
var ampm;
if (h12h >= 0 && h12h < 12) {
if (h12h === 0) {
h12h = 12; // 0 becomes 12
}
ampm = "AM";
}
else {
if (h12h > 12) {
h12h -= 12; // 13-23 becomes 1-11
}
ampm = "PM";
}
var timeString = ("00" + h12h).slice(-2) + ":" + ("00" + m12h).slice(-2) + " " + ampm;
return timeString;
}
context.JK.prettyPrintElements = function ($elements) {
$.each($elements, function (index, item) {
var $item = $(item);
@ -556,6 +581,10 @@
return $item;
}
// returns:
// * Win32
// * MacOSX
// * Unix
context.JK.GetOSAsString = function() {
if(!os) {
os = context.jamClient.GetOSAsString();
@ -938,6 +967,12 @@
if(!gon.isNativeClient) {
logger.debug("guarding against normal browser on screen thaht requires native client")
app.layout.showDialog('launch-app-dialog', args)
.one(EVENTS.DIALOG_CLOSED, function() {
if(args && args.goHome) {
window.location = '/client#/home';
}
})
return false;
}
return true;

View File

@ -4,7 +4,7 @@
context.JK = context.JK || {};
context.JK.ShowSessionInfo = function(app) {
context.JK.ShowSessionInfo = function(app, musicSessionId) {
var logger = context.JK.logger;
var rest = JK.Rest();
var ui = new context.JK.UIHelper(app);
@ -18,7 +18,7 @@
UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2}
};
function addComment(musicSessionId) {
function addComment() {
var comment = $("#txtSessionInfoComment").val();
if ($.trim(comment).length > 0) {
rest.addSessionInfoComment(musicSessionId, comment)
@ -64,7 +64,66 @@
});
}
function initialize(musicSessionId) {
// this is done post-page load to allow websocket connection to be established
function addLatencyDetails() {
rest.getSessionHistory(musicSessionId)
.done(function(session) {
if (session.approved_rsvps && session.approved_rsvps.length > 0) {
// loop through each record in RSVPs, which has already been rendered, and extract
// the user ID
$('.rsvp-details').each(function(index) {
var $user = $(this).find('div[hoveraction="musician"]');
var userId = $user.attr('user-id');
var latency = null;
var latencyStyle = LATENCY.UNKNOWN.style;
var latencyDescription = LATENCY.UNKNOWN.description;
// default current user to GOOD
if (userId === context.JK.currentUserId) {
latencyStyle = LATENCY.GOOD.style;
latencyDescription = LATENCY.GOOD.description;
}
else {
// find the corresponding user in the API response payload
for (var i=0; i < session.approved_rsvps.length; i++) {
if (session.approved_rsvps.id === userId) {
latency = session.approved_rsvps[i].latency;
break;
}
}
if (latency) {
if (latency <= LATENCY.GOOD.max) {
latencyDescription = LATENCY.GOOD.description;
latencyStyle = LATENCY.GOOD.style;
}
else if (latency > LATENCY.MEDIUM.min && latency <= LATENCY.MEDIUM.max) {
latencyDescription = LATENCY.MEDIUM.description;
latencyStyle = LATENCY.MEDIUM.style;
}
else {
latencyDescription = LATENCY.POOR.description;
latencyStyle = LATENCY.POOR.style;
}
}
else {
latencyStyle = LATENCY.UNKNOWN.style;
latencyDescription = LATENCY.UNKNOWN.description;
}
}
// add the latency details for this user to the UI
var latencyHtml = context.JK.fillTemplate($('#template-latency-detail').html(), {
latencyStyle: latencyStyle,
latencyDescription: latencyDescription
});
$(this).find('.latency-tags').append(latencyHtml);
});
}
});
}
function initialize() {
registerScheduledSessionComment();
var $parent = $('.landing-sidebar');
@ -134,12 +193,14 @@
$("#btnPostComment").click(function(e) {
if ($.trim($("#txtSessionInfoComment").val()).length > 0) {
addComment(musicSessionId);
addComment();
$("#txtSessionComment").val('');
$("#txtSessionComment").blur();
}
});
addLatencyDetails();
$(document).on("rsvpSubmitEvent", function() {
location.reload();
});

View File

@ -0,0 +1,39 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
var $signin;
var $signinRoot;
var $signupRoot;
var rest = context.JK.Rest();
var logger = context.JK.logger;
var EVENTS = context.JK.EVENTS;
function initialize() {
$signinRoot = $('.signin-common');
$signupRoot = $('.signup-common');
var signinHelper = new context.JK.SigninHelper(context.JK.app);
$(signinHelper).on(EVENTS.SHOW_SIGNUP, function() {
$signinRoot.hide();
$signupRoot.show();
});
signinHelper.initialize($signinRoot, false);
var signupHelper = new context.JK.SignupHelper(context.JK.app);
$(signupHelper).on(EVENTS.SHOW_SIGNIN, function() {
$signupRoot.hide();
$signinRoot.show();
});
signupHelper.initialize($signupRoot);
$signinRoot.find('input[name="session[email]"]').focus();
}
context.JK.SigninPage = initialize;
})(window, jQuery);

View File

@ -5,78 +5,21 @@
context.JK = context.JK || {};
context.JK.SigninDialog = function(app) {
var EVENTS = context.JK.EVENTS;
var logger = context.JK.logger;
var rest = context.JK.Rest();
var dialogId = '#signin-dialog';
var $dialog = null;
var signinHelper = null;
function reset() {
$(dialogId + ' #signin-form').removeClass('login-error')
$(dialogId + ' input[name=email]').val('');
$(dialogId + ' input[name=password]').val('');
$(dialogId + ' input[name=remember_me]').attr('checked', 'checked')
}
function login() {
var email = $(dialogId + ' input[name=email]').val();
var password = $(dialogId + ' input[name=password]').val();
var rememberMe = $(dialogId + ' input[name=remember_me]').is(':checked')
rest.login({email: email, password: password, remember_me: rememberMe})
.done(function() {
app.layout.closeDialog('signin-dialog')
var redirectTo = $.QueryString['redirect-to'];
if(redirectTo) {
logger.debug("redirectTo:" + redirectTo);
window.location.href = redirectTo;
}
else {
logger.debug("default post-login path");
window.location.href = '/client'
}
})
.fail(function(jqXHR) {
if(jqXHR.status == 422) {
$(dialogId + ' #signin-form').addClass('login-error')
}
else {
app.notifyServerError(jqXHR, "Unable to log in")
}
})
}
function events() {
$(dialogId + ' .signin-cancel').click(function(e) {
app.layout.closeDialog('signin-dialog');
e.stopPropagation();
return false;
});
$(dialogId + ' #signin-form').submit(function(e) {
login();
return false;
});
$(dialogId + ' .signin-submit').click(function(e) {
login();
return false;
});
$(dialogId + ' .show-signup-dialog').click(function(e) {
app.layout.closeDialog('signin-dialog')
app.layout.showDialog('signup-dialog')
return false;
})
}
function beforeShow() {
logger.debug("showing login form")
reset();
signinHelper.reset();
}
function afterShow() {
$(dialogId + ' input[name=email]').focus();
$dialog.find('input[name="session[email]"]').focus();
}
function afterHide() {
@ -93,10 +36,16 @@
app.bindDialog('signin-dialog', dialogBindings);
events();
$dialog = $(dialogId);
signinHelper = new context.JK.SigninHelper(app);
$(signinHelper).on(EVENTS.SHOW_SIGNUP, function() {
app.layout.closeDialog('signin-dialog')
app.layout.showDialog('signup-dialog')
})
signinHelper.initialize($dialog, true);
}
this.initialize = initialize;
}
})(window, jQuery);

View File

@ -0,0 +1,115 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.SigninHelper = function(app) {
if(!app) throw "no app defined";
var logger = context.JK.logger;
var rest = context.JK.Rest();
var $self = $(this);
var $parent = null;
var $signinBtn = null;
var $signinForm = null;
var $signinCancelBtn = null;
var $email = null;
var $password = null;
var $rememberMe = null;
var useAjax = false;
var EVENTS = context.JK.EVENTS;
function reset() {
$signinForm.removeClass('login-error')
$email.val('');
$password.val('');
$rememberMe.attr('checked', 'checked')
}
function login() {
var email = $email.val();
var password = $password.val();
var rememberMe = $rememberMe.is(':checked')
reset();
$signinBtn.text('TRYING...');
rest.login({email: email, password: password, remember_me: rememberMe})
.done(function() {
//app.layout.closeDialog('signin-dialog')
var redirectTo = $.QueryString['redirect-to'];
if(redirectTo) {
logger.debug("redirectTo:" + redirectTo);
window.location.href = redirectTo;
}
else {
logger.debug("default post-login path");
window.location.href = '/client'
}
})
.fail(function(jqXHR) {
if(jqXHR.status == 422) {
$signinForm.addClass('login-error')
}
else {
app.notifyServerError(jqXHR, "Unable to log in")
}
})
.always(function() {
$signinBtn.text('SIGN IN')
})
}
function events() {
$signinCancelBtn.click(function(e) {
app.layout.closeDialog('signin-dialog');
e.stopPropagation();
return false;
});
if(useAjax) {
$signinForm.submit(function(e) {
login();
return false;
});
$signinBtn.click(function(e) {
login();
return false;
});
}
$parent.find('.show-signup-dialog').click(function(e) {
$self.triggerHandler(EVENTS.SHOW_SIGNUP);
return false;
})
}
function initialize(_$parent, _useAjax){
$parent = _$parent;
useAjax = _useAjax;
$signinBtn = $parent.find('.signin-submit')
$signinForm = $parent.find('.signin-form')
$signinCancelBtn = $parent.find('.signin-cancel')
$email = $parent.find('input[name="session[email]"]');
$password = $parent.find('input[name="session[password]"]');
$rememberMe = $parent.find('input[name="user[remember_me]"]');
if($signinForm.length == 0) throw "no signin form found";
events();
}
this.initialize = initialize;
this.reset = reset;
return this;
}
})(window, jQuery);

View File

@ -1,49 +1,43 @@
(function(context,$) {
(function (context, $) {
"use strict";
"use strict";
context.JK = context.JK || {};
context.JK = context.JK || {};
context.JK.SignupDialog = function(app) {
var logger = context.JK.logger;
var rest = context.JK.Rest();
var dialogId = '#signup-dialog';
function events() {
$(dialogId + ' .signup-cancel').click(function(e) {
app.layout.closeDialog('signup-dialog');
e.stopPropagation();
return false;
});
$(dialogId + ' .show-signin-dialog').click(function(e) {
app.layout.closeDialog('signup-dialog')
app.layout.showDialog('signin-dialog')
return false;
})
}
function beforeShow() {
}
function afterHide() {
}
function initialize(){
var dialogBindings = {
'beforeShow' : beforeShow,
'afterHide': afterHide
};
app.bindDialog('signup-dialog', dialogBindings);
events();
}
this.initialize = initialize;
context.JK.SignupDialog = function (app) {
var logger = context.JK.logger;
var rest = context.JK.Rest();
var dialogId = '#signup-dialog';
var $dialog = null;
var signupHelper = null;
var EVENTS = context.JK.EVENTS;
function beforeShow() {
}
function afterHide() {
}
function initialize() {
var dialogBindings = {
'beforeShow': beforeShow,
'afterHide': afterHide
};
app.bindDialog('signup-dialog', dialogBindings);
$dialog = $(dialogId);
signupHelper = new context.JK.SignupHelper(app);
$(signupHelper).on(EVENTS.SHOW_SIGNIN, function () {
app.layout.closeDialog('signup-dialog')
app.layout.showDialog('signin-dialog')
})
signupHelper.initialize($dialog);
}
this.initialize = initialize;
}
})(window, jQuery);

View File

@ -0,0 +1,47 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.SignupHelper = function(app) {
if(!app) throw "no app defined";
var logger = context.JK.logger;
var rest = context.JK.Rest();
var $self = $(this);
var $parent = null;
var $signupCancel = null;
var $showSigninDialog = null;
var EVENTS = context.JK.EVENTS;
function events() {
$parent.find('.signup-cancel').click(function(e) {
app.layout.closeDialog('signup-dialog');
e.stopPropagation();
return false;
});
$parent.find('.show-signin-dialog').click(function(e) {
$self.triggerHandler(EVENTS.SHOW_SIGNIN);
return false;
})
}
function initialize(_$parent){
$parent = _$parent;
$showSigninDialog = $parent.find('.show-signin-dialog')
$signupCancel = $parent.find('.signup-cancel')
if($showSigninDialog.length == 0) throw "no $showSigninDialog found";
if($signupCancel.length == 0) throw "no $signupCancel form found";
events();
}
this.initialize = initialize;
return this;
}
})(window, jQuery);

View File

@ -21,7 +21,9 @@
//= require globals
//= require AAB_message_factory
//= require facebook_helper
//= require web/signup_helper
//= require web/signupDialog
//= require web/signin_helper
//= require web/signinDialog
//= require web/videoDialog
//= require invitationDialog

View File

@ -18,7 +18,7 @@
return false;
});
$('#signin').click(function (e) {
$('#signin.signin').click(function (e) {
if (context.JK.currentUserId) {
rest.getUserDetail({id:context.JK.currentUserId})
.done(function () {
@ -73,6 +73,12 @@
}
});
}
$('.like-link').click(function() {
var like_site = $(this).data('site');
JK.GA.trackJKSocial(JK.GA.Categories.jkLike, like_site, JK.clientType());
window.open("/endorse/0/"+like_site, '_blank');
});
}
context.JK.WelcomePage = initialize;

View File

@ -12,6 +12,7 @@
var $wizardSteps = null;
var $templateSteps = null;
var loopbackWizard = null;
var inputs = null;
var self = this;
@ -42,6 +43,8 @@
}
function newSession() {
inputs = null;
context._.each(STEPS, function(stepInfo, stepNumber) {
if(stepInfo.newSession) {
stepInfo.newSession.call(stepInfo);
@ -171,6 +174,13 @@
wizard.setBackState(enabled);
}
function setChosenInputs(_inputs) {
inputs = _inputs;
}
function getChosenInputs() {
return inputs;
}
function initialize(_loopbackWizard) {
@ -190,20 +200,23 @@
$wizardSteps = $dialog.find('.wizard-step');
$templateSteps = $('#template-ftuesteps');
stepUnderstandGear.initialize($wizardSteps.filter($('[layout-wizard-step=0]')));
stepSelectGear.initialize($wizardSteps.filter($('[layout-wizard-step=1]')));
stepConfigureTracks.initialize($wizardSteps.filter($('[layout-wizard-step=2]')));
stepConfigureVoiceChat.initialize($wizardSteps.filter($('[layout-wizard-step=3]')));
stepDirectMonitoring.initialize($wizardSteps.filter($('[layout-wizard-step=4]')));
stepNetworkTest.initialize($wizardSteps.filter($('[layout-wizard-step=5]')));
stepSuccess.initialize($wizardSteps.filter($('[layout-wizard-step=6]')));
wizard = new context.JK.Wizard(app);
stepUnderstandGear.initialize($wizardSteps.filter($('[layout-wizard-step=0]')), self);
stepSelectGear.initialize($wizardSteps.filter($('[layout-wizard-step=1]')), self);
stepConfigureTracks.initialize($wizardSteps.filter($('[layout-wizard-step=2]')), self);
stepConfigureVoiceChat.initialize($wizardSteps.filter($('[layout-wizard-step=3]')), self);
stepDirectMonitoring.initialize($wizardSteps.filter($('[layout-wizard-step=4]')), self);
stepNetworkTest.initialize($wizardSteps.filter($('[layout-wizard-step=5]')), self);
stepSuccess.initialize($wizardSteps.filter($('[layout-wizard-step=6]')), self);
wizard.initialize($dialog, $wizardSteps, STEPS);
events();
}
this.setChosenInputs = setChosenInputs; // so step 2 can 'talk' to step 3
this.getChosenInputs = getChosenInputs;
this.setNextState = setNextState;
this.setBackState = setBackState;
this.initialize = initialize;

View File

@ -14,6 +14,11 @@
var $step = null;
var successfullyAssignedOnce = false;
var wizard = null;
function handleHelp() {
return "https://jamkazam.desk.com/customer/portal/articles/1599961-first-time-setup---step-3---configure-tracks";
}
function handleNext() {
var saved = configureTracksHelper.trySave();
@ -33,15 +38,17 @@
function beforeShow() {
var forceInputsToUnassigned = !successfullyAssignedOnce;
configureTracksHelper.reset(forceInputsToUnassigned)
configureTracksHelper.reset(forceInputsToUnassigned, wizard.getChosenInputs())
}
function initialize(_$step) {
function initialize(_$step, _wizard) {
$step = _$step;
wizard = _wizard;
configureTracksHelper.initialize($step);
}
this.handleHelp = handleHelp;
this.newSession = newSession;
this.handleNext = handleNext;
this.beforeShow = beforeShow;

View File

@ -20,6 +20,10 @@
var voiceChatHelper = new context.JK.VoiceChatHelper(app);
var firstTimeShown = false;
function handleHelp() {
return "https://jamkazam.desk.com/customer/portal/articles/1599963-first-time-setup---step-4---configure-voice-chat";
}
function newSession() {
firstTimeShown = true;
}
@ -47,6 +51,7 @@
}
this.handleHelp = handleHelp;
this.handleNext = handleNext;
this.newSession = newSession;
this.beforeShow = beforeShow;

View File

@ -49,6 +49,10 @@
}
}
function handleHelp() {
return "https://jamkazam.desk.com/customer/portal/articles/1599967-first-time-setup---step-5---turn-off-direct-monitoring";
}
function handleNext() {
}
@ -87,6 +91,7 @@
$directMonitoringBtn.on('click', togglePlay);
}
this.handleHelp = handleHelp;
this.handleNext = handleNext;
this.newSession = newSession;
this.beforeShow = beforeShow;

View File

@ -23,6 +23,10 @@
updateButtons();
}
function networkTestCancel() {
updateButtons();
}
function networkTestStart() {
updateButtons();
}
@ -39,6 +43,10 @@
dialog.setBackState(!networkTest.isScoring());
}
function handleHelp() {
return "https://jamkazam.desk.com/customer/portal/articles/1599969-first-time-setup---step-6---test-your-network";
}
function newSession() {
networkTest.reset();
updateButtons();
@ -59,9 +67,11 @@
$(networkTest)
.on(networkTest.NETWORK_TEST_DONE, networkTestDone)
.on(networkTest.NETWORK_TEST_FAIL, networkTestFail)
.on(networkTest.NETWORK_TEST_CANCEL, networkTestCancel)
.on(networkTest.NETWORK_TEST_START, networkTestStart)
}
this.handleHelp = handleHelp;
this.newSession = newSession;
this.beforeHide = beforeHide;
this.beforeShow = beforeShow;

View File

@ -19,6 +19,7 @@
var frameBuffers = new context.JK.FrameBuffers(app);
var gearTest = new context.JK.GearTest(app);
var loopbackShowing = false;
var wizard = null;
// the goal of lastFailureAnalytics and trackedPass are to send only a single AudioTest 'Pass' or 'Failed' event, per FTUE wizard open/close
var lastFailureAnalytics = {};
@ -795,49 +796,59 @@
initializeNextButtonState();
}
function handleHelp() {
if(operatingSystem == "Win32") {
return "https://jamkazam.desk.com/customer/portal/articles/1599818-first-time-setup---step-2---select-and-test-audio-gear---windows-";
}
else {
return "https://jamkazam.desk.com/customer/portal/articles/1599845-first-time-setup---step-2---select-and-test-audio-gear---mac";
}
}
function handleNext() {
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var $assignedOutputs = $outputChannels.find('input[type="checkbox"]:checked');
var errors = [];
if($assignedInputs.length == 0) {
errors.push("There must be at least one selected input ports.");
}
if($assignedInputs.length > 12) {
errors.push("There can only be up to 12 selected inputs ports.");
}
if($assignedOutputs.length != 2) {
errors.push("There must be exactly 2 selected output ports.");
}
var $errors = $('<ul></ul>');
context._.each(errors, function(error) {
$errors.append('<li>' + error + '</li>');
});
if(errors.length > 0) {
context.JK.Banner.showAlert({html:$errors});
return false;
}
if(!savedProfile) {
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var $assignedOutputs = $outputChannels.find('input[type="checkbox"]:checked');
var errors = [];
if($assignedInputs.length == 0) {
errors.push("There must be at least one selected input ports.");
}
if($assignedInputs.length > 12) {
errors.push("There can only be up to 12 selected inputs ports.");
}
if($assignedOutputs.length != 2) {
errors.push("There must be exactly 2 selected output ports.");
}
var $errors = $('<ul></ul>');
context._.each(errors, function(error) {
$errors.append('<li>' + error + '</li>');
});
if(errors.length > 0) {
context.JK.Banner.showAlert({html:$errors});
context.jamClient.FTUESetMusicProfileName(gearUtils.createProfileName(selectedDeviceInfo));
var result = context.jamClient.FTUESave(true);
if(result && result != "") {
// failed
logger.warn("unable to FTUESave(true). reason:" + result);
context.JK.Banner.alertSupportedNeeded("Unable to persist the audio profile. " + result);
return false;
}
else {
context.jamClient.FTUESetMusicProfileName(gearUtils.createProfileName(selectedDeviceInfo));
var result = context.jamClient.FTUESave(true);
if(result && result != "") {
// failed
logger.warn("unable to FTUESave(true). reason:" + result);
context.JK.Banner.alertSupportedNeeded("Unable to persist the audio profile. " + result);
return false;
}
else {
context.JK.GA.trackAudioTestCompletion(context.JK.detectOS());
trackedPass = true;
lastFailureAnalytics = null;
savedProfile = true;
return true;
}
context.JK.GA.trackAudioTestCompletion(context.JK.detectOS());
trackedPass = true;
lastFailureAnalytics = null;
savedProfile = true;
}
}
// keep the shared state between step 2 and step 3 up-to-date
wizard.setChosenInputs(context._.map($assignedInputs, function(input) { return $(input).attr('data-id') }));
return true;
}
function onFocus() {
@ -883,8 +894,9 @@
updateDialogForCurrentDevices();
}
function initialize(_$step) {
function initialize(_$step, _wizard) {
$step = _$step;
wizard = _wizard;
$watchVideoInput = $step.find('.watch-video.audio-input');
$watchVideoOutput = $step.find('.watch-video.audio-output');
@ -919,6 +931,7 @@
this.getLastAudioTestFailAnalytics = getLastAudioTestFailAnalytics;
this.handleNext = handleNext;
this.newSession = newSession;
this.handleHelp = handleHelp;
this.beforeShow = beforeShow;
this.beforeHide = beforeHide;
this.beforeWizardShow = beforeWizardShow;

View File

@ -8,6 +8,10 @@
var $step = null;
var operatingSystem;
function handleHelp() {
return "https://jamkazam.desk.com/customer/portal/articles/1599817-first-time-setup---step-1";
}
function beforeShow() {
var $watchVideo = $step.find('.watch-video');
var videoUrl = 'https://www.youtube.com/watch?v=NiELWY769Tw';
@ -23,6 +27,7 @@
operatingSystem = context.JK.GetOSAsString();
}
this.handleHelp = handleHelp;
this.beforeShow = beforeShow;
this.initialize = initialize;

View File

@ -76,6 +76,20 @@
return false;
}
function help() {
if ($(this).is('.disabled')) return false;
var stepInfo = STEPS[step];
if(stepInfo.handleHelp) {
var result = stepInfo.handleHelp.call(stepInfo);
if(!result) {return false;}
context.JK.popExternalLink(result);
}
return false;
}
function moveToStep() {
var $nextWizardStep = $wizardSteps.filter($('[layout-wizard-step=' + step + ']'));
@ -119,6 +133,7 @@
$btnCancel.hide();
}
$btnHelp.on('click', help);
$btnNext.on('click', next);
$btnBack.on('click', back);
$btnClose.on('click', function() {$self.triggerHandler('wizard_close'); return false;});

View File

@ -9,6 +9,7 @@
* compiled file, but it's generally better to create a new file per style scope.
*
*= require_self
*= require jquery.ui.datepicker
*= require ./ie
*= require jquery.bt
*= require easydropdown

View File

@ -67,7 +67,7 @@
}
.session-wrapper {
padding: 10px 35px 5px 35px;
padding: 10px 35px 0 35px;
white-space: initial;
h3 {
@ -140,7 +140,7 @@
.btn-select-files {
margin-top: 10px;
margin-left:0;
margin-left:2px;
width:110px;
@include border_box_sizing;
}
@ -287,11 +287,6 @@
#session-step-5 {
}
.session-buttons {
padding-right: 30px;
padding-bottom: 20px;
}
#session-name-disp {
font-style:italic;
}
@ -319,10 +314,42 @@
margin-bottom:20px;
}
#create-session-buttons {
margin-top:10px;
.session-buttons {
position:absolute;
width:100%;
bottom:15px;
.left-buttons {
position:absolute;
left:29px;
bottom:0;
}
.right-buttons {
position:absolute;
right:29px;
bottom:0;
}
#create-session-buttons {
position: absolute;
bottom: 0;
width:100%;
@include border_box_sizing;
padding-right:45px;
padding-bottom:15px;
.btn-help {
float:left;
}
}
}
.error-text {
margin:2px 0 0 2em;
@ -346,6 +373,10 @@
}
#create-session-form {
position:relative;
padding-bottom:50px;
@include border_box_sizing;
min-height:100%;
.musician_access .dropdown-wrapper {
width:75px;
@ -403,13 +434,13 @@
.choosefriends-overlay {
width:384px;
height:344px;
padding:8px;
background-color:#787878;
position:fixed;
top:20%;
left:50%;
margin-left:-200px;
padding:8px 8px 15px !important;
min-height:initial !important;
}
.choosefriends-inner {

View File

@ -6,7 +6,7 @@
border: 1px solid $ColorScreenPrimary;
color:#fff;
min-width: 400px;
min-height: 450px;
min-height: 375px;
z-index: 100;
h2 {

View File

@ -443,7 +443,7 @@ div[layout-id="ftue3"] {
*/
/* Start Jeff's ftue.css */
.signin-overlay {
.landing-overlay {
z-index:100;
width:800px;
height:auto;

View File

@ -242,8 +242,8 @@ input[type="button"] {
.autocomplete-suggestions { border: 1px solid #999; background: #666; overflow: auto; }
.autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden; }
.autocomplete-selected { background: #F0F0F0; }
.autocomplete-suggestions strong { font-weight: normal; color: #3399FF; }
.autocomplete-selected { background: #999; }
.autocomplete-suggestions strong { font-weight: normal; color: #a2cffd; }
.autocomplete .selected {
background:$ColorScreenBackground;

View File

@ -1,6 +1,6 @@
/* DatePicker Container */
.ui-datepicker {
width: 216px;
width: 254px;
height: auto;
margin: 5px auto 0;
font: 9pt Arial, sans-serif;
@ -18,12 +18,12 @@
.ui-datepicker-header {
// background: url('../img/dark_leather.png') repeat 0 0 #000;
background-color: #7e7e7e;
color: #e0e0e0;
color: #333;
font-weight: bold;
-webkit-box-shadow: inset 0px 1px 1px 0px rgba(250, 250, 250, .2);
-moz-box-shadow: inset 0px 1px 1px 0px rgba(250, 250, 250, .2);
box-shadow: inset 0px 1px 1px 0px rgba(250, 250, 250, .2);
text-shadow: 1px -1px 0px #000;
//text-shadow: 1px -1px 0px #000;
filter: dropshadow(color=#000, offx=1, offy=-1);
line-height: 30px;
border-width: 1px 0 0 0;
@ -68,8 +68,8 @@
text-transform: uppercase;
font-size: 6pt;
padding: 5px 0;
color: #666666;
text-shadow: 1px 0px 0px #fff;
color: #ccc;
//text-shadow: 1px 0px 0px #fff;
filter: dropshadow(color=#fff, offx=1, offy=0);
}
.ui-datepicker tbody td {
@ -97,14 +97,14 @@
filter: dropshadow(color=#fff, offx=1, offy=1);
}
.ui-datepicker-calendar .ui-state-default {
background: #4e4e4e;
background: -moz-linear-gradient(top, #4e4e4e 0%, #0e0e0e 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#dedede));
background: -webkit-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
background: -o-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
background: -ms-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
background: linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#dedede',GradientType=0 );
//background: #4e4e4e;
//background: -moz-linear-gradient(top, #4e4e4e 0%, #0e0e0e 100%);
//background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#dedede));
//background: -webkit-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
//background: -o-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
//background: -ms-linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
//background: linear-gradient(top, #4e4e4e 0%,#0e0e0e 100%);
//filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ededed', endColorstr='#dedede',GradientType=0 );
-webkit-box-shadow: inset 1px 1px 0px 0px rgba(250, 250, 250, .5);
-moz-box-shadow: inset 1px 1px 0px 0px rgba(250, 250, 250, .5);
box-shadow: inset 1px 1px 0px 0px rgba(250, 250, 250, .5);
@ -124,6 +124,7 @@
position: relative;
margin: -1px;
}
.ui-datepicker-unselectable .ui-state-default {
background: #4e4e4e;
color: #b4b3b3;

View File

@ -172,7 +172,7 @@ small, .small {font-size:11px;}
.bold {font-weight:bold;}
.rsvp-instruments {
height:80px;
height:auto;
overflow:auto;
background-color:#202020;
padding:8px;

View File

@ -9,7 +9,6 @@
@include border_box_sizing;
padding-right:45px;
padding-bottom:15px;
}
.wizard-buttons-holder {

View File

@ -6,4 +6,6 @@
*= require client/ftue
*= require landing/simple_landing
*= require landing/footer
*= require users/signinCommon
*= require users/signin
*/

View File

@ -27,6 +27,11 @@ body {
top:0;
}
.landing-overlay {
position:relative;
top:0;
}
strong {
font-weight: 600;
@ -92,86 +97,22 @@ strong {
// all custom CSS for the sign-in page goes here
.signin-page {
.ftue-inner {
line-height:18px;
z-index:100;
width:300px;
height:auto;
position:absolute;
top:110px;
background-color:#333;
border: 1px solid #ed3618;
margin-left:-150px;
.overlay-inner {
height:auto;
margin-left:0;
}
.ftue-left, .ftue-right {
}
fieldset[name=text-input]{
float:right;
margin-right:18px;
}
fieldset[name=signin-options] {
float:left;
margin:10px 0 0 10px;
small {
float:left;
}
}
fieldset[name=actions] {
float:right;
margin: 10px 19px 0 0;
}
.field {
right:0;
}
.email {
float:left;
margin-right:10px;
}
.password {
float:left;
}
label {
margin:27px 0 10px;
}
.already-member {
}
.keep-logged-in {
}
.forgot-password {
font-size:11px;
float:right;
margin:15px 19px 0 0;
a {
text-decoration: underline;
}
}
.login-error {
background-color: #330000;
border: 1px solid #990000;
padding:4px;
}
.login-error-msg {
.signin-cancel {
display:none;
margin-top:10px;
text-align:center;
color:#F00;
font-size:11px;
}
fieldset.login-error .login-error-msg {
display:block;
}
}

View File

@ -0,0 +1,10 @@
body.signin {
.signup-common {
display:none;
.signup-cancel {
display:none;
}
}
}

View File

@ -0,0 +1,55 @@
.signin-common {
div.field {
width:100%;
}
div.overlay-inner {
height:auto;
}
label {
margin-bottom:2px;
}
div.email {
margin-top:5px;
}
div.password {
margin-top:20px;
}
div.actions {
margin-top:20px;
}
.login-error {
background-color: #330000;
border: 1px solid #990000;
padding:4px;
div.actions {
margin-top:10px;
}
}
.login-error-msg {
display:none;
margin-top:10px;
text-align:center;
color:#F00;
font-size:11px;
}
.login-error .login-error-msg {
display:block;
}
input[type=text], input[type=password]{
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
}

View File

@ -1,59 +1,3 @@
#signin-dialog {
height:auto;
}
#signin-dialog {
div.field {
width:100%;
}
div.overlay-inner {
height:auto;
}
label {
margin-bottom:2px;
}
div.email {
margin-top:5px;
}
div.password {
margin-top:20px;
}
div.actions {
margin-top:20px;
}
.login-error {
background-color: #330000;
border: 1px solid #990000;
padding:4px;
div.actions {
margin-top:10px;
}
}
.login-error-msg {
display:none;
margin-top:10px;
text-align:center;
color:#F00;
font-size:11px;
}
.login-error .login-error-msg {
display:block;
}
input[type=text], input[type=password]{
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
}

View File

@ -394,6 +394,10 @@ body.web {
width:100%;
}
}
.field.terms_of_service .field_with_errors {
display:inline;
}
}
ul {
@ -453,6 +457,10 @@ body.web {
top:0;
}
.landing-overlay {
position:relative;
top:0;
}
strong {
font-weight: 600;
@ -593,4 +601,7 @@ strong {
body.jam.web.welcome .no-websocket-connection {
display:none;
}
body.jam.web.register .no-websocket-connection {
display:none;
}

View File

@ -22,5 +22,6 @@
*= require web/welcome
#= require web/sessions
*= require web/events
*= require users/signinCommon
*= require users/signinDialog
*/

View File

@ -47,15 +47,9 @@ class MusicSessionsController < ApplicationController
# run these 3 queries only if the user has access to the page
if @can_view
ActiveRecord::Base.transaction do
@music_sessions, @user_scores = MusicSession.sms_index(current_user, {:session_id => params[:id], :client_id => cookies[:client_id]})
unless @music_sessions.blank?
ms = @music_sessions[0]
@approved_rsvps = ms.approved_rsvps
@open_slots = ms.open_slots
@pending_invitations = ms.pending_invitations
end
end
@approved_rsvps = @music_session.approved_rsvps
@open_slots = @music_session.open_slots
@pending_invitations = @music_session.pending_invitations
end
render :layout => "web"

View File

@ -3,7 +3,7 @@ class SessionsController < ApplicationController
layout "web"
def new
def signin
@login_error = false
@sso = params[:sso]
@send_back_to = request.headers['REFERER']
@ -25,7 +25,7 @@ class SessionsController < ApplicationController
@login_error = true
@sso = params[:sso]
@send_back_to = params[:send_back_to]
render 'new', :layout => "landing"
render 'signin', :layout => "landing"
else
if jkclient_agent?

View File

@ -145,7 +145,7 @@ class UsersController < ApplicationController
birth_date = fixup_birthday(params[:jam_ruby_user]["birth_date(2i)"], params[:jam_ruby_user]["birth_date(3i)"], params[:jam_ruby_user]["birth_date(1i)"])
location = { :country => params[:jam_ruby_user][:country], :state => params[:jam_ruby_user][:state], :city => params[:jam_ruby_user][:city]}
terms_of_service = params[:jam_ruby_user][:terms_of_service].nil? ? false : true
terms_of_service = params[:jam_ruby_user][:terms_of_service].nil? || params[:jam_ruby_user][:terms_of_service] == "0"? false : true
musician = params[:jam_ruby_user][:musician]
@user = UserManager.new.signup(remote_ip: request.remote_ip,

View File

@ -19,6 +19,7 @@ module ClientHelper
def gon_setup
gon.root_url = root_url
gon.client_path = client_path
# use gon to pass variables into javascript
if Rails.env == "development"
# if in development mode, we assume you are running websocket-gateway

View File

@ -30,4 +30,18 @@
%li In the resulting screen, drag the JamKazam icon to the Applications folder. It will show a progress bar as it copies.
%li Double-click the Applications folder to go into it.
%li If you are still running the JamKazam application, you will need to stop it before executing the last step.
%li Find the JamKazam application in the Applications folder, and double-click the icon to launch it!
%li Find the JamKazam application in the Applications folder, and double-click the icon to launch it!
%script{type: 'text/template', id: 'template-shutdown-prompt'}
.shutdown-prompt
We strongly recommend that you leave the JamKazam application running in the background.
This is a very lightweight app that will not disrupt your use of your computer and other applications, and leaving this app running will deliver the following benefits to you:
%ul
%li
%span.definition Scoring Service
= '- If you leave the app running, there is a service that can check your Internet latency to other JamKazam users. This is critical data that will guide you on which musicians and which sessions will offer a good online play experience.'
%li
%span.definition Recordings
= '- If you leave the app running, any recordings that you and others have made during sessions can be mastered - i.e. uploaded, mixed on our servers, and downloaded back to your computer - so that you have high quality versions of your recordings available.'
Please consider leaving this lightweight app running in the background for your own benefit, thanks!

View File

@ -1,78 +1,78 @@
<!-- Find Session Screen -->
<div layout="screen" layout-id="findSession" id="findSession" class="screen secondary">
<div class="content">
<div class="content-head">
<div class="content-icon">
<%= image_tag "content/icon_search.png", :size => "19x19" %>
</div>
<div class="content">
<div class="content-head">
<div class="content-icon">
<%= image_tag "content/icon_search.png", :size => "19x19" %>
</div>
<h1>find a session</h1>
<h1>find a session</h1>
<%= render "screen_navigation" %>
</div>
<div class="content-body">
<div class="content-body-scroller">
<form id="find-session-form">
<div class="session-filter">
<div style="min-width:770px;">
<div class="left ml35" style="padding-top:3px;">Filter Session List:</div>
<!-- genre filter -->
<div id="find-session-genre" class="left ml10">
<%= render "genreSelector" %>
</div>
<!-- date filter -->
<div class="search-box">
<input type="text" id="session-date-filter" placeholder="Any Date" />
</div>
<!-- language filter -->
<div class="language">
<select id="session-language-filter">
<% music_session_languages.each do |language| %>
<option value="<%= language[:id] %>"><%= language[:label] %></option>
<% end %>
</select>
</div>
<!-- keyword filter -->
<div class="search-box">
<input id="session-keyword-srch" type="text" name="search" placeholder="Search by Keyword" />
</div>
<div class="right mr10">
<a id="btn-refresh" href="/client#/findSession" style="text-decoration:none;" class="button-grey">REFRESH<span class="extra"></span></a>
</div>
</div>
</div>
<div class="content-scroller">
<div class="content-wrapper" style="padding-left:35px;padding-top:10px;">
<div id="sessions-active">
<%= render :partial => "sessionList", :locals => {:title => "current, active sessions", :category => "sessions-active"} %>
<br />
<div id="no-active-sessions">
No active public sessions found.
</div>
</div>
<div id="sessions-scheduled" class="mt35">
<%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %>
<br />
<div id="no-scheduled-sessions">
No scheduled sessions found.
</div>
</div>
<span class="btn-next-wrapper"><a href="/api/sessions/nindex/clientid?page=1" class="btn-next">Next</a></span>
</div>
</div>
</form>
<div id="end-of-session-list" class="end-of-list">
No more sessions.
</div>
</div>
</div>
<%= render "screen_navigation" %>
</div>
<div class="content-body">
<div class="content-body-scroller">
<form id="find-session-form">
<div class="session-filter">
<div style="min-width:770px;">
<div class="left ml35" style="padding-top:3px;">Filter Session List:</div>
<!-- genre filter -->
<div id="find-session-genre" class="left ml10">
<%= render "genreSelector" %>
</div>
<!-- date filter -->
<div class="search-box">
<input type="text" id="session-date-filter" placeholder="Any Date" />
</div>
<!-- language filter -->
<div class="language">
<select id="session-language-filter">
<% music_session_languages.each do |language| %>
<option value="<%= language[:id] %>"><%= language[:label] %></option>
<% end %>
</select>
</div>
<!-- keyword filter -->
<div class="search-box">
<input id="session-keyword-srch" type="text" name="search" placeholder="Search by Keyword" />
</div>
<div class="right mr10">
<a id="btn-refresh" href="/client#/findSession" style="text-decoration:none;" class="button-grey">REFRESH<span class="extra"></span></a>
</div>
</div>
</div>
<div class="content-scroller">
<div class="content-wrapper" style="padding-left:35px;padding-top:10px;">
<div id="sessions-active">
<%= render :partial => "sessionList", :locals => {:title => "current, active sessions", :category => "sessions-active"} %>
<br />
<div id="no-active-sessions">
No active public sessions found.
</div>
</div>
<div id="sessions-scheduled" class="mt35">
<%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %>
<br />
<div id="no-scheduled-sessions">
No scheduled sessions found.
</div>
</div>
<span class="btn-next-wrapper"><a href="/api/sessions/nindex/clientid?page=1" class="btn-next">Next</a></span>
</div>
</div>
</form>
<div id="end-of-session-list" class="end-of-list">
No more sessions.
</div>
</div>
</div>
</div>
</div>
<!-- active session template -->
@ -160,6 +160,9 @@
<td>Notation Files:</td>
<td>{notation_files}</td>
</tr>
<tr>
<td colspan="2">{scheduled_start}</td>
</tr>
</table>
</td>
<td width="35%">
@ -243,4 +246,5 @@
{latency_text}
</td>
</tr>
<tr><td><div style='height:5px;'>&nbsp;</div></td></tr>
</script>

View File

@ -6,5 +6,5 @@
.clearall
.buttons
%a.button-grey.btn-cancel{href:'#'} CANCEL
%a.button-orange.btn-help{href: '#'} HELP
%a.button-grey.btn-help{rel: 'external', href: 'https://jamkazam.desk.com/customer/portal/articles/1599969-first-time-setup---step-6---test-your-network'} HELP
%a.button-orange.btn-close{href:'#'} CLOSE

View File

@ -20,8 +20,7 @@
%br/
%br/
.left
%a.button-orange{:href => 'TBD', :rel => 'external', :target => '_blank'} HELP
%a.button-grey{:href => 'http://jamkazam.desk.com', :rel => 'external', :target => '_blank'} HELP
.right
%a.button-grey{:id => 'btnCancel', 'layout-action' => 'close'} CANCEL
%a.button-orange{:id => 'btnSubmitRsvp'} SUBMIT RSVP
%br{:clear => "all"}/
%a.button-orange{:id => 'btnSubmitRsvp'} SUBMIT RSVP

View File

@ -94,7 +94,7 @@
This is good option to choose if you just want to jump into a quick test session alone to make
sure you audio gear is working properly, and to familiarize yourself with the session interface.
Choosing this option will set your session to private so that you won't be disturbed, and will
set other options to defaults. To use this option, just click the NEXT buttono to proceed.
set other options to defaults. To use this option, just click the NEXT button to proceed.
</div>
</div>
</div>
@ -266,31 +266,31 @@
<li>
<input type="radio" name="session-policy-type" id="session-policy-standard" policy-id="Standard" checked="checked">
<label for="session-policy-standard" class="radio-text">
Session participants agree to standard legal provisions<br>
Standard legal agreement<br>
</label>
<div class="clearall"></div>
</li>
<li>
<input type="radio" name="session-policy-type" id="session-policy-creative" policy-id="Creative Commons">
<label for="session-policy-creative" class="radio-text">
Session participants agree to Creative Commons license<br>
Creative Commons agreement<br>
</label>
<div class="clearall"></div>
</li>
<li>
<input type="radio" name="session-policy-type" id="session-policy-offline" policy-id="Offline">
<label for="session-policy-offline" class="radio-text">
Session participants have made an offline agreement
Offline agreement
</label>
<div class="clearall"></div>
</li>
<li>
<!--<li>
<input type="radio" name="session-policy-type" id="session-policy-jamtracks" policy-id="Jamtracks">
<label for="session-policy-jamtracks" class="radio-text">
Session participants agree to JamTracks legal provisions
</label>
<div class="clearall"></div>
</li>
</li>-->
</ul>
</div>
<div id="session-policy-info" class="mb5">
@ -355,7 +355,7 @@
<br>
<h3 class="session-fans-access-header">How will you handle fan access?</h3>
<select id="session-fans-access">
<option value="listen-chat-band">Fans may listen, chat with the band</option>
<!--<option value="listen-chat-band">Fans may listen, chat with the band</option>-->
<option value="listen-chat-each" selected="selected">Fans may listen, chat with each other</option>
<option value="no-listen-chat">Fans may not listen to session</option>
</select>
@ -407,14 +407,17 @@
</div>
</div>
<div class="session-buttons">
<div id="create-session-buttons" class="right"></div>
<div class="clearall"></div>
</div>
</div>
<div class="clearall"></div>
<div class="session-buttons">
<div id="create-session-buttons" class="right"></div>
<div class="clearall"></div>
</div>
</form>
</div>
<div class="clearall"></div>
</div>
</div>
</div>
@ -438,9 +441,13 @@
<script type="text/template" id="template-session-buttons">
<div class="sessionbuttons-holder">
<a class="button-orange btn-help" href="http://jamkazam.desk.com/" target="_blank">HELP</a>
<a class="button-orange btn-back" href="#">BACK</a>
<div class="left-buttons">
<a class="button-grey btn-help" href="http://jamkazam.desk.com/" target="_blank">HELP</a>
</div>
<div class="right-buttons">
<a class="button-grey btn-back" href="#">BACK</a>
<a class="button-orange btn-next" href="#">NEXT</a>
</div>
</div>
</script>

View File

@ -47,7 +47,7 @@
Fan Access:
.right.w75.ib.mb10
%select{:name => "fan_access", :id => "session-settings-fan-access"}
%option{:value => "listen-chat-band"} Fans may listen, chat with the band
//%option{:value => "listen-chat-band"} Fans may listen, chat with the band
%option{:value => "listen-chat"} Fans may listen, chat with each other
%option{:value => "no-listen-chat"} Fans may not listen to session

View File

@ -124,7 +124,15 @@
// you need to be logged in to use this part of the interface.
// save original URL, and redirect to the home page
logger.debug("redirecting back to / because not logged in")
window.location.href = '/?redirect-to=' + encodeURIComponent(JK.locationPath());
var redirectPath= '?redirect-to=' + encodeURIComponent(JK.locationPath());
if(gon.isNativeClient) {
window.location.href = '/signin' + redirectPath;
}
else {
window.location.href = '/' + redirectPath;
}
<% end %>
@ -133,6 +141,9 @@
if (this.didInitAfterConnect) return;
this.didInitAfterConnect = true
var shutdownDialog = new JK.ShutdownDialog(JK.app);
shutdownDialog.initialize();
// This is a helper class with a singleton. No need to instantiate.
JK.GenreSelectorHelper.initialize(JK.app);

View File

@ -31,7 +31,7 @@
<%= render "layouts/social_meta" %>
<% end %>
</head>
<body class="jam">
<body class="jam landing <%= yield(:page_name) %>">
<div id="landing-container">
<%= javascript_include_tag "landing/landing" %>
@ -63,14 +63,22 @@
JK.currentUserId = '<%= current_user.id %>';
JK.currentUserAvatarUrl = JK.resolveAvatarUrl('<%= current_user.photo_url %>');
JK.currentUserName = '<%= current_user.name %>';
JK.currentUserMusician = '<%= current_user.musician %>';
<% else %>
JK.currentUserId = null;
JK.currentUserAvatarUrl = null;
JK.currentUserName = null;
JK.currentUserMusician = null;
<% end %>
JK.app = JK.JamKazam();
JK.app.initialize({inClient: false, layoutOpts: {layoutFooter: false, sizeOverlayToContent: true}});
})
</script>
<%= yield(:extra_js) %>
<%= render "shared/ga" %>
<!-- version info: <%= version %> -->
</body>

View File

@ -60,6 +60,10 @@
agreement (
%a.gold{:href => "#{@music_session.legal_policy_url}", :target => "_blank"} View full legal details
)
.clearall.left.w20.ib.mb10
%strong Fan Page:
.right.w75.ib.mb10.fan_page
= share_token_url(@music_session.share_token.token)
%br{clear:'all'}/
@ -84,28 +88,7 @@
.left.ml10
- rsvp.instrument_list.each do |i|
%img.instrument-icon{'instrument-id' => i[:id], height:24, width:24}
.right.w30.ib.f11.center
- if current_user.id == rsvp.id
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td.latency-green GOOD
- elsif !@user_scores[rsvp.id]
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td.latency-grey UNKNOWN
- else
- if @user_scores[rsvp.id] >= 0 && @user_scores[rsvp.id] <= 20.0
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td.latency-green GOOD
- elsif @user_scores[rsvp.id] > 20.0 && @user_scores[rsvp.id] <= 40.0
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td.latency-yellow MEDIUM
- elsif @user_scores[rsvp.id] > 40.0
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td.latency-red POOR
.right.w30.ib.f11.center.latency-tags
%br{:clear => "all"}/
%br/
@ -160,6 +143,12 @@
- content_for :extra_js do
:javascript
$(function () {
var ss = new window.JK.ShowSessionInfo(JK.app);
ss.initialize("#{@music_session.id}");
var ss = new window.JK.ShowSessionInfo(JK.app, "#{@music_session.id}");
ss.initialize();
})
%script{:type => 'text/template', :id => 'template-latency-detail'}
%table.musicians{:cellpadding => 0, :cellspacing => 0}
%tr.mb15
%td{:class => "{latencyStyle}"} {latencyDescription}

View File

@ -1,100 +0,0 @@
<% provide(:title, 'Sign in') %>
<div class="signin-overlay signin-page">
<!-- ftue header -->
<div class="content-head">
<h1>sign in or register</h1>
</div>
<!-- inner wrapper -->
<div class="ftue-inner">
<!-- sign in left column -->
<div class="ftue-left"><br />
<span class="white already-member"><strong>Already a member?</strong></span>
Enter your email address and password:
<div>
<%= form_for(:session, url: signin_path + (request.query_string.blank? ? '' : '?' + request.query_string)) do |f| %>
<input type="hidden" name="sso" value="<%= @sso %>">
<input type="hidden" name="send_back_to" value="<%= @send_back_to %>">
<fieldset name="text-input" class="<%= 'login-error' if @login_error %>">
<div class="field email">
<%= f.label :email, "Email Address:" %>
<%= f.text_field :email, :autofocus=>true %>
</div>
<div class="field password">
<%= f.label :password, "Password:" %>
<%= f.password_field :password %>
</div>
<br clear="all" />
<div class="login-error-msg">Invalid login</div>
</fieldset>
<br clear="all" />
<fieldset name="signin-options">
<script type="text/javascript">
if(window.jamClient === undefined) {
document.write('<input name="user[remember_me]" type="hidden" value="0">');
document.write('<small><input type="checkbox" class="keep-logged-in" value="1" name="user[remember_me]" id="user_remember_me" checked> Keep me logged in</small>');
}
</script>
</fieldset>
<fieldset name="actions">
<%= f.submit "SIGN IN", class: "button-orange m0" %>
</fieldset>
<br clear="all" />
<div class="forgot-password"><a href="/request_reset_password">Forgot Password?</a></div>
<% end %>
</div>
</div>
<!-- end left column -->
<!-- sign in right column -->
<div class="ftue-right">
<br>
<br>
<br>
<br>
<div align="center"><span class="white"><strong>Not a member?</strong></span> Join JamKazam for free:<br>
<br>
<a href="/signup" rel="external" class="button-orange">REGISTER NOW</a>
</div>
<!-- end right column -->
</div>
<br clear="all">
<!--
<br>
<br>
<br>
<span class="white"><strong>Have a Facebook account?</strong></span> Login or
register via Facebook:<br>
<br>
<a href="/auth/facebook">
<%= image_tag "content/button_facebook.png", {:height => 34, :width => 245} %>
</a><br>
<br>
We recommend using <span class="white"><strong>Connect with Facebook</strong></span> because it will make it easier to find and/or invite your musician friends using the JamKazam service.
-->
</div>
<!-- end right column -->
</div>
<!-- end inner -->
<!-- end overlay content -->

View File

@ -0,0 +1,18 @@
- provide(:title, 'Sign in')
- provide(:page_name, 'signin')
.signin-overlay.signin-page
.content-head
%h1 sign in or register
= render "users/signin"
= render "users/signup"
%br{clear: 'all'}
- content_for :extra_js do
:javascript
$(function () {
window.JK.SigninPage();
})

View File

@ -1,4 +1,4 @@
<div class="signin-overlay">
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">

View File

@ -0,0 +1,48 @@
.overlay-inner.signin-common
= link_to image_tag("content/button_facebook_signin.png", {:width => 249, :height => 46}), '/auth/facebook', class: "signin-facebook"
%br
%br
%br
%strong.white Or sign in with JamKazam Account
%br
%br
= form_for(:session, url: signin_path + (request.query_string.blank? ? '' : '?' + request.query_string), html: {class:"signin-form #{'login-error' if @login_error}"}) do |f|
%input{type:'hidden', name: 'sso', value: @sso}
%input{type:'hidden', name: 'send_back_to', value: @send_back_to}
.field.email
= f.label :email, "Email Address:"
= f.text_field :email, autofocus: true
.field.password
= f.label :password, "Password:"
= f.password_field :password, autofocus: true
:javascript
if(window.jamClient === undefined) {
document.write('<input name="user[remember_me]" type="hidden" value="0">');
document.write('<small><input type="checkbox" name="remember_me" class="keep-logged-in" value="1" name="user[remember_me]" id="user_remember_me" checked> Keep me logged in</small>');
} else {
document.write('<input name="user[remember_me]" type="hidden" value="1">');
}
.login-error-msg Invalid login
%br{clear:'all'}
.actions{align: 'center'}
%a.button-grey.signin-cancel{href:'#' } CANCEL
= f.submit "SIGN IN",class: 'button-orange signin-submit'
%br
%br
%small
%a.forgot-password{href:'/request_reset_password'} Forgot Password?
%br
.center
%small
Don't have an account?
%a.show-signup-dialog{href: '#'} Sign Up

View File

@ -1,66 +1,11 @@
<div class="dialog thin-dialog overlay-small" layout-id="signin-dialog" id="signin-dialog">
<!-- ftue header -->
<div class="content-head">
<h1>sign in</h1>
</div>
<!-- inner wrapper -->
<div class="overlay-inner">
<%= render "users/signin" %>
<%= link_to image_tag("content/button_facebook_signin.png", {:width => 249, :height => 46}), '/auth/facebook', class: "signin-facebook" %>
<br>
<br>
<br>
<strong class="white">Or sign in with JamKazam Account</strong>
<br>
<br>
<form id="signin-form" method="post" action="/">
<div class="field email">
<label for="email">Email Address:</label>
<input type="text" name="email"/>
</div>
<div class="field password">
<label for="password">Password:</label>
<input type="password" name="password"/>
</div>
<script type="text/javascript">
if(window.jamClient === undefined) {
document.write('<input name="user[remember_me]" type="hidden" value="0">');
document.write('<small><input type="checkbox" name="remember_me" class="keep-logged-in" value="1" name="user[remember_me]" id="user_remember_me" checked> Keep me logged in</small>');
} else {
document.write('<input name="user[remember_me]" type="hidden" value="1">');
}
</script>
<div class="login-error-msg">Invalid login</div>
<br clear="all"/>
<div align="center" class="actions">
<a href="#" class="button-grey signin-cancel">CANCEL</a>&nbsp;&nbsp;<input type="submit" value="SIGN IN" href="#" class="button-orange m0 signin-submit" />
<br>
<br>
<small><a class='forgot-password' href="/request_reset_password">Forgot Password?</a></small>
</div>
</form>
<br>
<div class="center">
<small>Don't have an account? <a href="#" class="show-signup-dialog">Sign Up</a></small>
</div>
</div>
<!-- end inner -->
<br clear="all">
</div>

View File

@ -0,0 +1,20 @@
.overlay-inner.signup-common
= link_to image_tag("content/button_facebook_signup.png", {:width => 249, :height => 46 }), '/auth/facebook', class: "signup-facebook"
%br
%br
%br
.center
%strong.white Or
%br
%br
.center
= link_to "SIGN UP WITH YOUR EMAIL", signup_path, class: "button-orange block signup-email"
%br
.center
%small
Already have an account?
%a.show-signin-dialog{href: '#'} Sign In
%br
%br
%a.signup-cancel{href: '#'} Cancel
%br{clear: 'all'}

View File

@ -5,29 +5,6 @@
<h1>sign up for jamkazam</h1>
</div>
<!-- inner wrapper -->
<div class="overlay-inner">
<%= link_to image_tag("content/button_facebook_signup.png", {:width => 249, :height => 46 }), '/auth/facebook', class: "signup-facebook" %>
<br>
<br><br>
<div class="center"><strong class="white">Or</strong></div>
<br>
<br>
<div class="center"><%= link_to "SIGN UP WITH YOUR EMAIL", signup_path, class: "button-orange block signup-email" %>
<br>
<div class="center">
<small>Already have an account? <a href="#" class='show-signin-dialog'>Sign In</a><br>
<br>
<a href="#" class="signup-cancel">Cancel</a></small>
</div>
</div>
<!-- end inner -->
<br clear="all">
</div>
<%= render "users/signup" %>
<!-- end overlay content -->
</div>

View File

@ -1,6 +1,6 @@
<% provide(:title, 'Already Signed Up') %>
<div class="signin-overlay">
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">
<h1>You have already signed up with this invitation</h1>

View File

@ -1,4 +1,5 @@
<% provide(:title, 'Register') %>
<% provide(:page_name, 'register') %>
<% provide(:title, 'Register') %>
<div class="content-wrapper register-page">
<h2>Create a JamKazam account</h2>
@ -54,7 +55,7 @@
<option value="" <%= @location[:state].blank? ? "selected" : "" %>>State/Province</option>
<% @regions.each do |region| %>
<% unless region.blank? %>
<option value="<%= region %>" <%= @location[:state] == region ? "selected" : "" %>><%= region %></option>
<option value="<%= region[:region] %>" <%= @location[:state] == region ? "selected" : "" %>><%= region[:name] %></option>
<% end %>
<% end %>
@ -118,7 +119,7 @@
<div class="field terms_of_service">
<small>
<input id="jam_ruby_user_terms_of_service" name="jam_ruby_user[terms_of_service]" type="checkbox"/>
<%= f.check_box :terms_of_service %>
<span>I have read and agree to the JamKazam <%= link_to "terms of service", corp_terms_path, :rel => "external" %>
.</span>
</small>

View File

@ -1,5 +1,7 @@
<% provide(:title, "Reset password") %>
<div class="signin-overlay">
<% provide(:page_name, "request-reset-password") %>
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">

View File

@ -1,5 +1,5 @@
<% provide(:title, "Reset password") %>
<div class="signin-overlay">
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">

View File

@ -1,6 +1,6 @@
<% provide(:title, "Reset password") %>
<div class="signin-overlay">
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">

View File

@ -1,6 +1,6 @@
<% provide(:title, "Reset password") %>
<div class="signin-overlay">
<div class="landing-overlay">
<!-- ftue header -->
<div class="content-head">

View File

@ -30,12 +30,6 @@
:javascript
$(function () {
window.JK.WelcomePage();
$('.like-link').click(function() {
var like_site = $(this).data('site');
JK.GA.trackJKSocial(JK.GA.Categories.jkLike, like_site, JK.clientType());
window.open("/endorse/0/"+like_site, '_blank');
});
})
- content_for :extra_dialogs do

View File

@ -17,7 +17,7 @@ SampleApp::Application.routes.draw do
match '/congratulations_fan', to: 'users#congratulations_fan'
match '/downloads', to: 'users#downloads'
match '/signin', to: 'sessions#new', via: :get
match '/signin', to: 'sessions#signin', via: :get
match '/signin', to: 'sessions#create', via: :post
match '/signout', to: 'sessions#destroy', via: :delete

View File

@ -6,4 +6,13 @@ namespace :users do
User.deliver_new_musician_notifications(since_date)
end
desc "Fix corrupted country codes"
task :fix_corrupted_country_codes do |task, args|
User.where(["country like ?","{:country%"]).find_each do |uu|
if uu.country =~ /{:countrycode=>"([A-Z]+)",/
uu.update_attribute(:country,$1)
end
end
end
end

View File

@ -7,12 +7,12 @@ describe SessionsController do
describe "GET 'new'" do
it "should work" do
get :new
get :signin
response.should be_success
end
it "should have the right title" do
get :new
get :signin
response.body.should have_title("JamKazam | Sign in")
end
end

View File

@ -28,7 +28,7 @@ describe "Create Session Flow", :js => true, :type => :feature, :capybara_featur
page.should have_css(".session-stepnumber", :count => 2)
page.should have_css(".session-stepnumber.session-stepactive", :count => 1)
page.should_not have_css(".btn-back")
page.should have_css(".btn-next.button-grey")
page.should have_css(".btn-next.disabled")
page.should have_css(".btn-help")
end
end
@ -47,6 +47,11 @@ describe "Create Session Flow", :js => true, :type => :feature, :capybara_featur
find('.start-time-list-holder .easydropdown')
find('.timezone-list-holder .easydropdown')
find('.recurring-mode-list-holder .easydropdown')
# by selecting this time, the end-time-list should auto-select to 6:30PM
# Out for the time being; because the contents of the dropdown is based on the current time
#jk_select('05:30 PM', '#start-time-list')
#find('.end-time-list-holder .selected', text: '06:30 PM')
end
end

View File

@ -18,7 +18,6 @@ describe "In a Session", :js => true, :type => :feature, :capybara_feature => tr
it "can't see a private session until it is made public", :slow => true do
pending "Needs finalization of Find Session Screen"
description = "Public or private, I cant decide!"
create_session(creator: user, description: description)
in_client(user) do
@ -28,7 +27,7 @@ describe "In a Session", :js => true, :type => :feature, :capybara_feature => tr
emulate_client
sign_in_poltergeist finder
visit "/client#/findSession"
expect(page).to have_selector('#sessions-none-found') # verify private session is not found
expect(page).to have_selector('#no-active-sessions') # verify private session is not found
sign_out_poltergeist(validate: true)
end
in_client(user) do

View File

@ -1,6 +1,6 @@
require 'spec_helper'
describe "signin" do
describe "signin" do
subject { page }
@ -12,8 +12,8 @@ describe "signin" do
it "success" do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('.curtain', text: 'Connecting...')
@ -21,8 +21,8 @@ describe "signin" do
it "success with redirect" do
visit signin_path + '?' + {'redirect-to' => '/'}.to_query
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'Play music together over the Internet as if in the same room')
@ -32,15 +32,15 @@ describe "signin" do
it 'failure, then success with redirect' do
visit signin_path + '?' + {'redirect-to' => '/'}.to_query
fill_in "Email", with: user.email
fill_in "Password", with: 'wrong'
fill_in "Email Address:", with: user.email
fill_in "Password:", with: 'wrong'
click_button "SIGN IN"
find('h1', text:'sign in or register')
find('.login-error')
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'Play music together over the Internet as if in the same room')
@ -48,8 +48,8 @@ describe "signin" do
it "success with forum sso" do
visit signin_path + '?' + {:sso => :forums}.to_query
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'welcome to fake login page')
@ -64,15 +64,15 @@ describe "signin" do
it "failure, then success with forum sso" do
visit signin_path + '?' + {:sso => :forums}.to_query
fill_in "Email", with: user.email
fill_in "Password", with: 'wrong'
fill_in "Email Address:", with: user.email
fill_in "Password:", with: 'wrong'
click_button "SIGN IN"
find('h1', text:'sign in or register')
find('.login-error')
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'welcome to fake login page')
@ -87,8 +87,8 @@ describe "signin" do
it "success with forum sso w/ custom redirect" do
visit signin_path + '?' + {:sso => :forums, send_back_to: '/junk'}.to_query
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'welcome to fake login page')
@ -105,8 +105,8 @@ describe "signin" do
it "redirects back to /client" do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('.curtain', text: 'Connecting...')
@ -118,8 +118,8 @@ describe "signin" do
it "redirects back to forum if sso=forum" do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('.curtain', text: 'Connecting...')
@ -131,6 +131,14 @@ describe "signin" do
describe "with javascript", :js => true, :type => :feature, :capybara_feature => true do
it "shows signup form when asked" do
find('.show-signup-dialog').trigger(:click)
# toggle back to signin
find('.show-signin-dialog').trigger(:click)
# toggle back to signup
find('.show-signup-dialog').trigger(:click)
end
# if a cookie with the default domain is found with another, delete the one with the default domain
it "delete duplicate session cookies" do
@ -143,8 +151,8 @@ describe "signin" do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'Play music together over the Internet as if in the same room')
@ -167,8 +175,8 @@ describe "signin" do
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
find('h1', text: 'Play music together over the Internet as if in the same room')
@ -200,7 +208,6 @@ describe "signin" do
end
it "can't signout with custom domain for cookie" do
sign_in_poltergeist(user)
original = Rails.application.config.session_cookie_domain

View File

@ -62,9 +62,9 @@ describe "Welcome", :js => true, :type => :feature, :capybara_feature => true d
describe "signin natively" do
it "redirects to client on login" do
within('#signin-form') do
fill_in "email", with: user.email
fill_in "password", with: user.password
within('.signin-form') do
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
end
@ -74,9 +74,9 @@ describe "Welcome", :js => true, :type => :feature, :capybara_feature => true d
end
it "shows error if bad login" do
within('#signin-form') do
fill_in "email", with: "junk"
fill_in "password", with: user.password
within('.signin-form') do
fill_in "Email Address:", with: "junk"
fill_in "Password:", with: user.password
click_button "SIGN IN"
end
@ -91,11 +91,10 @@ describe "Welcome", :js => true, :type => :feature, :capybara_feature => true d
it "redirect on login" do
visit "/client#/account"
find('.curtain')
find('h1', text: 'Play music together over the Internet as if in the same room')
find('#signin').trigger(:click)
within('#signin-form') do
fill_in "email", with: user.email
fill_in "password", with: user.password
find('h1', text: 'sign in or register')
within('.signin-form') do
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
click_button "SIGN IN"
end

View File

@ -62,7 +62,7 @@ describe "Scheduled Music Session API ", :type => :api do
last_response.status.should eql(200)
music_sessions = JSON.parse(last_response.body)
music_sessions.count.should eql(2)
music_sessions.count.should eql(3)
expect(Time.parse(music_sessions[0]["scheduled_start"]).to_i).to be < Time.parse(music_sessions[1]["scheduled_start"]).to_i
end

View File

@ -133,17 +133,22 @@ end
def sign_out_poltergeist(options = {})
open_user_dropdown
click_link 'Sign Out'
should_be_at_root if options[:validate]
should_be_at_signin if options[:validate]
end
def open_user_dropdown
find('.userinfo').hover()
end
def should_be_at_root
find('h1', text: 'Play music together over the Internet as if in the same room')
end
def should_be_at_signin
find('h1', text: 'sign in or register')
end
def leave_music_session_sleep_delay
# add a buffer to ensure WSG has enough time to expire
sleep_dur = (Rails.application.config.websocket_gateway_connect_time_stale_browser +
@ -234,7 +239,7 @@ def create_session(options={})
musician_access = options[:musician_access].nil? ? true : options[:musician_access]
approval_required = options[:approval_required].nil? ? true : options[:approval_required]
fan_access = options[:fan_access].nil? ? true : options[:fan_access]
fan_chat = options[:fan_chat].nil? ? true : options[:fan_chat]
fan_chat = options[:fan_chat].nil? ? false : options[:fan_chat]
# create session in one client
in_client(creator) do
@ -273,7 +278,7 @@ def create_session(options={})
if !fan_access && !fan_chat
fan_access_value = 'Fans may not listen to session'
elsif fan_access && fan_chat
fan_access_value = 'Fans may listen, chat with the band'
fan_access_value = 'Fans may listen, chat with the band' #XXX this option is currently disabled/not available
end
jk_select(fan_access_value, '#session-fans-access')
@ -301,7 +306,7 @@ def schedule_session(options = {})
musician_access = options[:musician_access].nil? ? true : options[:musician_access]
approval_required = options[:approval_required].nil? ? true : options[:approval_required]
fan_access = options[:fan_access].nil? ? true : options[:fan_access]
fan_chat = options[:fan_chat].nil? ? true : options[:fan_chat]
fan_chat = options[:fan_chat].nil? ? false : options[:fan_chat]
musician_access_value = 'Musicians may join by approval'
fan_permission_value = 'Fans may listen, chat with each other'
@ -443,7 +448,7 @@ end
def set_session_as_private()
find('#session-settings-button').trigger(:click)
within('#session-settings-dialog') do
jk_select("Private", '#session-settings-dialog #session-settings-musician-access')
jk_select("Only RSVP musicians may join", '#session-settings-dialog #session-settings-musician-access')
#select('Private', :from => 'session-settings-musician-access')
find('#session-settings-dialog-submit').trigger(:click)
end
@ -454,7 +459,7 @@ end
def set_session_as_public()
find('#session-settings-button').trigger(:click)
within('#session-settings-dialog') do
jk_select("Public", '#session-settings-dialog #session-settings-musician-access')
jk_select("Musicians may join at will", '#session-settings-dialog #session-settings-musician-access')
# select('Public', :from => 'session-settings-musician-access')
find('#session-settings-dialog-submit').trigger(:click)
end