diff --git a/db/manifest b/db/manifest index 04ad4b590..4bc66447b 100755 --- a/db/manifest +++ b/db/manifest @@ -73,3 +73,4 @@ crash_dumps.sql crash_dumps_idx.sql music_sessions_user_history_add_session_removed_at.sql user_progress_tracking.sql +whats_next.sql diff --git a/db/up/whats_next.sql b/db/up/whats_next.sql new file mode 100644 index 000000000..b633dd676 --- /dev/null +++ b/db/up/whats_next.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD COLUMN show_whats_next boolean DEFAULT TRUE; diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 14133dc49..7af848254 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -124,6 +124,7 @@ module JamRuby validates :terms_of_service, :acceptance => {:accept => true, :on => :create, :allow_nil => false } validates :subscribe_email, :inclusion => {:in => [nil, true, false]} validates :musician, :inclusion => {:in => [true, false]} + validates :show_whats_next, :inclusion => {:in => [nil, true, false]} # custom validators validate :validate_musician_instruments @@ -651,7 +652,7 @@ module JamRuby # throws ActiveRecord::RecordNotFound if instrument is invalid # throws an email delivery error if unable to connect out to SMTP - def self.signup(first_name, last_name, email, password, password_confirmation, terms_of_service, subscribe_email, + def self.signup(first_name, last_name, email, password, password_confirmation, terms_of_service, location, instruments, birth_date, musician, photo_url, invited_user, signup_confirm_url) user = User.new @@ -659,7 +660,7 @@ module JamRuby user.first_name = first_name user.last_name = last_name user.email = email - user.subscribe_email = subscribe_email + user.subscribe_email = true user.terms_of_service = terms_of_service user.musician = musician diff --git a/web/Gemfile b/web/Gemfile index 9f6af9081..80a543947 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -88,14 +88,13 @@ end gem 'capybara-screenshot' gem 'cucumber-rails', :require => false #, '1.3.0', :require => false gem 'factory_girl_rails', '4.1.0' - gem 'database_cleaner', '0.7.0' gem 'guard-spork', '0.3.2' gem 'spork', '0.9.0' gem 'launchy', '2.1.0' gem 'rack-test' # gem 'rb-fsevent', '0.9.1', :require => false # gem 'growl', '1.0.3' - gem 'poltergeist' , '1.4.1' # can't go to 1.4.0 until this is fixed https://github.com/jonleighton/poltergeist/issues/385 + gem 'poltergeist' end diff --git a/web/app/assets/images/content/button_download_linux.png b/web/app/assets/images/content/button_download_linux.png new file mode 100644 index 000000000..b271f72d2 Binary files /dev/null and b/web/app/assets/images/content/button_download_linux.png differ diff --git a/web/app/assets/images/content/button_download_mac.png b/web/app/assets/images/content/button_download_mac.png new file mode 100644 index 000000000..7a301312a Binary files /dev/null and b/web/app/assets/images/content/button_download_mac.png differ diff --git a/web/app/assets/images/content/button_download_other_linux.png b/web/app/assets/images/content/button_download_other_linux.png new file mode 100644 index 000000000..83aec944c Binary files /dev/null and b/web/app/assets/images/content/button_download_other_linux.png differ diff --git a/web/app/assets/images/content/button_download_other_mac.png b/web/app/assets/images/content/button_download_other_mac.png new file mode 100644 index 000000000..8f63820dc Binary files /dev/null and b/web/app/assets/images/content/button_download_other_mac.png differ diff --git a/web/app/assets/images/content/button_download_other_windows.png b/web/app/assets/images/content/button_download_other_windows.png new file mode 100644 index 000000000..d857bf373 Binary files /dev/null and b/web/app/assets/images/content/button_download_other_windows.png differ diff --git a/web/app/assets/images/content/button_download_windows.png b/web/app/assets/images/content/button_download_windows.png new file mode 100644 index 000000000..fd240ee35 Binary files /dev/null and b/web/app/assets/images/content/button_download_windows.png differ diff --git a/web/app/assets/images/content/ftue_whatsnext_create.png b/web/app/assets/images/content/ftue_whatsnext_create.png new file mode 100644 index 000000000..08d6ce6fa Binary files /dev/null and b/web/app/assets/images/content/ftue_whatsnext_create.png differ diff --git a/web/app/assets/images/content/ftue_whatsnext_musicians.png b/web/app/assets/images/content/ftue_whatsnext_musicians.png new file mode 100644 index 000000000..56804d7d9 Binary files /dev/null and b/web/app/assets/images/content/ftue_whatsnext_musicians.png differ diff --git a/web/app/assets/images/content/ftue_whatsnext_videos.png b/web/app/assets/images/content/ftue_whatsnext_videos.png new file mode 100644 index 000000000..860c0f1c2 Binary files /dev/null and b/web/app/assets/images/content/ftue_whatsnext_videos.png differ diff --git a/web/app/assets/images/web/Bullet-Black.png b/web/app/assets/images/web/Bullet-Black.png new file mode 100755 index 000000000..ef28ebc35 Binary files /dev/null and b/web/app/assets/images/web/Bullet-Black.png differ diff --git a/web/app/assets/images/web/Bullet-White.png b/web/app/assets/images/web/Bullet-White.png new file mode 100755 index 000000000..5b373a1c7 Binary files /dev/null and b/web/app/assets/images/web/Bullet-White.png differ diff --git a/web/app/assets/images/web/bkg_corporate.gif b/web/app/assets/images/web/bkg_corporate.gif new file mode 100644 index 000000000..c0f94155e Binary files /dev/null and b/web/app/assets/images/web/bkg_corporate.gif differ diff --git a/web/app/assets/images/web/bkg_home.gif b/web/app/assets/images/web/bkg_home.gif new file mode 100644 index 000000000..dd9434401 Binary files /dev/null and b/web/app/assets/images/web/bkg_home.gif differ diff --git a/web/app/assets/images/web/carousel_bands.jpg b/web/app/assets/images/web/carousel_bands.jpg new file mode 100644 index 000000000..309366d68 Binary files /dev/null and b/web/app/assets/images/web/carousel_bands.jpg differ diff --git a/web/app/assets/images/web/carousel_fans.jpg b/web/app/assets/images/web/carousel_fans.jpg new file mode 100644 index 000000000..929864c5b Binary files /dev/null and b/web/app/assets/images/web/carousel_fans.jpg differ diff --git a/web/app/assets/images/web/carousel_musicians.jpg b/web/app/assets/images/web/carousel_musicians.jpg new file mode 100644 index 000000000..74d0fe73a Binary files /dev/null and b/web/app/assets/images/web/carousel_musicians.jpg differ diff --git a/web/app/assets/images/web/cta_button.png b/web/app/assets/images/web/cta_button.png new file mode 100644 index 000000000..cca3f358a Binary files /dev/null and b/web/app/assets/images/web/cta_button.png differ diff --git a/web/app/assets/images/web/icon_pdf.png b/web/app/assets/images/web/icon_pdf.png new file mode 100644 index 000000000..a08a55700 Binary files /dev/null and b/web/app/assets/images/web/icon_pdf.png differ diff --git a/web/app/assets/images/web/icon_pr.png b/web/app/assets/images/web/icon_pr.png new file mode 100644 index 000000000..99d0e7aae Binary files /dev/null and b/web/app/assets/images/web/icon_pr.png differ diff --git a/web/app/assets/images/web/icon_product.png b/web/app/assets/images/web/icon_product.png new file mode 100644 index 000000000..739cf6200 Binary files /dev/null and b/web/app/assets/images/web/icon_product.png differ diff --git a/web/app/assets/images/web/icon_users.png b/web/app/assets/images/web/icon_users.png new file mode 100644 index 000000000..889d5395f Binary files /dev/null and b/web/app/assets/images/web/icon_users.png differ diff --git a/web/app/assets/images/web/logo_corporate.png b/web/app/assets/images/web/logo_corporate.png new file mode 100644 index 000000000..529cff728 Binary files /dev/null and b/web/app/assets/images/web/logo_corporate.png differ diff --git a/web/app/assets/images/web/logo_home.png b/web/app/assets/images/web/logo_home.png new file mode 100644 index 000000000..d7482a85d Binary files /dev/null and b/web/app/assets/images/web/logo_home.png differ diff --git a/web/app/assets/images/web/next_button.png b/web/app/assets/images/web/next_button.png new file mode 100755 index 000000000..dc45fd579 Binary files /dev/null and b/web/app/assets/images/web/next_button.png differ diff --git a/web/app/assets/images/web/prev_button.png b/web/app/assets/images/web/prev_button.png new file mode 100755 index 000000000..445d40377 Binary files /dev/null and b/web/app/assets/images/web/prev_button.png differ diff --git a/web/app/assets/images/web/shadowLeft.png b/web/app/assets/images/web/shadowLeft.png new file mode 100755 index 000000000..74d131262 Binary files /dev/null and b/web/app/assets/images/web/shadowLeft.png differ diff --git a/web/app/assets/images/web/shadowLeft8.png b/web/app/assets/images/web/shadowLeft8.png new file mode 100755 index 000000000..c4b7bc6aa Binary files /dev/null and b/web/app/assets/images/web/shadowLeft8.png differ diff --git a/web/app/assets/images/web/shadowMiddle8.png b/web/app/assets/images/web/shadowMiddle8.png new file mode 100755 index 000000000..a4381df28 Binary files /dev/null and b/web/app/assets/images/web/shadowMiddle8.png differ diff --git a/web/app/assets/images/web/shadowRight.png b/web/app/assets/images/web/shadowRight.png new file mode 100755 index 000000000..56f1a7d86 Binary files /dev/null and b/web/app/assets/images/web/shadowRight.png differ diff --git a/web/app/assets/images/web/shadowTile.png b/web/app/assets/images/web/shadowTile.png new file mode 100755 index 000000000..ad9e48ab3 Binary files /dev/null and b/web/app/assets/images/web/shadowTile.png differ diff --git a/web/app/assets/images/web/video.png b/web/app/assets/images/web/video.png new file mode 100755 index 000000000..05960f0ac Binary files /dev/null and b/web/app/assets/images/web/video.png differ diff --git a/web/app/assets/javascripts/accounts.js b/web/app/assets/javascripts/accounts.js index 50a79821b..c01cb12ed 100644 --- a/web/app/assets/javascripts/accounts.js +++ b/web/app/assets/javascripts/accounts.js @@ -91,12 +91,12 @@ function navToEditIdentity() { resetForm() - window.location = '#/account/identity' + window.location = '/client#/account/identity' } function navToEditProfile() { resetForm() - window.location = '#/account/profile' + window.location = '/client#/account/profile' } function navToEditSubscriptions() { @@ -109,7 +109,7 @@ function navToEditAudio() { resetForm() - window.location = "#/account/audio" + window.location = "/client#/account/audio" } // handle update avatar event diff --git a/web/app/assets/javascripts/accounts_identity.js b/web/app/assets/javascripts/accounts_identity.js index 27f71ec2f..66a1d80a6 100644 --- a/web/app/assets/javascripts/accounts_identity.js +++ b/web/app/assets/javascripts/accounts_identity.js @@ -74,7 +74,7 @@ function navToAccount() { resetForm(); - window.location = '#/account'; + window.location = '/client#/account'; } function handleUpdateEmail() { diff --git a/web/app/assets/javascripts/accounts_profile.js b/web/app/assets/javascripts/accounts_profile.js index 97f563159..25716900d 100644 --- a/web/app/assets/javascripts/accounts_profile.js +++ b/web/app/assets/javascripts/accounts_profile.js @@ -38,7 +38,8 @@ last_name: userDetail.last_name, user_instruments: userDetail.instruments, birth_date : userDetail.birth_date, - gender: userDetail.gender + gender: userDetail.gender, + subscribe_email: userDetail.subscribe_email ? "checked=checked" : "" }); var content_root = $('#account-profile-content-scroller') @@ -263,12 +264,12 @@ function navToAccount() { resetForm(); - window.location = '#/account'; + window.location = '/client#/account'; } function navToAvatar() { resetForm(); - window.location = '#/account/profile/avatar'; + window.location = '/client#/account/profile/avatar'; } function handleUpdateProfile() { @@ -280,11 +281,12 @@ var city = getCityElement().val(); var firstName = getFirstNameElement().val(); var lastName = getLastNameElement().val(); - var gender = getGenderElement().val() + var gender = getGenderElement().val(); + var subscribeEmail = getSubscribeEmail().is(':checked'); var birthDate = getBirthDate(); var instruments = getInstrumentsValue(); - postUpdateProfile({ + api.updateUser({ country: country, state: region, city: city, @@ -292,25 +294,13 @@ last_name: lastName, gender: gender, birth_date: birthDate, - instruments: instruments + instruments: instruments, + subscribe_email: subscribeEmail }) .done(postUpdateProfileSuccess) .fail(postUpdateProfileFailure) } - function postUpdateProfile(options) { - - var url = "/api/users/" + context.JK.currentUserId; - return $.ajax({ - type: "POST", - dataType: "json", - contentType: 'application/json', - url: url, - data: JSON.stringify(options), - processData: false - }); - } - function postUpdateProfileSuccess(response) { app.notify( { title: "Profile Changed", @@ -332,6 +322,7 @@ var city = context.JK.format_errors("city", errors); var birth_date = context.JK.format_errors("birth_date", errors); var gender = context.JK.format_errors("birth_date", errors); + var subscribeEmail = context.JK.format_errors("subscribe_email", errors); var instruments = context.JK.format_errors("musician_instruments", errors) if(first_name != null) { @@ -358,6 +349,10 @@ getYearElement().closest('div.field').addClass('error').end().after(birth_date); } + if(subscribeEmail != null) { + getSubscribeEmail().closest('div.field').addClass('error').end().after(subscribeEmail); + } + if(gender != null) { getGenderElement().closest('div.field').addClass('error').end().after(gender); } @@ -480,6 +475,10 @@ return $('#account-profile-content-scroller select#user_birth_date_1i'); } + function getSubscribeEmail() { + return $('#account-profile-content-scroller input[name=subscribe_email]'); + } + function getInstrumentsElement() { return $('#account-profile-content-scroller .instrument_selector'); } diff --git a/web/app/assets/javascripts/accounts_profile_avatar.js b/web/app/assets/javascripts/accounts_profile_avatar.js index 4f1757f30..48bbfc20d 100644 --- a/web/app/assets/javascripts/accounts_profile_avatar.js +++ b/web/app/assets/javascripts/accounts_profile_avatar.js @@ -15,6 +15,7 @@ var selection = null; var targetCropSize = 88; var updatingAvatar = false; + var userDropdown; function beforeShow(data) { userId = data.id; @@ -92,7 +93,7 @@ function deleteAvatarSuccess(response) { renderAvatar(null, null); - JK.Header.loadMe(); + userDropdown.loadMe(); rest.getUserDetail() .done(function(userDetail) { @@ -139,7 +140,7 @@ function navToEditProfile() { resetForm(); - window.location = '#/account/profile' + window.location = '/client#/account/profile' } function renderAvatarSpinner() { @@ -306,8 +307,9 @@ quality: 90, policy: filepickerPolicy.policy, signature: filepickerPolicy.signature - }, { path: createStorePath(self.userDetail) + 'cropped.jpg', access: 'public' }, + }, { path: createStorePath(self.userDetail) + 'cropped-' + new Date().getTime() + '.jpg', access: 'public' }, function(cropped) { + logger.debug("converting cropped"); rest.getFilepickerPolicy({handle: cropped.url, convert: true}) .done(function(filepickerPolicy) { filepicker.convert(cropped, { @@ -320,6 +322,7 @@ signature: filepickerPolicy.signature }, { path: createStorePath(self.userDetail), access: 'public' }, function(scaled) { + logger.debug("converted and scaled final image %o", scaled); rest.updateAvatar({ original_fpfile: determineCurrentFpfile(), cropped_fpfile: scaled, @@ -361,7 +364,7 @@ self.userDetail = response; // notify any listeners that the avatar changed - JK.Header.loadMe(); + userDropdown.loadMe(); // $('.avatar_large img').trigger('avatar_changed', [self.userDetail.photo_url]); app.notify( @@ -414,13 +417,15 @@ return $.cookie('original_fpfile') == null ? userDetail.crop_selection : null; } - function initialize() { + function initialize(userDropdownInstance) { var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow }; app.bindScreen('account/profile/avatar', screenBindings); events(); + + userDropdown = userDropdownInstance; } this.initialize = initialize; diff --git a/web/app/assets/javascripts/addNewGear.js b/web/app/assets/javascripts/addNewGear.js index b12573b9c..4d7ba9907 100644 --- a/web/app/assets/javascripts/addNewGear.js +++ b/web/app/assets/javascripts/addNewGear.js @@ -14,7 +14,6 @@ // ON TOP OF OTHER DIALOGS. ANY OTHER DIALOGS THAT // USE THIS NEED TO BE ADDED TO THE FOLLOWING LIST. // NEED TO FIGURE OUT A CLEANER WAY TO HANDLE THIS. - app.layout.closeDialog('add-track'); app.layout.closeDialog('configure-audio'); }); diff --git a/web/app/assets/javascripts/application.js b/web/app/assets/javascripts/application.js index 9f73afcd2..91cc6c0f6 100644 --- a/web/app/assets/javascripts/application.js +++ b/web/app/assets/javascripts/application.js @@ -12,10 +12,10 @@ // //= require jquery //= require jquery_ujs +//= require jquery.icheck //= require jquery.color //= require jquery.cookie //= require jquery.Jcrop //= require jquery.naturalsize //= require jquery.queryparams -//= require bootstrap //= require_directory . diff --git a/web/app/assets/javascripts/configureTrack.js b/web/app/assets/javascripts/configureTrack.js index 4470c0599..01b32d7c5 100644 --- a/web/app/assets/javascripts/configureTrack.js +++ b/web/app/assets/javascripts/configureTrack.js @@ -41,17 +41,17 @@ var originalVoiceChat; var configure_audio_instructions = { - "Win32": "Choose the audio profile you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + + "Win32": "Choose the audio device you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + "to your tracks, to indicate what instrument you are playing on each track, and to assign audio outputs for listening. " + "If you want to use a new audio device you have not tested/certified for latency using JamKazam, click the Add New Audio " + "Gear button to test that device.", - "MacOSX": "Choose the audio profile you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + + "MacOSX": "Choose the audio device you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + "to your tracks, to indicate what instrument you are playing on each track, and to assign audio outputs for listening. " + "If you want to use a new audio device you have not tested/certified for latency using JamKazam, click the Add New Audio " + "Gear button to test that device.", - "Unix": "Choose the audio profile you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + + "Unix": "Choose the audio device you would like to use for this session. If needed, use arrow buttons to assign audio inputs " + "to your tracks, to indicate what instrument you are playing on each track, and to assign audio outputs for listening. " + "If you want to use a new audio device you have not tested/certified for latency using JamKazam, click the Add New Audio " + "Gear button to test that device." @@ -61,25 +61,6 @@ "for both music and chat. Otherwise, choose a device to use for voice chat, and use arrow buttons to " + "select an input on that device."; - function toggleTrack2ConfigDetails(visible) { - if (visible) { - $('#track2-details').show(); - $('#track2-input-buttons').show(); - $('#track1-input').height('92px'); - $('#track1-instrument').height('92px'); - $('#track1-input-buttons').addClass('mt30'); - $('#track1-input-buttons').removeClass('mt65'); - } - else { - $('#track2-details').hide(); - $('#track2-input-buttons').hide(); - $('#track1-input').height('195px'); - $('#track1-instrument').height('195px'); - $('#track1-input-buttons').addClass('mt65'); - $('#track1-input-buttons').removeClass('mt30'); - } - } - function events() { // Music Audio Tab @@ -425,15 +406,12 @@ context.JK.loadOptions($('#template-option').html(), $('#track1-instrument'), instrument_array, "id", "description", current_instrument); - // load Track 2 config details if necessary - if (myTrackCount > 1) { - // load Track 2 Input(s) - context.JK.loadOptions($('#template-option').html(), $('#track2-input'), track2AudioInputChannels, "id", "name", -1); + // load Track 2 Input(s) + context.JK.loadOptions($('#template-option').html(), $('#track2-input'), track2AudioInputChannels, "id", "name", -1); - // load Track 2 Instrument - current_instrument = context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK2); - context.JK.loadOptions($('#template-option').html(), $('#track2-instrument'), instrument_array, "id", "description", current_instrument); - } + // load Track 2 Instrument + current_instrument = context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK2); + context.JK.loadOptions($('#template-option').html(), $('#track2-instrument'), instrument_array, "id", "description", current_instrument); // load Unused Outputs context.JK.loadOptions($('#template-option').html(), $('#audio-output-unused'), outputUnassignedList, "id", "name", -1); @@ -614,29 +592,52 @@ context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK1, instrumentVal); // UPDATE SERVER - //logger.debug("Updating track " + myTracks[0].trackId + " with instrument " + instrumentText); + logger.debug("Updating track " + myTracks[0].trackId + " with instrument " + instrumentText); var data = {}; data.instrument_id = instrumentText; sessionModel.updateTrack(sessionId, myTracks[0].trackId, data); - if (myTrackCount > 1) { - // TRACK 2 INPUTS - $('#track2-input > option').each(function() { - logger.debug("Saving track 2 input = " + this.value); - context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2); - }); + // TRACK 2 INPUTS + var track2Selected = false; + $('#track2-input > option').each(function() { + track2Selected = true; + logger.debug("Saving track 2 input = " + this.value); + context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2); + }); + if (track2Selected) { // TRACK 2 INSTRUMENT instrumentVal = $('#track2-instrument').val(); instrumentText = $('#track2-instrument > option:selected').text().toLowerCase(); + + // track 2 new - add + if (myTrackCount === 1) { + data = {}; + // use the first track's connection_id (not sure why we need this on the track data model) + logger.debug("myTracks[0].connection_id=" + myTracks[0].connection_id); + data.connection_id = myTracks[0].connection_id; + data.instrument_id = instrumentText; + data.sound = "stereo"; + sessionModel.addTrack(sessionId, data); + } + // track 2 exists - update + else if (myTrackCount === 2) { + // UPDATE SERVER + logger.debug("Updating track " + myTracks[1].trackId + " with instrument " + instrumentText); + data = {}; + data.instrument_id = instrumentText; + sessionModel.updateTrack(sessionId, myTracks[1].trackId, data); + } logger.debug("Saving track 2 instrument = " + instrumentVal); context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK2, instrumentVal); - - // UPDATE SERVER - //logger.debug("Updating track " + myTracks[1].trackId + " with instrument " + instrumentText); - data.instrument_id = instrumentText; - sessionModel.updateTrack(sessionId, myTracks[1].trackId, data); + } + else { + // track 2 was removed + if (myTrackCount === 2) { + logger.debug("Deleting track " + myTracks[1].trackId); + sessionModel.deleteTrack(sessionId, myTracks[1].trackId); + } } // UNASSIGNED OUTPUTS @@ -695,7 +696,7 @@ function validateAudioSettings(allowEmptyInput) { var isValid = true; - var noTrackErrMsg = 'You must assign at least one input port to each of your tracks. Please update your settings to correct this. If you want to delete a track, please return to the session screen and delete the track by clicking the "x" box in the upper right-hand corner of the track.'; + var noTrackErrMsg = 'You must assign at least one input port to each of your tracks. Please update your settings to correct this.'; var noInstrumentErrMsg = 'You must specify what instrument is being played for each track. Please update your settings to correct this.'; var outputErrMsg = 'You must assign two output ports for stereo session audio to hear music. Please update your settings to correct this.'; @@ -723,8 +724,8 @@ logger.debug("validateAudioSettings:myTrackCount=" + myTrackCount); // if Track 2 exists, verify Input and Instrument exist - if (isValid && myTrackCount > 1) { - if ($('#track2-input > option').size() === 0 || $('#track2-input > option').size() > 2) { + if (isValid) { + if ($('#track2-input > option').size() > 2) { errMsg = noTrackErrMsg; isValid = false; } @@ -834,7 +835,6 @@ _init(); myTrackCount = myTracks.length; logger.debug("initialize:myTrackCount=" + myTrackCount); - toggleTrack2ConfigDetails(myTrackCount > 1); }; this.showMusicAudioPanel = showMusicAudioPanel; diff --git a/web/app/assets/javascripts/createSession.js b/web/app/assets/javascripts/createSession.js index a8520ec94..fe19afe00 100644 --- a/web/app/assets/javascripts/createSession.js +++ b/web/app/assets/javascripts/createSession.js @@ -7,7 +7,7 @@ var logger = context.JK.logger; var realtimeMessaging = context.JK.JamServer; var friendSelectorDialog = new context.JK.FriendSelectorDialog(app, friendSelectorCallback); - var invitationDialog = new context.JK.InvitationDialog(app); + var invitationDialog = null; var autoComplete = null; var userNames = []; var userIds = []; @@ -100,7 +100,7 @@ } function resetForm() { - $('#intellectual-property').attr('checked', false); + $('#intellectual-property').iCheck('uncheck').attr('checked', false); var $form = $('#create-session-form'); var description = sessionSettings.hasOwnProperty('description') ? sessionSettings.description : ''; @@ -114,7 +114,7 @@ if (musician_access) { var approval_required = sessionSettings.hasOwnProperty('approval_required') ? sessionSettings.approval_required : false; - $('#musician-access-option-' + approval_required).attr('checked', 'checked'); + $('#musician-access-option-' + approval_required).iCheck('check').attr('checked', 'checked'); } var fan_access = sessionSettings.hasOwnProperty('fan_access') ? sessionSettings.fan_access : true; @@ -123,7 +123,7 @@ if (fan_access) { var fan_chat = sessionSettings.hasOwnProperty('fan_chat') ? sessionSettings.fan_chat : false; - $('#fan-chat-option-' + fan_chat).attr('checked', 'checked'); + $('#fan-chat-option-' + fan_chat).iCheck('check').attr('checked', 'checked'); } // Should easily be able to grab other items out of sessionSettings and put them into the appropriate ui elements. } @@ -293,7 +293,7 @@ friendSelectorDialog.showDialog(selectedFriendIds); }); - $('.btn-email-invitation').click(function() { + $('div[layout-id="createSession"] .btn-email-invitation').click(function() { invitationDialog.showEmailDialog(); }); @@ -374,6 +374,15 @@ resetForm(); } + // this exists solely due to a bug in Windows QTWebkit: https://bugreports.qt-project.org/browse/QTBUG-30072 + function initializeButtons() { + $('div[layout-id="createSession"] .icheckbuttons input').iCheck({ + checkboxClass: 'icheckbox_minimal', + radioClass: 'iradio_minimal', + inheritClass: true + }); + } + function searchFriends(query) { if (query.length < 2) { $('#friend-search-results').empty(); @@ -403,12 +412,13 @@ }); } - function initialize() { + function initialize(invitationDialogInstance) { friendSelectorDialog.initialize(); - invitationDialog.initialize(); + invitationDialog = invitationDialogInstance; events(); loadBands(); loadSessionSettings(); + initializeButtons(); var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow }; app.bindScreen('createSession', screenBindings); } diff --git a/web/app/assets/javascripts/header.js b/web/app/assets/javascripts/header.js index 9bb52535f..02575410f 100644 --- a/web/app/assets/javascripts/header.js +++ b/web/app/assets/javascripts/header.js @@ -1,7 +1,7 @@ (function(context,$) { /** - * Javascript for managing the header (account dropdown) as well + * Javascript for managing the header as well * as any dialogs reachable from there. Account settings dialog. */ @@ -17,8 +17,7 @@ var instrumentIds = []; var instrumentNames = []; var instrumentPopularities = {}; // id -> popularity - var invitationDialog = new context.JK.InvitationDialog(app); - var rest = new JK.Rest(); + function loadInstruments() { // TODO: This won't work in the long-term. We'll need to provide @@ -98,45 +97,10 @@ context.location = '#/home'; }); - $('.userinfo').on('click', function() { - $('ul.shortcuts', this).toggle(); - }); - - $('.userinfo .invite-friends .menuheader').on('click', function(e) { - $(this).closest('li').css('height', 'auto').find('ul').toggle(); - e.stopPropagation(); - return false; - }); - - /** - $('.userinfo .sign-out a').on('click', function(e) { - e.stopPropagation(); - - /** rest.signout() - .done(function() { - - }) - - }); */ - - $('.invite-friends .google-invite a').on('click', function(e) { - invitationDialog.showGoogleDialog(); - }); - - $('.invite-friends .email-invite a').on('click', function(e) { - invitationDialog.showEmailDialog(); - }) - $('#account-identity-form').submit(handleIdentitySubmit); $('#account-profile-form').submit(handleProfileSubmit); // Remove added instruments when 'X' is clicked $('#added-profile-instruments').on("click", ".instrument span", removeInvitation); - - $('#header-avatar').on('avatar_changed', function(event, newAvatarUrl) { - updateAvatar(newAvatarUrl); - event.preventDefault(); - return false; - }) } function handleIdentitySubmit(evt) { @@ -194,52 +158,12 @@ return false; } - function loadMe() { - $.ajax({ - url: '/api/users/' + context.JK.currentUserId - }).done(function(r) { - userMe = r; - // TODO - Setting global variable for local user. - context.JK.userMe = r; - updateHeader(); - }).fail(app.ajaxError); - } - - function updateHeader() { - - $('#user').html(userMe.name); - showAvatar(); - } - - // initially show avatar - function showAvatar() { - var photoUrl = context.JK.resolveAvatarUrl(userMe.photo_url); - $('#header-avatar').attr('src', photoUrl); - } - - // handle update avatar event - function updateAvatar(avatar_url) { - var photoUrl = context.JK.resolveAvatarUrl(avatar_url); - var avatar = $(new Image()); - avatar.attr('src', photoUrl + '?cache_bust=' + new Date().getTime()); - avatar.attr('alt', "Avatar"); - avatar.attr('id', 'header-avatar'); - $('#header-avatar').replaceWith(avatar); - } - this.initialize = function() { - events(); loadInstruments(); - loadMe(); - invitationDialog.initialize(); - - //searcher = new context.JK.Searcher(app); //searcher.initialize(); }; - - this.loadMe = loadMe; }; })(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/homeScreen.js b/web/app/assets/javascripts/homeScreen.js index 56e802e0d..9f94bc624 100644 --- a/web/app/assets/javascripts/homeScreen.js +++ b/web/app/assets/javascripts/homeScreen.js @@ -8,17 +8,6 @@ var isFtueComplete = false; function beforeShow(data) { - refreshDeviceState(); - } - - function refreshDeviceState() { - isFtueComplete = checkDeviceState(); - updateTiles(); - } - - function checkDeviceState() { - var devices = context.jamClient.TrackGetDevices(); - return Object.keys(devices).length > 0; } function mouseenterTile() { @@ -49,19 +38,7 @@ } function userHasDevices() { - var $createSession = $('div[type="createSession"]'); - var $findSession = $('div[type="findSession"]'); - $createSession.attr('layout-link', 'createSession'); - $findSession.attr('layout-link', 'findSession'); - - // undo any earlier disabling - $('h2', $createSession).removeClass('disabled'); - $('h2', $findSession).removeClass('disabled'); - $createSession.removeClass('createsession-disabled'); - $createSession.addClass('createsession'); - $findSession.removeClass('findsession-disabled'); - $findSession.addClass('findsession'); // and enable features $($createSession).on('mouseenter', mouseenterTile); @@ -97,36 +74,22 @@ // used to initialize things that do not have to be touched up in the same UI sessiion function events() { // initialize profile, feed and account tiles normally - $('.homecard.profile, .homecard.feed, .homecard.account').on('mouseenter', mouseenterTile); - $('.homecard.profile, .homecard.feed, .homecard.account').on('mouseleave', mouseleaveTile); - $('div[layout-id=ftue]').on("ftue_success", refreshDeviceState); + $('.homecard').on('mouseenter', mouseenterTile); + $('.homecard').on('mouseleave', mouseleaveTile); + if(gon.allow_force_native_client) { $('body').on('keyup', switchClientMode); } } - function updateTiles() { - logger.debug("isFtueComplete=" + isFtueComplete); - - if(isFtueComplete) { - userHasDevices(); - } - else { - userHasNoDevices(); - } - - $('.profile').on('click', function() { - context.location = '#/profile/' + context.JK.currentUserId; - }); - } - - this.initialize = function() { var screenBindings = { 'beforeShow': beforeShow }; app.bindScreen('home', screenBindings); events(); - + $('.profile').on('click', function() { + context.location = '#/profile/' + context.JK.currentUserId; + }); }; this.beforeShow = beforeShow; diff --git a/web/app/assets/javascripts/invitationDialog.js b/web/app/assets/javascripts/invitationDialog.js index f6598ff72..a3c569f59 100644 --- a/web/app/assets/javascripts/invitationDialog.js +++ b/web/app/assets/javascripts/invitationDialog.js @@ -106,7 +106,6 @@ $('#btn-send-invitation').show(); $('#btn-next-invitation').hide(); clearTextFields(); - app.layout.showDialog('inviteUsers') } diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 376626928..ea66bcbec 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -293,6 +293,21 @@ }); } + function updateUser(options) { + var id = getId(options); + + delete options['id']; + + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + id, + data: JSON.stringify(options), + processData: false + }); + } + function initialize() { return self; } @@ -322,6 +337,7 @@ this.userSocialPromoted = userSocialPromoted; this.createJoinRequest = createJoinRequest; this.updateJoinRequest = updateJoinRequest; + this.updateUser = updateUser; return this; }; diff --git a/web/app/assets/javascripts/jamkazam.js b/web/app/assets/javascripts/jamkazam.js index 9ac210a95..6fade3525 100644 --- a/web/app/assets/javascripts/jamkazam.js +++ b/web/app/assets/javascripts/jamkazam.js @@ -28,7 +28,10 @@ var heartbeatAckCheckInterval = null; var opts = { - layoutOpts: {} + inClient: true, // specify false if you want the app object but none of the client-oriented features + layoutOpts: { + layoutFooter: true // specify false if you want footer to be left alone + } }; /** @@ -89,7 +92,6 @@ function loggedIn(header, payload) { app.clientId = payload.client_id; $.cookie('client_id', payload.client_id); - // $.cookie('remember_token', payload.token); // removed per vrfs-273/403 heartbeatMS = payload.heartbeat_interval * 1000; logger.debug("jamkazam.js.loggedIn(): clientId now " + app.clientId + "; Setting up heartbeat every " + heartbeatMS + " MS"); @@ -279,14 +281,17 @@ this.opts = $.extend(opts, inOpts); this.layout = new context.JK.Layout(); this.layout.initialize(this.opts.layoutOpts); - registerLoginAck(); - registerHeartbeatAck(); - registerBadStateRecovered(); - registerBadStateError(); - registerSocketClosed(); events(); - context.JK.FaderHelpers.initialize(); - context.window.onunload = this.unloadFunction; + + if(opts.inClient) { + registerLoginAck(); + registerHeartbeatAck(); + registerBadStateRecovered(); + registerBadStateError(); + registerSocketClosed(); + context.JK.FaderHelpers.initialize(); + context.window.onunload = this.unloadFunction; + } }; diff --git a/web/app/assets/javascripts/jquery.hoverIntent.js b/web/app/assets/javascripts/jquery.hoverIntent.js index 3dcff261f..bc1637354 100644 --- a/web/app/assets/javascripts/jquery.hoverIntent.js +++ b/web/app/assets/javascripts/jquery.hoverIntent.js @@ -1,106 +1,115 @@ -/** -* hoverIntent is similar to jQuery's built-in "hover" function except that -* instead of firing the onMouseOver event immediately, hoverIntent checks -* to see if the user's mouse has slowed down (beneath the sensitivity -* threshold) before firing the onMouseOver event. -* -* hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+ -* -* -* hoverIntent is currently available for use in all personal or commercial -* projects under both MIT and GPL licenses. This means that you can choose -* the license that best suits your project, and use it accordingly. -* -* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions -* $("ul li").hoverIntent( showNav , hideNav ); -* -* // advanced usage receives configuration object only -* $("ul li").hoverIntent({ -* sensitivity: 7, // number = sensitivity threshold (must be 1 or higher) -* interval: 100, // number = milliseconds of polling interval -* over: showNav, // function = onMouseOver callback (required) -* timeout: 0, // number = milliseconds delay before onMouseOut function call -* out: hideNav // function = onMouseOut callback (required) -* }); -* -* @param f onMouseOver function || An object with configuration options -* @param g onMouseOut function || Nothing (use configuration options object) -* @author Brian Cherne brian(at)cherne(dot)net -*/ +/*! + * hoverIntent r7 // 2013.03.11 // jQuery 1.9.1+ + * http://cherne.net/brian/resources/jquery.hoverIntent.html + * + * You may use hoverIntent under the terms of the MIT license. Basically that + * means you are free to use hoverIntent as long as this header is left intact. + * Copyright 2007, 2013 Brian Cherne + */ + +/* hoverIntent is similar to jQuery's built-in "hover" method except that + * instead of firing the handlerIn function immediately, hoverIntent checks + * to see if the user's mouse has slowed down (beneath the sensitivity + * threshold) before firing the event. The handlerOut function is only + * called after a matching handlerIn. + * + * // basic usage ... just like .hover() + * .hoverIntent( handlerIn, handlerOut ) + * .hoverIntent( handlerInOut ) + * + * // basic usage ... with event delegation! + * .hoverIntent( handlerIn, handlerOut, selector ) + * .hoverIntent( handlerInOut, selector ) + * + * // using a basic configuration object + * .hoverIntent( config ) + * + * @param handlerIn function OR configuration object + * @param handlerOut function OR selector for delegation OR undefined + * @param selector selector OR undefined + * @author Brian Cherne + */ (function($) { - $.fn.hoverIntent = function(f,g) { - // default configuration options - var cfg = { - sensitivity: 7, - interval: 100, - timeout: 0 - }; - // override configuration options with user supplied object - cfg = $.extend(cfg, g ? { over: f, out: g } : f ); + $.fn.hoverIntent = function(handlerIn,handlerOut,selector) { - // instantiate variables - // cX, cY = current X and Y position of mouse, updated by mousemove event - // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval - var cX, cY, pX, pY; + // default configuration values + var cfg = { + interval: 100, + sensitivity: 7, + timeout: 0 + }; - // A private function for getting mouse position - var track = function(ev) { - cX = ev.pageX; - cY = ev.pageY; - }; + if ( typeof handlerIn === "object" ) { + cfg = $.extend(cfg, handlerIn ); + } else if ($.isFunction(handlerOut)) { + cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } ); + } else { + cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } ); + } - // A private function for comparing current and previous mouse position - var compare = function(ev,ob) { - ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); - // compare mouse positions to see if they've crossed the threshold - if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) { - $(ob).unbind("mousemove",track); - // set hoverIntent state to true (so mouseOut can be called) - ob.hoverIntent_s = 1; - return cfg.over.apply(ob,[ev]); - } else { - // set previous coordinates for next time - pX = cX; pY = cY; - // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs) - ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval ); - } - }; + // instantiate variables + // cX, cY = current X and Y position of mouse, updated by mousemove event + // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval + var cX, cY, pX, pY; - // A private function for delaying the mouseOut function - var delay = function(ev,ob) { - ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); - ob.hoverIntent_s = 0; - return cfg.out.apply(ob,[ev]); - }; + // A private function for getting mouse position + var track = function(ev) { + cX = ev.pageX; + cY = ev.pageY; + }; - // A private function for handling mouse 'hovering' - var handleHover = function(e) { - // copy objects to be passed into t (required for event object to be passed in IE) - var ev = jQuery.extend({},e); - var ob = this; + // A private function for comparing current and previous mouse position + var compare = function(ev,ob) { + ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); + // compare mouse positions to see if they've crossed the threshold + if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) { + $(ob).off("mousemove.hoverIntent",track); + // set hoverIntent state to true (so mouseOut can be called) + ob.hoverIntent_s = 1; + return cfg.over.apply(ob,[ev]); + } else { + // set previous coordinates for next time + pX = cX; pY = cY; + // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs) + ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval ); + } + }; - // cancel hoverIntent timer if it exists - if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); } + // A private function for delaying the mouseOut function + var delay = function(ev,ob) { + ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); + ob.hoverIntent_s = 0; + return cfg.out.apply(ob,[ev]); + }; - // if e.type == "mouseenter" - if (e.type == "mouseenter") { - // set "previous" X and Y position based on initial entry point - pX = ev.pageX; pY = ev.pageY; - // update "current" X and Y position based on mousemove - $(ob).bind("mousemove",track); - // start polling interval (self-calling timeout) to compare mouse coordinates over time - if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );} + // A private function for handling mouse 'hovering' + var handleHover = function(e) { + // copy objects to be passed into t (required for event object to be passed in IE) + var ev = jQuery.extend({},e); + var ob = this; - // else e.type == "mouseleave" - } else { - // unbind expensive mousemove event - $(ob).unbind("mousemove",track); - // if hoverIntent state is true, then call the mouseOut function after the specified delay - if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );} - } - }; + // cancel hoverIntent timer if it exists + if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); } - // bind the function to the two event listeners - return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover); - }; + // if e.type == "mouseenter" + if (e.type == "mouseenter") { + // set "previous" X and Y position based on initial entry point + pX = ev.pageX; pY = ev.pageY; + // update "current" X and Y position based on mousemove + $(ob).on("mousemove.hoverIntent",track); + // start polling interval (self-calling timeout) to compare mouse coordinates over time + if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );} + + // else e.type == "mouseleave" + } else { + // unbind expensive mousemove event + $(ob).off("mousemove.hoverIntent",track); + // if hoverIntent state is true, then call the mouseOut function after the specified delay + if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );} + } + }; + + // listen for mouseenter and mouseleave + return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector); + }; })(jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/landing/downloads.js b/web/app/assets/javascripts/landing/downloads.js deleted file mode 100644 index 76f6e5714..000000000 --- a/web/app/assets/javascripts/landing/downloads.js +++ /dev/null @@ -1,74 +0,0 @@ -(function(context,$) { - - "use strict"; - - context.JK = context.JK || {}; - - var downloads = {}; - - function listClients() { - var rest = context.JK.Rest(); - - var currentOS = context.JK.detectOS(); - - var downloads = $('.downloads'); - rest.getClientDownloads() - .done(function(data) { - downloads.removeClass('spinner-large'); - - var count = 0; - for ( var property in data ) count++; - - - if(count == 0) { - alert("Currently unable to list client software downloads."); - } - else { - - $.each(data, function(key, item) { - - - // if the currentOS we detect from browser is found within the product of an available client - // we flag it with this boolean - var matchesUserOS = currentOS != null && key.toLowerCase().indexOf(currentOS.toLowerCase()) > -1; - - var platform = key.substring('JamClient/'.length); - - var options = { - emphasis: matchesUserOS ? "currentOS" : "", - uri: item.uri, - platform: platform - } - - var download = $(context._.template($('#client-download-link').html(), options, { variable: 'data' })); - - download.find('a').data('platform', platform).click(function() { - var clicked = $(this); - rest.userDownloadedClient().always(function() { - $('body').append('