Merge branch 'develop' of https://bitbucket.org/jamkazam/jam-cloud into develop
This commit is contained in:
commit
156095f3c8
|
|
@ -182,3 +182,4 @@ rsvp_slots_prof_level.sql
|
|||
add_file_name_music_notation.sql
|
||||
change_scheduled_start_music_session.sql
|
||||
music_sessions_iso_639_3.sql
|
||||
discardable_claimed_recordings.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE claimed_recordings ADD COLUMN discarded BOOLEAN DEFAULT FALSE;
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
module JamRuby
|
||||
|
||||
# To use this, be sure to add this in before block: stub_const("APP_CONFIG", web_config)
|
||||
class Nav
|
||||
|
||||
def self.home(options ={})
|
||||
"#{APP_CONFIG.external_root_url}/client#/home#{dialog(options)}"
|
||||
"#{base_url}/home#{dialog(options)}"
|
||||
end
|
||||
|
||||
def self.profile(user)
|
||||
"#{base_url}/profile/#{user.id}"
|
||||
end
|
||||
|
||||
def self.feed
|
||||
"#{base_url}/feed"
|
||||
end
|
||||
|
||||
def self.accept_friend_request_dialog(friend_request_id)
|
||||
|
|
@ -12,6 +21,10 @@ module JamRuby
|
|||
|
||||
private
|
||||
|
||||
def self.base_url
|
||||
"#{APP_CONFIG.external_root_url}/client#"
|
||||
end
|
||||
|
||||
def self.dialog(options)
|
||||
dialog = ''
|
||||
if options[:dialog]
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ module JamRuby
|
|||
# same, sorted by score. date seems irrelevant as these are active sessions. ams_init must be called
|
||||
# first.
|
||||
def self.ams_query(current_user, options = {})
|
||||
session_id = options[:session_id]
|
||||
client_id = options[:client_id]
|
||||
genre = options[:genre]
|
||||
lang = options[:lang]
|
||||
|
|
@ -392,6 +393,7 @@ module JamRuby
|
|||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", keyword + ':*') unless keyword.blank?
|
||||
|
||||
if !day.blank? && !timezone_offset.blank?
|
||||
|
|
@ -399,6 +401,9 @@ module JamRuby
|
|||
day = Date.parse(day)
|
||||
next_day = day + 1
|
||||
timezone_offset = timezone_offset.to_i
|
||||
if timezone_offset > 0
|
||||
timezone_offset = "+#{timezone_offset}"
|
||||
end
|
||||
query = query.where("scheduled_start BETWEEN TIMESTAMP WITH TIME ZONE '#{day} 00:00:00#{timezone_offset}'
|
||||
AND TIMESTAMP WITH TIME ZONE '#{next_day} 00:00:00#{timezone_offset}'")
|
||||
rescue Exception => e
|
||||
|
|
@ -678,6 +683,10 @@ module JamRuby
|
|||
music_session.approval_required
|
||||
end
|
||||
|
||||
def music_notations
|
||||
music_session.music_notations
|
||||
end
|
||||
|
||||
def tick_track_changes
|
||||
self.track_changes_counter += 1
|
||||
self.save!(:validate => false)
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ module JamRuby
|
|||
belongs_to :genre, :class_name => "JamRuby::Genre"
|
||||
has_many :recorded_tracks, :through => :recording, :class_name => "JamRuby::RecordedTrack"
|
||||
has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id"
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id", :dependent => :destroy
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => "claimed_recording_id", :dependent => :destroy
|
||||
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id'
|
||||
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id', :dependent => :destroy
|
||||
|
||||
validates :name, no_profanity: true, length: {minimum: 3, maximum: 64}, presence: true
|
||||
validates :description, no_profanity: true, length: {maximum: 8000}
|
||||
|
|
@ -39,9 +39,9 @@ module JamRuby
|
|||
raise PermissionError, "user doesn't own claimed_recording"
|
||||
end
|
||||
|
||||
self.name = params[:name] unless params[:name].nil?
|
||||
self.description = params[:description] unless params[:description].nil?
|
||||
self.genre = Genre.find(params[:genre]) unless params[:genre].nil?
|
||||
self.name = params[:name]
|
||||
self.description = params[:description]
|
||||
self.genre = Genre.find_by_id(params[:genre]) unless params[:genre].nil?
|
||||
self.is_public = params[:is_public] unless params[:is_public].nil?
|
||||
save
|
||||
end
|
||||
|
|
@ -50,13 +50,10 @@ module JamRuby
|
|||
if user != self.user
|
||||
raise PermissionError, "user doesn't own claimed_recording"
|
||||
end
|
||||
|
||||
# If this is the only copy, destroy the entire recording. Otherwise, just destroy this claimed_recording
|
||||
if recording.claimed_recordings.count == 1
|
||||
recording.destroy
|
||||
else
|
||||
self.destroy
|
||||
end
|
||||
|
||||
ClaimedRecording.where(:id => id).update_all(:discarded => true )
|
||||
|
||||
recording.discard(user)
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,46 +8,16 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.import_from_iso3166(file)
|
||||
|
||||
# File iso3166.csv
|
||||
# Format:
|
||||
# countrycode,countryname
|
||||
|
||||
# what this does is not replace the contents of the table, but rather update the specified rows with the names.
|
||||
# any rows not specified have the countryname reset to be the same as the countrycode.
|
||||
|
||||
self.transaction do
|
||||
self.connection.execute "update #{self.table_name} set countryname = countrycode"
|
||||
|
||||
File.open(file, 'r:ISO-8859-1') do |io|
|
||||
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
|
||||
count = 0
|
||||
|
||||
ncols = 2
|
||||
|
||||
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
|
||||
csv.each do |row|
|
||||
raise "file does not have expected number of columns (#{ncols}): #{row.length}" unless row.length == ncols
|
||||
|
||||
countrycode = row[0]
|
||||
countryname = row[1]
|
||||
|
||||
stmt = "UPDATE #{self.table_name} SET countryname = #{MaxMindIsp.quote_value(countryname)} WHERE countrycode = #{MaxMindIsp.quote_value(countrycode)}"
|
||||
self.connection.execute stmt
|
||||
count += 1
|
||||
|
||||
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level < Logger::INFO
|
||||
ActiveRecord::Base.logger.debug "... logging updates to #{self.table_name} suspended ..."
|
||||
ActiveRecord::Base.logger.level = Logger::INFO
|
||||
end
|
||||
end
|
||||
|
||||
if ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger.level = saved_level
|
||||
ActiveRecord::Base.logger.debug "updated #{count} records in #{self.table_name}"
|
||||
end
|
||||
end # file
|
||||
end # transaction
|
||||
self.delete_all
|
||||
File.open(file, 'r:ISO-8859-1') do |io|
|
||||
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
|
||||
csv.each do |row|
|
||||
cc = self.new
|
||||
cc.countrycode = row[0]
|
||||
cc.countryname = row[1]
|
||||
cc.save
|
||||
end
|
||||
end # file
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ module JamRuby
|
|||
query = Feed.joins("LEFT OUTER JOIN recordings ON recordings.id = feeds.recording_id")
|
||||
.joins("LEFT OUTER JOIN music_sessions ON music_sessions.id = feeds.music_session_id")
|
||||
.limit(limit)
|
||||
.where('recordings is NULL OR recordings.all_discarded = false') # remove any 'all_discarded recordings from the search results'
|
||||
|
||||
# handle sort
|
||||
if sort == 'date'
|
||||
|
|
@ -72,14 +73,14 @@ module JamRuby
|
|||
end
|
||||
|
||||
|
||||
if target_user
|
||||
if target_user
|
||||
|
||||
if target_user != user.id
|
||||
require_public_recordings = "claimed_recordings.is_public = TRUE AND"
|
||||
require_public_sessions = "music_sessions.fan_access = TRUE AND"
|
||||
end
|
||||
|
||||
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} (claimed_recordings.user_id = '#{target_user}' OR (recordings.band_id IN (SELECT band_id FROM bands_musicians where user_id='#{target_user}')))")
|
||||
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.discarded = FALSE AND #{require_public_recordings} (claimed_recordings.user_id = '#{target_user}' OR (recordings.band_id IN (SELECT band_id FROM bands_musicians where user_id='#{target_user}')))")
|
||||
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions.id = music_sessions_user_history.music_session_id AND #{require_public_sessions} music_sessions_user_history.user_id = '#{target_user}'")
|
||||
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
|
||||
if sort == 'plays'
|
||||
|
|
@ -97,7 +98,7 @@ module JamRuby
|
|||
require_public_sessions = "music_sessions.fan_access = TRUE AND"
|
||||
end
|
||||
|
||||
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} recordings.band_id = '#{target_band}'")
|
||||
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.discarded = FALSE AND #{require_public_recordings} recordings.band_id = '#{target_band}'")
|
||||
query = query.where("music_sessions IS NULL OR #{require_public_sessions} music_sessions.band_id = '#{target_band}'")
|
||||
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
|
||||
if sort == 'plays'
|
||||
|
|
@ -108,7 +109,7 @@ module JamRuby
|
|||
query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL')
|
||||
#query = query.where('music_sessions.id is NULL OR music_sessions_user_history.id IS NOT NULL')
|
||||
else
|
||||
query = query.joins('LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.is_public = TRUE')
|
||||
query = query.joins('LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.discarded = FALSE AND claimed_recordings.is_public = TRUE')
|
||||
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions.id = music_sessions_user_history.music_session_id AND music_sessions.fan_access = TRUE")
|
||||
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
|
||||
if sort == 'plays'
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ module JamRuby
|
|||
|
||||
def language_description
|
||||
if self.language.blank?
|
||||
self.language = "en"
|
||||
self.language = "eng" # iso-639-3
|
||||
end
|
||||
|
||||
iso639Details = ISO_639.find_by_code(self.language)
|
||||
|
|
@ -605,6 +605,7 @@ module JamRuby
|
|||
# same, sorted by score. date seems irrelevant as these are active sessions. sms_init must be called
|
||||
# first.
|
||||
def self.sms_query(current_user, options = {})
|
||||
session_id = options[:session_id]
|
||||
client_id = options[:client_id]
|
||||
genre = options[:genre]
|
||||
lang = options[:lang]
|
||||
|
|
@ -663,6 +664,7 @@ module JamRuby
|
|||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", keyword + ':*') unless keyword.blank?
|
||||
|
||||
if !day.blank? && !timezone_offset.blank?
|
||||
|
|
@ -670,9 +672,7 @@ module JamRuby
|
|||
day = Date.parse(day)
|
||||
next_day = day + 1
|
||||
timezone_offset = timezone_offset.to_i
|
||||
if timezone_offset == 0
|
||||
timezone_offset = '' # no offset to specify in this case
|
||||
elsif timezone_offset > 0
|
||||
if timezone_offset > 0
|
||||
timezone_offset = "+#{timezone_offset}"
|
||||
end
|
||||
query = query.where("scheduled_start BETWEEN TIMESTAMP WITH TIME ZONE '#{day} 00:00:00#{timezone_offset}'
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ module JamRuby
|
|||
|
||||
attr_accessible :owner, :owner_id, :band, :band_id, :recorded_tracks_attributes, :mixes_attributes, :claimed_recordings_attributes, :name, :description, :genre, :is_public, :duration, as: :admin
|
||||
|
||||
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
has_many :users, :through => :recorded_tracks, :class_name => "JamRuby::User"
|
||||
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
has_many :mixes, :class_name => "JamRuby::Mix", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id"
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id"
|
||||
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
|
||||
has_one :feed, :class_name => "JamRuby::Feed", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ module JamRuby
|
|||
unless self.users.exists?(user)
|
||||
raise PermissionError, "user was not in this session"
|
||||
end
|
||||
recorded_tracks.where(:user_id=> user.id)
|
||||
recorded_tracks.where(:user_id => user.id)
|
||||
end
|
||||
|
||||
def has_access?(user)
|
||||
|
|
@ -211,7 +211,7 @@ module JamRuby
|
|||
|
||||
# check if all recorded_tracks for this recording are discarded
|
||||
if recorded_tracks.where('discard = false or discard is NULL').length == 0
|
||||
self.all_discarded = true
|
||||
self.all_discarded = true # the feed won't pick this up; also background cleanup will find these and whack them later
|
||||
self.save(:validate => false)
|
||||
end
|
||||
|
||||
|
|
@ -238,7 +238,7 @@ module JamRuby
|
|||
.order('recorded_tracks.id')
|
||||
.where('recorded_tracks.fully_uploaded = TRUE')
|
||||
.where('recorded_tracks.id > ?', since)
|
||||
.where('claimed_recordings.user_id = ?', user).limit(limit).each do |recorded_track|
|
||||
.where('claimed_recordings.user_id = ? AND claimed_recordings.discarded = FALSE', user).limit(limit).each do |recorded_track|
|
||||
downloads.push(
|
||||
{
|
||||
:type => "recorded_track",
|
||||
|
|
@ -258,7 +258,7 @@ module JamRuby
|
|||
.order('mixes.id')
|
||||
.where('mixes.completed_at IS NOT NULL')
|
||||
.where('mixes.id > ?', since)
|
||||
.where('claimed_recordings.user_id = ?', user)
|
||||
.where('claimed_recordings.user_id = ? AND claimed_recordings.discarded = FALSE', user)
|
||||
.limit(limit).each do |mix|
|
||||
downloads.push(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,52 +8,17 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.import_from_region_codes(file)
|
||||
|
||||
# File region_codes.csv
|
||||
# Format:
|
||||
# countrycode,region,regionname
|
||||
|
||||
# what this does is replace the contents of the table with the new data.
|
||||
|
||||
self.transaction do
|
||||
self.connection.execute "delete from #{self.table_name}"
|
||||
|
||||
File.open(file, 'r:ISO-8859-1') do |io|
|
||||
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : -1
|
||||
count = 0
|
||||
errors = 0
|
||||
ncols = 3
|
||||
|
||||
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
|
||||
csv.each do |row|
|
||||
raise "file does not have expected number of columns (#{ncols}): #{row.length}" unless row.length == ncols
|
||||
|
||||
countrycode = row[0]
|
||||
region = row[1]
|
||||
regionname = row[2]
|
||||
|
||||
if countrycode.length == 2 and region.length == 2 and regionname.length >= 2 and regionname.length <= 64
|
||||
|
||||
stmt = "INSERT INTO #{self.table_name} (countrycode, region, regionname) VALUES (#{self.connection.quote(countrycode)}, #{self.connection.quote(region)}, #{self.connection.quote(regionname)})"
|
||||
self.connection.execute stmt
|
||||
count += 1
|
||||
|
||||
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level < Logger::INFO
|
||||
ActiveRecord::Base.logger.debug "... logging updates to #{self.table_name} suspended ..."
|
||||
ActiveRecord::Base.logger.level = Logger::INFO
|
||||
end
|
||||
else
|
||||
ActiveRecord::Base.logger.warn("bogus region_codes record '#{countrycode}', '#{region}', '#{regionname}'") if ActiveRecord::Base.logger
|
||||
errors += 1
|
||||
end
|
||||
end
|
||||
|
||||
if ActiveRecord::Base.logger
|
||||
ActiveRecord::Base.logger.level = saved_level
|
||||
ActiveRecord::Base.logger.debug "inserted #{count} records into #{self.table_name}, #{errors} errors"
|
||||
end
|
||||
end # file
|
||||
end # transaction
|
||||
self.delete_all
|
||||
File.open(file, 'r:ISO-8859-1') do |io|
|
||||
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
|
||||
csv.each do |row|
|
||||
rr = Region.new
|
||||
rr.countrycode = row[0]
|
||||
rr.region = row[1]
|
||||
rr.regionname = row[2]
|
||||
rr.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ FactoryGirl.define do
|
|||
legal_terms true
|
||||
genre JamRuby::Genre.first
|
||||
band nil
|
||||
language 'en'
|
||||
language 'eng'
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -403,8 +403,8 @@ describe ActiveMusicSession do
|
|||
let(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) }
|
||||
let(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) }
|
||||
|
||||
let!(:music_session_1) { FactoryGirl.create(:active_music_session, :creator => creator_1, genre: Genre.find('african'), language: 'en', description: "Bunny Jumps" ) }
|
||||
let!(:music_session_2) { FactoryGirl.create(:active_music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'es', description: "Play with us as we jam to beatles and bunnies") }
|
||||
let!(:music_session_1) { FactoryGirl.create(:active_music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) }
|
||||
let!(:music_session_2) { FactoryGirl.create(:active_music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") }
|
||||
|
||||
let(:good_network_score) { 20 }
|
||||
let(:fair_network_score) { 30 }
|
||||
|
|
@ -459,14 +459,14 @@ describe ActiveMusicSession do
|
|||
music_sessions.length.should == 2
|
||||
|
||||
# get only english
|
||||
music_sessions, user_search = ams(searcher_1, client_id: searcher_conn_1.client_id, lang: 'en')
|
||||
music_sessions, user_search = ams(searcher_1, client_id: searcher_conn_1.client_id, lang: 'eng')
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].language.should == 'en'
|
||||
music_sessions[0].language.should == 'eng'
|
||||
|
||||
# get only ambient
|
||||
music_sessions, user_search = ams(searcher_1, client_id: searcher_conn_1.client_id, lang: 'es')
|
||||
music_sessions, user_search = ams(searcher_1, client_id: searcher_conn_1.client_id, lang: 'spa')
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].language.should == 'es'
|
||||
music_sessions[0].language.should == 'spa'
|
||||
end
|
||||
|
||||
it "keyword" do
|
||||
|
|
|
|||
|
|
@ -314,8 +314,8 @@ describe MusicSession do
|
|||
let!(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) }
|
||||
let!(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) }
|
||||
|
||||
let!(:music_session_1) { FactoryGirl.create(:music_session, creator: creator_1, genre: Genre.find('african'), language: 'en', description: "Bunny Jumps") }
|
||||
let!(:music_session_2) { FactoryGirl.create(:music_session, creator: creator_2, genre: Genre.find('ambient'), language: 'es', description: "Play with us as we jam to beatles and bunnies") }
|
||||
let!(:music_session_1) { FactoryGirl.create(:music_session, creator: creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps") }
|
||||
let!(:music_session_2) { FactoryGirl.create(:music_session, creator: creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") }
|
||||
let!(:music_session_3) { FactoryGirl.create(:music_session, creator: creator_3) }
|
||||
|
||||
let(:good_network_score) { 20 }
|
||||
|
|
@ -399,8 +399,8 @@ describe MusicSession do
|
|||
let(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) }
|
||||
let(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) }
|
||||
|
||||
let!(:music_session_1) { FactoryGirl.create(:music_session, :creator => creator_1, genre: Genre.find('african'), language: 'en', description: "Bunny Jumps" ) }
|
||||
let!(:music_session_2) { FactoryGirl.create(:music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'es', description: "Play with us as we jam to beatles and bunnies") }
|
||||
let!(:music_session_1) { FactoryGirl.create(:music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) }
|
||||
let!(:music_session_2) { FactoryGirl.create(:music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") }
|
||||
|
||||
let(:good_network_score) { 20 }
|
||||
let(:fair_network_score) { 30 }
|
||||
|
|
@ -448,14 +448,14 @@ describe MusicSession do
|
|||
music_sessions.length.should == 2
|
||||
|
||||
# get only english
|
||||
music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'en')
|
||||
music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'eng')
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].language.should == 'en'
|
||||
music_sessions[0].language.should == 'eng'
|
||||
|
||||
# get only ambient
|
||||
music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'es')
|
||||
music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'spa')
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].language.should == 'es'
|
||||
music_sessions[0].language.should == 'spa'
|
||||
end
|
||||
|
||||
it "keyword" do
|
||||
|
|
@ -498,7 +498,6 @@ describe MusicSession do
|
|||
music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, day: (Date.today + 1).to_s, timezone_offset: DateTime.now.offset.numerator)
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].should == music_session_1
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -188,8 +188,12 @@ describe Recording do
|
|||
expect { @claimed_recordign.discard(@user2) }.to raise_error
|
||||
@claimed_recording = @recording.claim(@user2, "name2", "description2", @genre, true)
|
||||
@claimed_recording.discard(@user2)
|
||||
@claimed_recording.reload
|
||||
@claimed_recording.discarded.should == true
|
||||
@recording.recorded_tracks_for_user(@user2)[0].discard.should == true
|
||||
@recording.reload
|
||||
@recording.claimed_recordings.length.should == 1
|
||||
@recording.claimed_recordings.length.should == 2
|
||||
@recording.all_discarded.should == false
|
||||
end
|
||||
|
||||
it "should destroy the entire recording if there was only one claimed_recording which is discarded" do
|
||||
|
|
@ -199,8 +203,10 @@ describe Recording do
|
|||
@genre = FactoryGirl.create(:genre)
|
||||
@claimed_recording = @recording.claim(@user, "name", "description", @genre, true)
|
||||
@claimed_recording.discard(@user)
|
||||
expect { Recording.find(@recording.id) }.to raise_error
|
||||
expect { ClaimedRecording.find(@claimed_recording.id) }.to raise_error
|
||||
@claimed_recording.reload
|
||||
@claimed_recording.discarded.should == true
|
||||
@claimed_recording.recording.all_discarded.should == true
|
||||
@recording.recorded_tracks_for_user(@user)[0].discard.should == true
|
||||
end
|
||||
|
||||
it "should use the since parameter when restricting uploads" do
|
||||
|
|
|
|||
|
|
@ -206,8 +206,8 @@
|
|||
if(!region) return;
|
||||
|
||||
var option = $(nilOptionStr)
|
||||
option.text(region)
|
||||
option.attr("value", region)
|
||||
option.text(region['name'])
|
||||
option.attr("value", region['region'])
|
||||
|
||||
regionSelect.append(option)
|
||||
})
|
||||
|
|
@ -431,6 +431,7 @@
|
|||
var cityElement = getCityElement();
|
||||
|
||||
updateRegionList(selectedCountry, getRegionElement());
|
||||
updateCityList(selectedCountry, null, cityElement);
|
||||
}
|
||||
|
||||
function updateRegionList(selectedCountry, regionElement) {
|
||||
|
|
@ -445,7 +446,10 @@
|
|||
|
||||
api.getRegions({ country: selectedCountry })
|
||||
.done(getRegionsDone)
|
||||
.fail(app.ajaxError)
|
||||
.error(function(err) {
|
||||
regionElement.children().remove()
|
||||
regionElement.append($(nilOptionStr).text(nilOptionText))
|
||||
})
|
||||
.always(function () {
|
||||
loadingRegionsData = false;
|
||||
})
|
||||
|
|
@ -470,14 +474,18 @@
|
|||
|
||||
api.getCities({ country: selectedCountry, region: selectedRegion })
|
||||
.done(getCitiesDone)
|
||||
.fail(app.ajaxError)
|
||||
.error(function(err) {
|
||||
cityElement.children().remove()
|
||||
cityElement.append($(nilOptionStr).text(nilOptionText))
|
||||
})
|
||||
.always(function () {
|
||||
loadingCitiesData = false;
|
||||
})
|
||||
}
|
||||
else {
|
||||
cityElement.children().remove()
|
||||
cityElement.append($(nilOptionStr).text(nilOptionText))
|
||||
cityElement.children().remove();
|
||||
cityElement.append($(nilOptionStr).text(nilOptionText));
|
||||
context.JK.dropdown(cityElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -309,19 +309,22 @@
|
|||
$.each(response["regions"], function (index, region) {
|
||||
if (!region) return;
|
||||
var option = $(nilOptionStr);
|
||||
option.text(region);
|
||||
option.attr("value", region);
|
||||
option.text(region['name']);
|
||||
option.attr("value", region['region']);
|
||||
|
||||
if (initialRegion === region) {
|
||||
if (initialRegion === region['region']) {
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
|
||||
$region.append(option);
|
||||
});
|
||||
|
||||
|
||||
context.JK.dropdown($region);
|
||||
|
||||
if (onRegionsLoaded) {
|
||||
onRegionsLoaded();
|
||||
}
|
||||
}).error(function(err) {
|
||||
context.JK.dropdown($region);
|
||||
if (onRegionsLoaded) {
|
||||
onRegionsLoaded();
|
||||
}
|
||||
|
|
@ -338,6 +341,7 @@
|
|||
var nilOption = $(nilOptionStr);
|
||||
nilOption.text(nilOptionText);
|
||||
$city.append(nilOption);
|
||||
nilOption.attr('selected','selected');
|
||||
|
||||
if (selectedCountry && selectedRegion) {
|
||||
rest.getCities({'country': selectedCountry, 'region': selectedRegion}).done(function (response) {
|
||||
|
|
@ -355,9 +359,13 @@
|
|||
});
|
||||
|
||||
context.JK.dropdown($city);
|
||||
}).error(function(err) {
|
||||
context.JK.dropdown($city);
|
||||
});
|
||||
} else {
|
||||
context.JK.dropdown($city);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addInvitation(value, data) {
|
||||
if ($('#selected-band-invitees div[user-id=' + data + ']').length === 0) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
var self = this;
|
||||
var logger = context.JK.logger;
|
||||
var $banner = null;
|
||||
var $closeBtn = null;
|
||||
var $yesBtn = null;
|
||||
var $noBtn = null;
|
||||
|
||||
// you can also do
|
||||
// * showAlert('title', 'text')
|
||||
|
|
@ -26,6 +29,19 @@
|
|||
return show(options);
|
||||
}
|
||||
|
||||
function showYesNo(options) {
|
||||
if (typeof options == 'string' || options instanceof String) {
|
||||
if(arguments.length == 2) {
|
||||
options = {title: options, html:arguments[1]}
|
||||
}
|
||||
else {
|
||||
options = {html:options};
|
||||
}
|
||||
}
|
||||
options.type = 'yes_no'
|
||||
return show(options);
|
||||
}
|
||||
|
||||
// responsible for updating the contents of the update dialog
|
||||
// as well as registering for any event handlers
|
||||
function show(options) {
|
||||
|
|
@ -33,7 +49,12 @@
|
|||
var html = options.html;
|
||||
|
||||
if(!options.title) {
|
||||
options.title = 'alert'
|
||||
if(options.type == 'alert') {
|
||||
options.title = 'alert'
|
||||
}
|
||||
else if(options.type == 'yes_no') {
|
||||
options.title = 'please confirm';
|
||||
}
|
||||
}
|
||||
|
||||
var $h1 = $banner.find('h1');
|
||||
|
|
@ -50,11 +71,18 @@
|
|||
throw "unable to show banner for empty message";
|
||||
}
|
||||
|
||||
var $closeBtn = $banner.find('.close-btn');
|
||||
|
||||
if((options.type == "alert" && !options.buttons) || options.close) {
|
||||
|
||||
$closeBtn.show().click(function() {
|
||||
var closeButtonText = 'CLOSE';
|
||||
if(options.close !== null && typeof options.close == 'object') {
|
||||
// extra styling options for close button
|
||||
if(options.close.name) {
|
||||
closeButtonText = options.close.name;
|
||||
}
|
||||
}
|
||||
|
||||
$closeBtn.show().text(closeButtonText).unbind('click').click(function() {
|
||||
hide();
|
||||
return false;
|
||||
});
|
||||
|
|
@ -63,6 +91,27 @@
|
|||
$closeBtn.hide();
|
||||
}
|
||||
|
||||
if(options.type == "yes_no") {
|
||||
$yesBtn.show().unbind('click').click(function() {
|
||||
if(options.yes) {
|
||||
options.yes();
|
||||
}
|
||||
hide();
|
||||
return false;
|
||||
})
|
||||
$noBtn.show().unbind('click').click(function() {
|
||||
if(options.no) {
|
||||
options.no();
|
||||
}
|
||||
hide();
|
||||
return false;
|
||||
})
|
||||
}
|
||||
else {
|
||||
$yesBtn.hide();
|
||||
$noBtn.hide();
|
||||
}
|
||||
|
||||
if(options.buttons) {
|
||||
var $buttons = $banner.find('.buttons')
|
||||
context._.each(options.buttons, function(button) {
|
||||
|
|
@ -86,6 +135,7 @@
|
|||
return newContent;
|
||||
}
|
||||
|
||||
|
||||
function hide() {
|
||||
$banner.hide();
|
||||
$banner.find('.user-btn').remove();
|
||||
|
|
@ -96,6 +146,10 @@
|
|||
function initialize() {
|
||||
|
||||
$banner = $('#banner');
|
||||
|
||||
$closeBtn = $banner.find('.close-btn');
|
||||
$yesBtn = $banner.find('.yes-btn');
|
||||
$noBtn = $banner.find('.no-btn');
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +158,7 @@
|
|||
initialize: initialize,
|
||||
show: show,
|
||||
showAlert: showAlert,
|
||||
showYesNo: showYesNo,// shows Yes and Cancel button (confirmation dialog)
|
||||
hide: hide
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
app.layout.showDialog('comment-dialog');
|
||||
return app.layout.showDialog('comment-dialog');
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.EditRecordingDialog = function (app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var claimedRecordingId = null;
|
||||
var $dialog = null;
|
||||
var $form = null;
|
||||
var $name = null;
|
||||
var $description = null;
|
||||
var $genre = null;
|
||||
var $isPublic = null;
|
||||
var $cancelBtn = null;
|
||||
var $saveBtn = null;
|
||||
var $deleteBtn = null;
|
||||
|
||||
var updating = false;
|
||||
var deleting = false;
|
||||
|
||||
function resetForm() {
|
||||
|
||||
// remove all display errors
|
||||
$dialog.find('.error-text').remove()
|
||||
$dialog.find('.error').removeClass("error")
|
||||
}
|
||||
|
||||
function beforeShow(args) {
|
||||
|
||||
claimedRecordingId = args.d1;
|
||||
|
||||
if(!claimedRecordingId) throw "claimedRecordingId must be specified";
|
||||
|
||||
resetForm();
|
||||
|
||||
rest.getClaimedRecording(claimedRecordingId)
|
||||
.done(function(data) {
|
||||
var name = data.name;
|
||||
var description = data.description;
|
||||
var is_public = data.is_public;
|
||||
var genre_id = data.genre_id;
|
||||
|
||||
context.JK.GenreSelectorHelper.setSelectedGenres($genre.parent(), [genre_id]);
|
||||
$name.val(name);
|
||||
$description.val(description);
|
||||
if(is_public) {
|
||||
$isPublic.attr('checked', 'checked').iCheck('check')
|
||||
}
|
||||
else {
|
||||
$isPublic.removeAttr('checked').iCheck('uncheck')
|
||||
}
|
||||
})
|
||||
.fail(app.ajaxError)
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
|
||||
}
|
||||
|
||||
function attemptUpdate() {
|
||||
if(updating) return;
|
||||
|
||||
updating = true;
|
||||
var name = $name.val();
|
||||
var description = $description.val();
|
||||
var genre = $genre.val();
|
||||
var is_public = $isPublic.is(':checked');
|
||||
|
||||
rest.updateClaimedRecording({id: claimedRecordingId, name: name, description: description, is_public: is_public, genre: genre })
|
||||
.done(function(updated) {
|
||||
resetForm();
|
||||
$dialog.triggerHandler('recording_updated', {id: claimedRecordingId, name: name, description: description, is_public: is_public, genre: genre})
|
||||
app.layout.closeDialog('edit-recording');
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
|
||||
if(jqXHR.status = 422) {
|
||||
// highlight fields in error
|
||||
|
||||
resetForm();
|
||||
|
||||
var errors = JSON.parse(jqXHR.responseText);
|
||||
|
||||
var $name_errors = context.JK.format_errors('name', errors);
|
||||
if ($name_errors) $name.closest('div.field').addClass('error').end().after($name_errors);
|
||||
|
||||
var $description_errors = context.JK.format_errors('description', errors);
|
||||
if ($description_errors) $description.closest('div.field').addClass('error').end().after($description_errors);
|
||||
|
||||
var $genre_errors = context.JK.format_errors('genre', errors);
|
||||
if ($genre_errors) $genre.closest('div.field').addClass('error').end().after($genre_errors);
|
||||
|
||||
var $is_public_errors = context.JK.format_errors('is_public', errors);
|
||||
if ($is_public_errors) $isPublic.closest('div.field').addClass('error').end().after($is_public_errors);
|
||||
|
||||
}
|
||||
else {
|
||||
app.ajaxError(arguments);
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
updating = false;
|
||||
})
|
||||
}
|
||||
|
||||
function attemptDelete() {
|
||||
if(deleting) return;
|
||||
|
||||
deleting = true;
|
||||
context.JK.Banner.showYesNo({
|
||||
title: "Confirm Deletion",
|
||||
html: "Are you sure you want to delete this recording?",
|
||||
yes: function() {
|
||||
rest.deleteClaimedRecording(claimedRecordingId)
|
||||
.done(function() {
|
||||
$dialog.triggerHandler('recording_deleted', {id: claimedRecordingId});
|
||||
app.layout.closeDialog('edit-recording');
|
||||
})
|
||||
.fail(app.ajaxError)
|
||||
.always(function() {
|
||||
deleting = false;
|
||||
})
|
||||
},
|
||||
no : function() {
|
||||
context.JK.Banner.hide();
|
||||
deleting = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
app.layout.closeDialog('edit-recording');
|
||||
}
|
||||
|
||||
function events() {
|
||||
$saveBtn.click(attemptUpdate);
|
||||
$deleteBtn.click(attemptDelete);
|
||||
$cancelBtn.click(cancel)
|
||||
$form.submit(false);
|
||||
}
|
||||
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog('edit-recording', dialogBindings);
|
||||
|
||||
$dialog = $('#edit-recording-dialog');
|
||||
$form = $dialog.find('form');
|
||||
$cancelBtn = $dialog.find('.cancel-btn');
|
||||
$saveBtn = $dialog.find('.save-btn');
|
||||
$deleteBtn = $dialog.find('.delete-btn');
|
||||
$name = $dialog.find('input[name="name"]');
|
||||
$description = $dialog.find('textarea[name="description"]');
|
||||
$genre = $dialog.find('select[name=genre]');
|
||||
$isPublic = $dialog.find('input[name=is_public]');
|
||||
|
||||
events();
|
||||
|
||||
context.JK.GenreSelectorHelper.render($genre.parent());
|
||||
context.JK.checkbox($isPublic);
|
||||
};
|
||||
|
||||
this.initialize = initialize;
|
||||
}
|
||||
})(window, jQuery);
|
||||
|
|
@ -5,407 +5,15 @@
|
|||
context.JK.FeedScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var rest = new context.JK.Rest();
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
var currentQuery = null;
|
||||
var currentPage = 0;
|
||||
var LIMIT = 20;
|
||||
var $screen = null;
|
||||
var $next = null;
|
||||
var $scroller = null;
|
||||
var $content = null;
|
||||
var $noMoreFeeds = null;
|
||||
var $refresh = null;
|
||||
var $sortFeedBy = null;
|
||||
var $includeDate = null;
|
||||
var $includeType = null;
|
||||
var next = null;
|
||||
|
||||
function defaultQuery() {
|
||||
var query = { limit:LIMIT, page:currentPage};
|
||||
|
||||
if(next) {
|
||||
query.since = next;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
function buildQuery() {
|
||||
currentQuery = defaultQuery();
|
||||
|
||||
// specify search criteria based on form
|
||||
currentQuery.sort = $sortFeedBy.val();
|
||||
currentQuery.time_range = $includeDate.val();
|
||||
currentQuery.type = $includeType.val();
|
||||
|
||||
return currentQuery;
|
||||
}
|
||||
var feed = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
currentPage = 0;
|
||||
$content.empty(); // TODO: do we need to delete audio elements?
|
||||
$noMoreFeeds.hide();
|
||||
next = null;
|
||||
}
|
||||
|
||||
function handleFeedResponse(response) {
|
||||
next = response.next;
|
||||
|
||||
renderFeeds(response);
|
||||
|
||||
if(response.next == null) {
|
||||
// if we less results than asked for, end searching
|
||||
$scroller.infinitescroll('pause');
|
||||
logger.debug("end of feeds")
|
||||
|
||||
if(currentPage > 0) {
|
||||
$noMoreFeeds.show();
|
||||
// there are bugs with infinitescroll not removing the 'loading'.
|
||||
// it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPage++;
|
||||
buildQuery();
|
||||
registerInfiniteScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
|
||||
clearResults();
|
||||
|
||||
currentQuery = buildQuery();
|
||||
rest.getFeeds(currentQuery)
|
||||
.done(function(response) {
|
||||
handleFeedResponse(response);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Feed Unavailable')
|
||||
})
|
||||
}
|
||||
|
||||
function registerInfiniteScroll() {
|
||||
|
||||
$scroller.infinitescroll({
|
||||
behavior: 'local',
|
||||
navSelector: '#feedScreen .btn-next-pager',
|
||||
nextSelector: '#feedScreen .btn-next-pager',
|
||||
binder: $scroller,
|
||||
dataType: 'json',
|
||||
appendCallback: false,
|
||||
prefill: false,
|
||||
bufferPx:100,
|
||||
loading: {
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
|
||||
img: '/assets/shared/spinner.gif'
|
||||
},
|
||||
path: function(page) {
|
||||
return '/api/feeds?' + $.param(buildQuery());
|
||||
}
|
||||
},function(json, opts) {
|
||||
handleFeedResponse(json);
|
||||
});
|
||||
$scroller.infinitescroll('resume');
|
||||
}
|
||||
|
||||
|
||||
function toggleSessionDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
return false;
|
||||
}
|
||||
|
||||
function startSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenBroadcast');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenBroadcast');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleSessionPlay() {
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
|
||||
var $status = $feedItem.find('.session-status')
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
$status.text('SESSION IN PROGRESS');
|
||||
stopSessionPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startSessionPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function stateChangeSession(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
var $status = $feedItem.find('.session-status');
|
||||
|
||||
if(data.displayText) $status.text(data.displayText);
|
||||
|
||||
if(data.isEnd) stopSessionPlay();
|
||||
|
||||
if(data.isSessionOver) {
|
||||
$controls.removeClass('inprogress').addClass('ended')
|
||||
}
|
||||
}
|
||||
|
||||
function startRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenRecording');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenRecording');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleRecordingPlay() {
|
||||
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
stopRecordingPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startRecordingPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function stateChangeRecording(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
|
||||
var $sliderBar = $('.recording-position', $feedItem);
|
||||
var $statusBar = $('.recording-status', $feedItem);
|
||||
var $currentTime = $('.recording-current', $feedItem);
|
||||
var $status = $('.status-text', $feedItem);
|
||||
var $playButton = $('.play-button', $feedItem);
|
||||
|
||||
if(data.isEnd) stopRecordingPlay($feedItem);
|
||||
if(data.isError) {
|
||||
$sliderBar.hide();
|
||||
$playButton.hide();
|
||||
$currentTime.hide();
|
||||
$statusBar.show();
|
||||
$status.text(data.displayText);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRecordingDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var $name = $feedItem.find('.name');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
$name.css('height', $name.data('original-height'));
|
||||
$name.dotdotdot();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$name.trigger('destroy.dot');
|
||||
$name.data('original-height', $name.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderFeeds(feeds) {
|
||||
|
||||
$.each(feeds.entries, function(i, feed) {
|
||||
if(feed.type == 'music_session') {
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
status_class: feed['is_over?'] ? 'ended' : 'inprogress',
|
||||
mount_class: feed['has_mount?'] ? 'has-mount' : 'no-mount'
|
||||
}
|
||||
var $feedItem = $(context._.template($('#template-feed-music-session').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
|
||||
// do everything we can before we attach the item to the page
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem).show());
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleSessionDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleSessionDetails);
|
||||
$('.play-button', $feedItem).click(toggleSessionPlay);
|
||||
|
||||
if (!feed.session_removed_at)
|
||||
{
|
||||
$('.btn-share', $feedItem).click(function() {
|
||||
ui.launchShareDialog(feed.id, 'session');
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('.btn-share', $feedItem).hide();
|
||||
}
|
||||
|
||||
$('.btn-comment', $feedItem).click(function() {
|
||||
ui.launchCommentDialog({
|
||||
session_id: feed.id,
|
||||
entity_type: 'session'
|
||||
});
|
||||
});
|
||||
|
||||
$('.btn-like', $feedItem).click(function() {
|
||||
ui.addSessionLike(feed.id, JK.currentUserId, $('.likes', $feedItem), $('.btn-like', $feedItem))
|
||||
});
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenBroadcast();
|
||||
$controls.bind('statechange.listenBroadcast', stateChangeSession);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
context.JK.bindProfileClickEvents($feedItem);
|
||||
}
|
||||
else if(feed.type == 'recording') {
|
||||
if(feed.claimed_recordings.length == 0) {
|
||||
logger.error("a recording in the feed should always have one claimed_recording")
|
||||
return;
|
||||
}
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
candidate_claimed_recording: feed.claimed_recordings[0],
|
||||
mix_class: feed['has_mix?'] ? 'has-mix' : 'no-mix',
|
||||
}
|
||||
|
||||
var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem));
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleRecordingDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleRecordingDetails);
|
||||
$('.play-button', $feedItem).click(toggleRecordingPlay);
|
||||
|
||||
$('.btn-share', $feedItem).click(function() {
|
||||
ui.launchShareDialog(options.candidate_claimed_recording.id, 'recording');
|
||||
});
|
||||
|
||||
$('.btn-comment', $feedItem).click(function() {
|
||||
ui.launchCommentDialog({
|
||||
recording_id: feed.id,
|
||||
claimed_recording_id: options.candidate_claimed_recording.id,
|
||||
entity_type: 'recording'
|
||||
});
|
||||
});
|
||||
|
||||
$('.btn-like', $feedItem).click(function() {
|
||||
ui.addRecordingLike(feed.id, options.candidate_claimed_recording.id, JK.currentUserId, $('.likes', $feedItem), $('.btn-like', $feedItem));
|
||||
});
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenRecording({recordingId: feed.id, claimedRecordingId: options.candidate_claimed_recording.id, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
$controls.bind('statechange.listenRecording', stateChangeRecording);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
context.JK.bindProfileClickEvents($feedItem);
|
||||
}
|
||||
else {
|
||||
logger.warn("skipping feed type: " + feed.type);
|
||||
}
|
||||
|
||||
context.JK.bindProfileClickEvents();
|
||||
});
|
||||
}
|
||||
|
||||
function renderFeed(feed) {
|
||||
$content.append(feed);
|
||||
}
|
||||
|
||||
function search() {
|
||||
logger.debug("Searching for feeds...");
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$refresh.on("click", search);
|
||||
$sortFeedBy.on('change', search);
|
||||
$includeDate.on('change', search);
|
||||
$includeType.on('change', search);
|
||||
feed.refresh();
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
@ -415,21 +23,17 @@
|
|||
};
|
||||
app.bindScreen('feed', screenBindings);
|
||||
|
||||
$screen = $('[layout-id="feed"]');
|
||||
$scroller = $screen.find('.content-body-scroller');
|
||||
$content = $screen.find('.feed-content');
|
||||
$noMoreFeeds = $('#end-of-feeds-list');
|
||||
$refresh = $screen.find('#btn-refresh-feed');
|
||||
$sortFeedBy = $screen.find('#feed_order_by');
|
||||
$includeDate = $screen.find('#feed_date');
|
||||
$includeType = $screen.find('#feed_show');
|
||||
var $screen = $('[layout-id="feed"]');
|
||||
var $scroller = $screen.find('.content-body-scroller');
|
||||
var $content = $screen.find('.feed-content');
|
||||
var $noMoreFeeds = $('#end-of-feeds-list');
|
||||
var $refresh = $screen.find('.btn-refresh-entries');
|
||||
var $sortFeedBy = $screen.find('#feed_order_by');
|
||||
var $includeDate = $screen.find('#feed_date');
|
||||
var $includeType = $screen.find('#feed_show');
|
||||
|
||||
// set default search criteria
|
||||
$sortFeedBy.val('date')
|
||||
$includeDate.val('month')
|
||||
$includeType.val('all')
|
||||
|
||||
events();
|
||||
feed = new context.JK.Feed(app);
|
||||
feed.initialize($screen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType);
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,586 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.Feed = function (app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var rest = new context.JK.Rest();
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
var userId = null;
|
||||
var currentQuery = null;
|
||||
var currentPage = 0;
|
||||
var LIMIT = 20;
|
||||
var $next = null;
|
||||
var $screen = null;
|
||||
var $scroller = null;
|
||||
var $content = null;
|
||||
var $noMoreFeeds = null;
|
||||
var $refresh = null;
|
||||
var $sortFeedBy = null;
|
||||
var $includeDate = null;
|
||||
var $includeType = null;
|
||||
var next = null;
|
||||
|
||||
function defaultQuery() {
|
||||
var query = { limit:LIMIT, page:currentPage};
|
||||
|
||||
if(next) {
|
||||
query.since = next;
|
||||
}
|
||||
|
||||
if(userId) {
|
||||
query.user = userId;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
function buildQuery() {
|
||||
currentQuery = defaultQuery();
|
||||
|
||||
// specify search criteria based on form
|
||||
currentQuery.sort = $sortFeedBy.val();
|
||||
currentQuery.time_range = $includeDate.val();
|
||||
currentQuery.type = $includeType.val();
|
||||
|
||||
return currentQuery;
|
||||
}
|
||||
|
||||
|
||||
function clearResults() {
|
||||
currentPage = 0;
|
||||
$content.empty(); // TODO: do we need to delete audio elements?
|
||||
$noMoreFeeds.hide();
|
||||
next = null;
|
||||
}
|
||||
|
||||
function handleFeedResponse(response) {
|
||||
next = response.next;
|
||||
|
||||
renderFeeds(response);
|
||||
|
||||
if(response.next == null) {
|
||||
// if we less results than asked for, end searching
|
||||
$scroller.infinitescroll('pause');
|
||||
logger.debug("end of feeds")
|
||||
|
||||
if(currentPage == 0 && response.entries.length == 0) {
|
||||
$content.append("<div class='no-feed-msg'>This user has no history.</div>") ;
|
||||
}
|
||||
|
||||
if(currentPage > 0) {
|
||||
$noMoreFeeds.show();
|
||||
// there are bugs with infinitescroll not removing the 'loading'.
|
||||
// it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPage++;
|
||||
buildQuery();
|
||||
registerInfiniteScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function setUser(_userId) {
|
||||
userId = _userId;
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
|
||||
clearResults();
|
||||
|
||||
currentQuery = buildQuery();
|
||||
rest.getFeeds(currentQuery)
|
||||
.done(function(response) {
|
||||
handleFeedResponse(response);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Feed Unavailable')
|
||||
})
|
||||
}
|
||||
|
||||
function registerInfiniteScroll() {
|
||||
|
||||
$scroller.infinitescroll({
|
||||
behavior: 'local',
|
||||
navSelector: '#feedScreen .btn-next-pager',
|
||||
nextSelector: '#feedScreen .btn-next-pager',
|
||||
binder: $scroller,
|
||||
dataType: 'json',
|
||||
appendCallback: false,
|
||||
prefill: false,
|
||||
bufferPx:100,
|
||||
loading: {
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
|
||||
img: '/assets/shared/spinner.gif'
|
||||
},
|
||||
path: function(page) {
|
||||
return '/api/feeds?' + $.param(buildQuery());
|
||||
}
|
||||
},function(json, opts) {
|
||||
handleFeedResponse(json);
|
||||
});
|
||||
$scroller.infinitescroll('resume');
|
||||
}
|
||||
|
||||
|
||||
function toggleSessionDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
return false;
|
||||
}
|
||||
|
||||
function startSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenBroadcast');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopSessionPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenBroadcast');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleSessionPlay() {
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
|
||||
var $status = $feedItem.find('.session-status')
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
$status.text('SESSION IN PROGRESS');
|
||||
stopSessionPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startSessionPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function stateChangeSession(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
var $status = $feedItem.find('.session-status');
|
||||
|
||||
if(data.displayText) $status.text(data.displayText);
|
||||
|
||||
if(data.isEnd) stopSessionPlay();
|
||||
|
||||
if(data.isSessionOver) {
|
||||
$controls.removeClass('inprogress').addClass('ended')
|
||||
}
|
||||
}
|
||||
|
||||
function startRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenRecording');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenRecording');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleRecordingPlay() {
|
||||
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
stopRecordingPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startRecordingPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isOwner() {
|
||||
return userId == context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function obtainCandidate(recording) {
|
||||
if(isOwner()) {
|
||||
var candidate = null;
|
||||
context._.each(recording.claimed_recordings, function(claimedRecording) {
|
||||
if(claimedRecording.user_id == context.JK.currentUserId) {
|
||||
candidate = claimedRecording;
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
if(!candidate) throw "unable to find candidate claimed recording, yet we can see this recording. server error..."
|
||||
return candidate;
|
||||
}
|
||||
else {
|
||||
return recording.claimed_recordings[0]
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOpen($feedItem, $name, $description, $musicians) {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$name.trigger('destroy.dot');
|
||||
$name.data('original-height', $name.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
function toggleClose($feedItem, $name, $description, $musicians, immediate) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}, immediate ? 0 : 400).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
$name.css('height', $name.data('original-height'));
|
||||
$name.dotdotdot();
|
||||
});
|
||||
}
|
||||
|
||||
function stateChangeRecording(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
|
||||
var $sliderBar = $('.recording-position', $feedItem);
|
||||
var $statusBar = $('.recording-status', $feedItem);
|
||||
var $currentTime = $('.recording-current', $feedItem);
|
||||
var $status = $('.status-text', $feedItem);
|
||||
var $playButton = $('.play-button', $feedItem);
|
||||
|
||||
if(data.isEnd) stopRecordingPlay($feedItem);
|
||||
if(data.isError) {
|
||||
$sliderBar.hide();
|
||||
$playButton.hide();
|
||||
$currentTime.hide();
|
||||
$statusBar.show();
|
||||
$status.text(data.displayText);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRecordingDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var $name = $feedItem.find('.name');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
toggleClose($feedItem, $name, $description, $musicians)
|
||||
}
|
||||
else {
|
||||
toggleOpen($feedItem, $name, $description, $musicians)
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateRecordingName($feedEntry, name) {
|
||||
$feedEntry.find('.name-text').text(name);
|
||||
}
|
||||
|
||||
function updateRecordingDescription($feedEntry, description) {
|
||||
$feedEntry.find('.description').text(description);
|
||||
}
|
||||
|
||||
function updateIsPublic($feedEntry, isPublic) {
|
||||
var $isPrivate = $feedEntry.find('.is_private')
|
||||
if(isPublic) {
|
||||
$isPrivate.removeClass('enabled')
|
||||
}
|
||||
else {
|
||||
$isPrivate.addClass('enabled')
|
||||
}
|
||||
}
|
||||
|
||||
function updateComments($feedEntry, comments) {
|
||||
$feedEntry.find('.comments').html(comments)
|
||||
}
|
||||
|
||||
function updatePlays($feedEntry, plays) {
|
||||
$feedEntry.find('.plays').html(plays);
|
||||
}
|
||||
|
||||
function updateLikes($feedEntry, likes) {
|
||||
$feedEntry.find('.likes').html(likes);
|
||||
}
|
||||
|
||||
function updateStats($feedEntry) {
|
||||
if($feedEntry.is('.recording-entry')) {
|
||||
var id = $feedEntry.attr('data-claimed-recording-id');
|
||||
rest.getClaimedRecording(id)
|
||||
.done(function(claimedRecording) {
|
||||
updateComments($feedEntry, claimedRecording.recording.comment_count);
|
||||
updateLikes($feedEntry, claimedRecording.recording.like_count);
|
||||
updatePlays($feedEntry, claimedRecording.recording.play_count);
|
||||
|
||||
})
|
||||
.fail(app.ajaxError)
|
||||
}
|
||||
else {
|
||||
var id = $feedEntry.attr('data-music-session');
|
||||
rest.getSessionHistory(id)
|
||||
.done(function(music_session) {
|
||||
updateComments($feedEntry, music_session.comment_count);
|
||||
updateLikes($feedEntry, music_session.like_count);
|
||||
updatePlays($feedEntry, music_session.play_count);
|
||||
})
|
||||
.fail(app.ajaxError)
|
||||
}
|
||||
}
|
||||
|
||||
function updateGenre($feedEntry, genre) {
|
||||
$feedEntry.find('.genre').text(context.JK.GenreSelectorHelper.getNameForId(genre));
|
||||
}
|
||||
|
||||
function renderFeeds(feeds) {
|
||||
|
||||
$.each(feeds.entries, function(i, feed) {
|
||||
if(feed.type == 'music_session') {
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
status_class: feed['is_over?'] ? 'ended' : 'inprogress',
|
||||
mount_class: feed['has_mount?'] ? 'has-mount' : 'no-mount'
|
||||
}
|
||||
var $feedItem = $(context._.template($('#template-feed-music-session').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.session-controls');
|
||||
|
||||
// do everything we can before we attach the item to the page
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem).show());
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleSessionDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleSessionDetails);
|
||||
$('.play-button', $feedItem).click(toggleSessionPlay);
|
||||
|
||||
if (!feed.session_removed_at)
|
||||
{
|
||||
$('.btn-share', $feedItem).click(function() {
|
||||
ui.launchShareDialog(feed.id, 'session');
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('.btn-share', $feedItem).hide();
|
||||
}
|
||||
|
||||
$('.btn-comment', $feedItem).click(function() {
|
||||
var result = ui.launchCommentDialog({
|
||||
session_id: feed.id,
|
||||
entity_type: 'session'
|
||||
}).one(EVENTS.DIALOG_CLOSED, function() {
|
||||
updateStats($feedItem);
|
||||
})
|
||||
});
|
||||
|
||||
$('.btn-like', $feedItem).click(function() {
|
||||
ui.addSessionLike(feed.id, JK.currentUserId, $('.likes', $feedItem), $('.btn-like', $feedItem))
|
||||
});
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenBroadcast();
|
||||
$controls.bind('statechange.listenBroadcast', stateChangeSession);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
context.JK.bindProfileClickEvents($feedItem);
|
||||
}
|
||||
else if(feed.type == 'recording') {
|
||||
if(feed.claimed_recordings.length == 0) {
|
||||
logger.error("a recording in the feed should always have one claimed_recording")
|
||||
return;
|
||||
}
|
||||
var options = {
|
||||
feed_item: feed,
|
||||
candidate_claimed_recording: obtainCandidate(feed),
|
||||
mix_class: feed['has_mix?'] ? 'has-mix' : 'no-mix',
|
||||
}
|
||||
|
||||
var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem));
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleRecordingDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleRecordingDetails);
|
||||
$('.play-button', $feedItem).click(toggleRecordingPlay);
|
||||
updateIsPublic($feedItem, options.candidate_claimed_recording.is_public);
|
||||
|
||||
$('.btn-share', $feedItem).click(function() {
|
||||
ui.launchShareDialog(options.candidate_claimed_recording.id, 'recording');
|
||||
});
|
||||
|
||||
$('.btn-comment', $feedItem).click(function() {
|
||||
ui.launchCommentDialog({
|
||||
recording_id: feed.id,
|
||||
claimed_recording_id: options.candidate_claimed_recording.id,
|
||||
entity_type: 'recording'
|
||||
})
|
||||
.one(EVENTS.DIALOG_CLOSED, function() {
|
||||
updateStats($feedItem);
|
||||
});
|
||||
});
|
||||
|
||||
$('.btn-like', $feedItem).click(function() {
|
||||
ui.addRecordingLike(feed.id, options.candidate_claimed_recording.id, JK.currentUserId, $('.likes', $feedItem), $('.btn-like', $feedItem));
|
||||
});
|
||||
|
||||
if(isOwner()) {
|
||||
$('.edit-recording-dialog', $feedItem).data('claimed_recording_id', options.candidate_claimed_recording.id).click(function() {
|
||||
app.layout.showDialog('edit-recording', {d1: $(this).data('claimed_recording_id')})
|
||||
.one(EVENTS.DIALOG_CLOSED, function() {
|
||||
$(this).unbind('recording_updated').unbind('recording_deleted');
|
||||
})
|
||||
.one('recording_updated', function(e, data) {
|
||||
// find recording by claimed recording id
|
||||
var $feedEntry = $screen.find('.feed-entry.recording-entry[data-claimed-recording-id="'+ data.id +'"]');
|
||||
var $musicians = $feedEntry.find('.musician-detail');
|
||||
var $description = $feedEntry.find('.description');
|
||||
var $name = $feedEntry.find('.name');
|
||||
var $detailsLink = $feedEntry.find('.details');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
toggleClose($feedEntry, $name, $description, $musicians, true);
|
||||
}
|
||||
|
||||
$description.trigger('destroy.dot');
|
||||
$name.trigger('destroy.dot');
|
||||
|
||||
updateRecordingName($feedEntry, data.name);
|
||||
updateRecordingDescription($feedEntry, data.description);
|
||||
updateIsPublic($feedEntry, data.is_public);
|
||||
updateGenre($feedEntry, data.genre);
|
||||
|
||||
$name.dotdotdot();
|
||||
$description.dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedEntry.css('height'));
|
||||
|
||||
$detailsLink.data('toggledOpen', false);
|
||||
})
|
||||
.one('recording_deleted', function(e, data) {
|
||||
var $feedEntry = $screen.find('.feed-entry.recording-entry[data-claimed-recording-id="'+ data.id +'"]');
|
||||
$feedEntry.remove();
|
||||
})
|
||||
return false;
|
||||
}).show();
|
||||
}
|
||||
|
||||
// put the feed item on the page
|
||||
renderFeed($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenRecording({recordingId: feed.id, claimedRecordingId: options.candidate_claimed_recording.id, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
$controls.bind('statechange.listenRecording', stateChangeRecording);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
context.JK.bindProfileClickEvents($feedItem);
|
||||
}
|
||||
else {
|
||||
logger.warn("skipping feed type: " + feed.type);
|
||||
}
|
||||
|
||||
context.JK.bindProfileClickEvents();
|
||||
});
|
||||
}
|
||||
|
||||
function renderFeed(feed) {
|
||||
$content.append(feed);
|
||||
}
|
||||
|
||||
function search() {
|
||||
logger.debug("Searching for feeds...");
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$refresh.on("click", search);
|
||||
$sortFeedBy.on('change', search);
|
||||
$includeDate.on('change', search);
|
||||
$includeType.on('change', search);
|
||||
}
|
||||
|
||||
function initialize(_$parent, _$scroller, _$content, _$noMorefeeds, _$refresh, _$sortFeedBy, _$includeDate, _$includeType) {
|
||||
$screen = _$parent;
|
||||
$scroller = _$scroller;
|
||||
$content = _$content;
|
||||
$noMoreFeeds = _$noMorefeeds;
|
||||
$refresh = _$refresh;
|
||||
$sortFeedBy = _$sortFeedBy;
|
||||
$includeDate = _$includeDate;
|
||||
$includeType = _$includeType;
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($scroller.length == 0) throw "$scroller must be specified";
|
||||
if($content.length == 0) throw "$content must be specified";
|
||||
if($noMoreFeeds.length == 0) throw "$noMoreFeeds must be specified";
|
||||
if($refresh.length == 0) throw "$refresh must be specified";
|
||||
if($sortFeedBy.length == 0) throw "$sortFeedBy must be specified";
|
||||
if($includeDate.length == 0) throw "$includeDate must be specified";
|
||||
if($includeType.length ==0) throw "$includeType must be specified";
|
||||
|
||||
// set default search criteria
|
||||
$sortFeedBy.val('date')
|
||||
$includeDate.val('month')
|
||||
$includeType.val('all')
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.refresh = refresh;
|
||||
this.setUser = setUser;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window, jQuery)
|
||||
|
|
@ -99,10 +99,8 @@
|
|||
// date filter
|
||||
var date = $('#session-date-filter').val();
|
||||
if (date !== null && date.length > 0) {
|
||||
console.log(date);
|
||||
currentQuery.day = context.JK.formatDateYYYYMMDD(date);
|
||||
// console.log("currentQuery.day=%o", currentQuery.day);
|
||||
currentQuery.timezone_offset = new Date().getTimezoneOffset();
|
||||
currentQuery.timezone_offset = (new Date().getTimezoneOffset()) / 60;
|
||||
}
|
||||
|
||||
// language filter
|
||||
|
|
@ -160,7 +158,6 @@
|
|||
clearResults();
|
||||
buildQuery();
|
||||
loadSessions();
|
||||
context.JK.guardAgainstBrowser(app);
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
|
|
|
|||
|
|
@ -7,21 +7,12 @@
|
|||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.GenreSelectorDeferred = null;
|
||||
context.JK.GenreSelectorHelper = (function() {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var _genres = []; // will be list of structs: [ {label:xxx, value:yyy}, {...}, ... ]
|
||||
|
||||
function loadGenres() {
|
||||
var url = "/api/genres";
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
async: false, // do this synchronously so the event handlers in events() can be wired up
|
||||
success: genresLoaded
|
||||
});
|
||||
}
|
||||
|
||||
function reset(parentSelector, defaultGenre) {
|
||||
defaultGenre = typeof(defaultGenre) == 'undefined' ? '' : defaultGenre;
|
||||
$('select', parentSelector).val(defaultGenre);
|
||||
|
|
@ -38,7 +29,7 @@
|
|||
|
||||
function render(parentSelector) {
|
||||
$('select', parentSelector).empty();
|
||||
$('select', parentSelector).append('<option value="">Any Genre</option>');
|
||||
$('select', parentSelector).append('<option value="">Unspecified</option>');
|
||||
var template = $('#template-genre-option').html();
|
||||
$.each(_genres, function(index, value) {
|
||||
// value will be a dictionary entry from _genres:
|
||||
|
|
@ -67,6 +58,21 @@
|
|||
return selectedGenres;
|
||||
}
|
||||
|
||||
function getNameForId(genreId) {
|
||||
var name = null;
|
||||
context._.each(_genres, function(genre) {
|
||||
if(genreId == genre.value) {
|
||||
name = genre.label;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if(!name) {
|
||||
logger.warn("no genre found for genreId: " + genreId);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function setSelectedGenres(parentSelector, genreList) {
|
||||
if (!genreList) {
|
||||
return;
|
||||
|
|
@ -79,18 +85,31 @@
|
|||
$('select', parentSelector).val(values[0]);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
loadGenres();
|
||||
function initialize(app) {
|
||||
// XXX; _instruments should be populated in a template, rather than round-trip to server
|
||||
if(!context.JK.GenreSelectorDeferred) {
|
||||
// this dance is to make sure there is only one server request instead of InstrumentSelector instances *
|
||||
context.JK.GenreSelectorDeferred = rest.getGenres()
|
||||
}
|
||||
|
||||
context.JK.GenreSelectorDeferred
|
||||
.done(function(response) {genresLoaded(response)})
|
||||
.fail(app.ajaxError)
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
var me = { // This will be our singleton.
|
||||
initialize: initialize,
|
||||
getSelectedGenres: getSelectedGenres,
|
||||
setSelectedGenres: setSelectedGenres,
|
||||
getNameForId : getNameForId,
|
||||
getSelectedGenresValues: getSelectedGenresValues,
|
||||
reset: reset,
|
||||
render: render,
|
||||
loadGenres: loadGenres
|
||||
render: function() {
|
||||
var _args = arguments;
|
||||
context.JK.GenreSelectorDeferred.done(function(){render.apply(self, _args)})
|
||||
}
|
||||
};
|
||||
|
||||
return me;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@
|
|||
}
|
||||
|
||||
function updateSession(id, newSession) {
|
||||
return $.ajax('/api/sessions/' + id, {
|
||||
return $.ajax({
|
||||
url: '/api/sessions/' + id,
|
||||
type: "PUT",
|
||||
data : newSession,
|
||||
dataType : 'json'
|
||||
|
|
@ -954,6 +955,27 @@
|
|||
});
|
||||
}
|
||||
|
||||
function updateClaimedRecording(options) {
|
||||
var claimedRecordingId = options["id"];
|
||||
return $.ajax({
|
||||
type: "PUT",
|
||||
dataType: "json",
|
||||
url: '/api/claimed_recordings/' + claimedRecordingId,
|
||||
contentType: 'application/json',
|
||||
processData: false,
|
||||
data: JSON.stringify(options)
|
||||
});
|
||||
}
|
||||
|
||||
function deleteClaimedRecording(id) {
|
||||
return $.ajax({
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
url: "/api/claimed_recordings/" + id
|
||||
});
|
||||
}
|
||||
|
||||
function claimRecording(options) {
|
||||
var recordingId = options["id"];
|
||||
|
||||
|
|
@ -1220,6 +1242,8 @@
|
|||
this.getRecording = getRecording;
|
||||
this.getClaimedRecordings = getClaimedRecordings;
|
||||
this.getClaimedRecording = getClaimedRecording;
|
||||
this.updateClaimedRecording = updateClaimedRecording;
|
||||
this.deleteClaimedRecording = deleteClaimedRecording;
|
||||
this.claimRecording = claimRecording;
|
||||
this.startPlayClaimedRecording = startPlayClaimedRecording;
|
||||
this.stopPlayClaimedRecording = stopPlayClaimedRecording;
|
||||
|
|
|
|||
|
|
@ -644,8 +644,9 @@
|
|||
|
||||
function showDialog(dialog, options) {
|
||||
if (dialogEvent(dialog, 'beforeShow', options) === false) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
logger.debug("opening dialog: " + dialog)
|
||||
var $overlay = $('.dialog-overlay')
|
||||
|
||||
if (opts.sizeOverlayToContent) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
var PAYLOAD_SIZE = 100;
|
||||
var MINIMUM_ACCEPTABLE_SESSION_SIZE = 2;
|
||||
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var rest = context.JK.Rest();
|
||||
var logger = context.JK.logger;
|
||||
var $step = null;
|
||||
|
|
@ -201,6 +202,7 @@
|
|||
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
|
||||
}
|
||||
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);
|
||||
|
|
@ -211,11 +213,13 @@
|
|||
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
|
||||
}
|
||||
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') {
|
||||
gearUtils.skipNetworkTest();
|
||||
context.JK.alertSupportedNeeded("No network test servers are available." + appendContextualStatement());
|
||||
renderStopTest('', '');
|
||||
testedSuccessfully = true;
|
||||
|
|
@ -227,18 +231,21 @@
|
|||
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.noNetwork);
|
||||
}
|
||||
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") {
|
||||
gearUtils.skipNetworkTest();
|
||||
context.JK.alertSupportedNeeded("Communication with the JamKazam network service timed out." + appendContextualStatement());
|
||||
testedSuccessfully = true;
|
||||
renderStopTest('', '');
|
||||
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
|
||||
}
|
||||
else {
|
||||
gearUtils.skipNetworkTest();
|
||||
context.JK.alertSupportedNeeded("The JamKazam client software had a logic error while scoring your Internet connection.");
|
||||
renderStopTest('', '');
|
||||
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.jamerror);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
var sentFriendRequest = false;
|
||||
var profileScreen = null;
|
||||
var textMessageDialog = null;
|
||||
var feed = null;
|
||||
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
|
||||
function beforeShow(data) {
|
||||
userId = data.id;
|
||||
feed.setUser(userId);
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
|
@ -37,6 +39,10 @@
|
|||
resetForm();
|
||||
}
|
||||
|
||||
function beforeHide(data) {
|
||||
feed.setUser(null);
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
$('#profile-instruments').empty();
|
||||
|
||||
|
|
@ -571,7 +577,7 @@
|
|||
}
|
||||
|
||||
function bindHistory() {
|
||||
|
||||
feed.refresh();
|
||||
}
|
||||
|
||||
/****************** BANDS TAB *****************/
|
||||
|
|
@ -752,15 +758,31 @@
|
|||
function bindFavorites() {
|
||||
}
|
||||
|
||||
function initializeFeed() {
|
||||
|
||||
var $scroller = profileScreen.find('.content-body-scroller');
|
||||
var $content = profileScreen.find('.feed-content');
|
||||
var $noMoreFeeds = $('#end-of-feeds-list');
|
||||
var $refresh = profileScreen.find('.btn-refresh-entries');
|
||||
var $sortFeedBy = profileScreen.find('#feed_order_by');
|
||||
var $includeDate = profileScreen.find('#feed_date');
|
||||
var $includeType = profileScreen.find('#feed_show');
|
||||
|
||||
feed = new context.JK.Feed(app);
|
||||
feed.initialize(profileScreen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType);
|
||||
}
|
||||
|
||||
function initialize(textMessageDialogInstance) {
|
||||
textMessageDialog = textMessageDialogInstance;
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
'afterShow': afterShow,
|
||||
'beforeHide' : beforeHide
|
||||
};
|
||||
app.bindScreen('profile', screenBindings);
|
||||
profileScreen = $('#user-profile');
|
||||
events();
|
||||
initializeFeed();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -98,10 +98,10 @@
|
|||
id: recording.id
|
||||
})
|
||||
.done(function () {
|
||||
console.error("recording discarded by user. recordingId=%o", recording.id);
|
||||
logger.debug("recording discarded by user. recordingId=%o", recording.id);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
console.error("recording discard by user failed. recordingId=%o. reason: %o", recording.id, jqXHR.responseText);
|
||||
logger.error("recording discard by user failed. recordingId=%o. reason: %o", recording.id, jqXHR.responseText);
|
||||
})
|
||||
.always(function () {
|
||||
app.layout.closeDialog('recordingFinished')
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
app.layout.showDialog('rsvp-cancel-dialog');
|
||||
return app.layout.showDialog('rsvp-cancel-dialog');
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
app.layout.showDialog(dialogId);
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
context.JK = context.JK || {};
|
||||
|
||||
context.JK.CreateScheduledSession = function(app) {
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var logger = context.JK.logger;
|
||||
var rest = JK.Rest();
|
||||
var invitationDialog = null;
|
||||
|
|
@ -188,9 +189,7 @@
|
|||
|
||||
function beforeShowStep5() {
|
||||
var startType = null;
|
||||
if (createSessionSettings.createType == 'start-scheduled' ||
|
||||
createSessionSettings.createType == 'immediately' ||
|
||||
createSessionSettings.createType == 'quick-start') {
|
||||
if (willOptionStartSession()) {
|
||||
startType = 'Now!';
|
||||
createSessionSettings.startType = "START SESSION";
|
||||
}
|
||||
|
|
@ -305,6 +304,10 @@
|
|||
if (createSessionSettings.createType == 'start-scheduled') {
|
||||
var session = scheduledSessions[createSessionSettings.selectedSessionId];
|
||||
|
||||
if(session == null) {
|
||||
// TODO: notify user they need to pick session? Or maybe it should be grayed out.
|
||||
return false;
|
||||
}
|
||||
var moveToFinish = function() {
|
||||
app.layout.closeDialog('confirm');
|
||||
createSessionSettings.startDate = new Date(session.scheduled_start).toDateString();
|
||||
|
|
@ -488,7 +491,27 @@
|
|||
function beforeMoveStep5() {
|
||||
}
|
||||
|
||||
function startSessionClicked() {
|
||||
|
||||
if(willOptionStartSession()) {
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
app.notify(
|
||||
{ title: "Unable to Start New Session",
|
||||
text: "You can only start a session once you have working audio gear and a tested internet connection."
|
||||
})
|
||||
})
|
||||
.done(function(){
|
||||
startSession();
|
||||
});
|
||||
}
|
||||
else {
|
||||
startSession();
|
||||
}
|
||||
}
|
||||
|
||||
function startSession() {
|
||||
|
||||
var data = {};
|
||||
|
||||
if (createSessionSettings.createType == 'start-scheduled') {
|
||||
|
|
@ -563,22 +586,15 @@
|
|||
});
|
||||
}
|
||||
|
||||
var tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
if(tracks.length == 0) {
|
||||
logger.error("we should never have 0 tracks and have gotten this far. Launch FTUE is the best we can do right now")
|
||||
// If user hasn't completed FTUE - do so now.
|
||||
app.afterFtue = function() { startSession(); };
|
||||
app.layout.startNewFtue();
|
||||
return false;
|
||||
}
|
||||
|
||||
var joinSession = function(sessionId) {
|
||||
var tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
|
||||
var options = {};
|
||||
options.client_id = app.clientId;
|
||||
options.session_id = sessionId;
|
||||
options.as_musician = true;
|
||||
options.tracks = tracks;
|
||||
rest.joinSession(options)
|
||||
rest.joinSession(options)
|
||||
.done(function(response) {
|
||||
var invitationCount = data.invitations.length;
|
||||
|
||||
|
|
@ -600,16 +616,19 @@
|
|||
app.notifyServerError(jqXHR, "Unable to Create Session");
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
if (createSessionSettings.createType == 'start-scheduled') {
|
||||
joinSession(createSessionSettings.selectedSessionId);
|
||||
$('#create-session-buttons .btn-next').off('click');
|
||||
}
|
||||
else {
|
||||
rest.createScheduledSession(data)
|
||||
.done(function(response) {
|
||||
logger.debug("created session on server");
|
||||
$('#create-session-buttons .btn-next').off('click');
|
||||
var newSessionId = response.id;
|
||||
$(".btn-next").off('click');
|
||||
|
||||
if (createSessionSettings.createType == 'quick-start' || createSessionSettings.createType == "immediately") {
|
||||
joinSession(newSessionId);
|
||||
|
|
@ -620,6 +639,7 @@
|
|||
}
|
||||
})
|
||||
.fail(function(jqXHR){
|
||||
logger.debug("unable to schedule a session")
|
||||
app.notifyServerError(jqXHR, "Unable to schedule a session");
|
||||
});
|
||||
}
|
||||
|
|
@ -734,7 +754,7 @@
|
|||
|
||||
if (step == STEP_SELECT_CONFIRM) {
|
||||
$btnNext.html(createSessionSettings.startType);
|
||||
$btnNext.on('click', startSession);
|
||||
$btnNext.on('click', startSessionClicked);
|
||||
}
|
||||
else
|
||||
$btnNext.on('click', next);
|
||||
|
|
@ -764,7 +784,20 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
// will this option result in a session being started?
|
||||
function willOptionStartSession() {
|
||||
return createSessionSettings.createType == 'start-scheduled' ||
|
||||
createSessionSettings.createType == 'immediately' ||
|
||||
createSessionSettings.createType == 'quick-start';
|
||||
}
|
||||
|
||||
function next(event) {
|
||||
if(willOptionStartSession()) {
|
||||
if(!context.JK.guardAgainstBrowser(app)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var valid = beforeMoveStep();
|
||||
if (!valid) {
|
||||
return false;
|
||||
|
|
@ -820,7 +853,7 @@
|
|||
}
|
||||
|
||||
function afterShow() {
|
||||
context.JK.guardAgainstBrowser(app);
|
||||
|
||||
}
|
||||
|
||||
function getFormattedTime(date, change) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.SessionScreen = function(app) {
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var logger = context.JK.logger;
|
||||
var self = this;
|
||||
var sessionModel = null;
|
||||
|
|
@ -114,23 +115,25 @@
|
|||
checkForCurrentUser();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
if(!context.JK.JamServer.connected) {
|
||||
promptLeave = false;
|
||||
app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.');
|
||||
window.location = '/client#/home'
|
||||
return;
|
||||
}
|
||||
if(!context.JK.JamServer.connected) {
|
||||
promptLeave = false;
|
||||
app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.');
|
||||
window.location = '/client#/home'
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.JK.hasOneConfiguredDevice() || context.JK.TrackHelpers.getUserTracks(context.jamClient).length == 0) {
|
||||
app.afterFtue = function() { initializeSession(); };
|
||||
app.cancelFtue = function() { promptLeave = false; window.location = '/client#/home' };
|
||||
app.layout.startNewFtue();
|
||||
}
|
||||
else {
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
})
|
||||
.done(function(){
|
||||
initializeSession();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function notifyWithUserInfo(title , text, clientId) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.SessionList = function(app) {
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var ui = new context.JK.UIHelper(app);
|
||||
|
|
@ -11,18 +12,17 @@
|
|||
var $inactiveSessionTemplate = $('#template-inactive-session-row');
|
||||
var $notationFileTemplate = $('#template-notation-files');
|
||||
var $openSlotsTemplate = $('#template-open-slots');
|
||||
var $pendingInvitationsTemplate = $('#template-pending-invitations');
|
||||
var $latencyTemplate = $('#template-latency');
|
||||
var $musicianTemplate = $('#template-musician-info');
|
||||
var showJoinLink = true;
|
||||
var showRsvpLink = true;
|
||||
|
||||
var LATENCY = {
|
||||
GOOD : {description: "GOOD", style: "latency-green", min: 0.0, max: 20.0},
|
||||
MEDIUM : {description: "MEDIUM", style: "latency-yellow", min: 20.0, max: 40.0},
|
||||
POOR : {description: "POOR", style: "latency-red", min: 40.0, max: 10000000000.0},
|
||||
UNREACHABLE: {description: "UNREACHABLE", style: "latency-grey", min: -1, max: -1},
|
||||
UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2}
|
||||
GOOD : {description: "GOOD", style: "latency-green", min: 0.0, max: 20.0},
|
||||
MEDIUM : {description: "MEDIUM", style: "latency-yellow", min: 20.0, max: 40.0},
|
||||
POOR : {description: "POOR", style: "latency-red", min: 40.0, max: 10000000000.0},
|
||||
UNREACHABLE: {description: "UNREACHABLE", style: "latency-grey", min: -1, max: -1},
|
||||
UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2}
|
||||
};
|
||||
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
showJoinLink = session.musician_access;
|
||||
|
||||
// render musicians who are already in the session
|
||||
if (session.active_music_session && "participants" in session.active_music_session) {
|
||||
if (session.active_music_session && "participants" in session.active_music_session && session.active_music_session.participants.length > 0) {
|
||||
for (i=0; i < session.active_music_session.participants.length; i++) {
|
||||
inSessionUsers.push(session.active_music_session.participants[i].user.id);
|
||||
var inSessionUserInfo = createInSessionUser(session.active_music_session.participants[i]);
|
||||
|
|
@ -49,11 +49,16 @@
|
|||
latencyHtml += inSessionUserInfo[1];
|
||||
}
|
||||
}
|
||||
// this provides a buffer at the top to shift the first latency tag down in the event there are NO in-session musicians
|
||||
else {
|
||||
latencyHtml += "<div style='height:15px;'> </div>";
|
||||
}
|
||||
|
||||
// render users who have approved RSVPs
|
||||
if (session.approved_rsvps) {
|
||||
for (i=0; i < session.approved_rsvps.length; i++) {
|
||||
if (!(session.approved_rsvps[i].id in inSessionUsers)) {
|
||||
// do not show the user in this section if he is already in the session
|
||||
if ($.inArray(session.approved_rsvps[i].id, inSessionUsers) === -1) {
|
||||
if (session.approved_rsvps[i].id === context.JK.currentUserId) {
|
||||
showJoinLink = true;
|
||||
}
|
||||
|
|
@ -61,6 +66,9 @@
|
|||
rsvpUsersHtml += rsvpUserInfo[0];
|
||||
latencyHtml += rsvpUserInfo[1];
|
||||
}
|
||||
else {
|
||||
showJoinLink = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,18 +97,25 @@
|
|||
// wire up the Join Link to the T&Cs dialog
|
||||
var $parentRow = $('tr[id=' + session.id + ']', tbGroup);
|
||||
$('.join-link', $parentRow).click(function(evt) {
|
||||
if(!context.JK.guardAgainstBrowser(app)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!context.JK.JamServer.connected) {
|
||||
app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.');
|
||||
return false;
|
||||
}
|
||||
// If no FTUE, show that first.
|
||||
if (!context.JK.hasOneConfiguredDevice() || context.JK.TrackHelpers.getUserTracks(context.jamClient).length == 0) {
|
||||
app.afterFtue = function() { joinClick(session.id); };
|
||||
app.layout.startNewFtue();
|
||||
}
|
||||
else {
|
||||
joinClick(session.id);
|
||||
}
|
||||
|
||||
gearUtils.guardAgainstInvalidConfiguration(app)
|
||||
.fail(function() {
|
||||
app.notify(
|
||||
{ title: "Unable to Join Session",
|
||||
text: "You can only join a session once you have working audio gear and a tested internet connection."
|
||||
})
|
||||
})
|
||||
.done(function(){
|
||||
joinClick(session.id);
|
||||
})
|
||||
|
||||
return false;
|
||||
});
|
||||
|
|
@ -119,10 +134,10 @@
|
|||
$('#actionHeader', tbGroup).html('RSVP');
|
||||
|
||||
var i = 0;
|
||||
var rsvpUsersHtml = '', openSlotsHtml = '', pendingInvitationsHtml = '', latencyHtml = '', notationFileHtml = '';
|
||||
var rsvpUsersHtml = '', openSlotsHtml = '', latencyHtml = '', notationFileHtml = '';
|
||||
|
||||
// render users who have approved RSVPs
|
||||
if (session.approved_rsvps) {
|
||||
if (session.approved_rsvps && session.approved_rsvps.length > 0) {
|
||||
for (i=0; i < session.approved_rsvps.length; i++) {
|
||||
if (session.approved_rsvps[i].id === context.JK.currentUserId) {
|
||||
hasApprovedRsvp = true;
|
||||
|
|
@ -132,6 +147,10 @@
|
|||
latencyHtml += rsvpUserInfo[1];
|
||||
}
|
||||
}
|
||||
// this provides a buffer at the top to shift the first latency tag down in the event there are NO RSVP musicians
|
||||
else {
|
||||
latencyHtml += "<div style='height:15px;'> </div>";
|
||||
}
|
||||
|
||||
// render open slots
|
||||
if (session.open_slots) {
|
||||
|
|
@ -147,7 +166,6 @@
|
|||
if (session.pending_invitations[i].id === context.JK.currentUserId) {
|
||||
hasInvitation = true;
|
||||
}
|
||||
pendingInvitationsHtml += createPendingInvitation(session.pending_invitations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +184,6 @@
|
|||
}
|
||||
|
||||
var sessionVals = buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml);
|
||||
sessionVals.pending_invitations = pendingInvitationsHtml.length > 0 ? pendingInvitationsHtml : 'N/A';
|
||||
sessionVals.rsvp_link_display_style = showRsvpLink ? "block" : "none";
|
||||
|
||||
var row = context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals);
|
||||
|
|
@ -319,15 +336,6 @@
|
|||
return context.JK.fillTemplate($openSlotsTemplate.html(), slot);
|
||||
}
|
||||
|
||||
function createPendingInvitation(user) {
|
||||
|
||||
var invitationVals = {
|
||||
avatar_url: context.JK.resolveAvatarUrl(user.photo_url)
|
||||
};
|
||||
|
||||
return context.JK.fillTemplate($pendingInvitationsTemplate.html(), invitationVals);
|
||||
}
|
||||
|
||||
function createNotationFile(notation) {
|
||||
var notationVals = {
|
||||
file_url: notation.file_url,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
context.JK.SessionSettingsDialog = function(app, sessionScreen) {
|
||||
var logger = context.JK.logger;
|
||||
var $dialog;
|
||||
var $screen = $('#session-settings');
|
||||
var $selectedFilenames = $screen.find('#selected-filenames');
|
||||
var $uploadSpinner = $screen.find($('.upload-spinner'));
|
||||
var $selectedFilenames = $('#settings-selected-filenames');
|
||||
var $inputFiles = $('#settings-select-files');
|
||||
var $btnSelectFiles = $screen.find('.btn-select-files');
|
||||
var rest = new JK.Rest();
|
||||
|
||||
function beforeShow(data) {
|
||||
|
|
@ -19,7 +25,6 @@
|
|||
// genre
|
||||
context.JK.GenreSelectorHelper.setSelectedGenres('#session-settings-genre', currentSession.genres);
|
||||
|
||||
|
||||
// name
|
||||
$('#session-settings-name').val(currentSession.name);
|
||||
|
||||
|
|
@ -56,7 +61,12 @@
|
|||
}
|
||||
|
||||
// notation files
|
||||
|
||||
$selectedFilenames.empty();
|
||||
for (var i=0; i < currentSession.music_notations.length; i++) {
|
||||
var notation = currentSession.music_notations[i];
|
||||
console.log('notation.file_name %o', notation.file_name);
|
||||
$selectedFilenames.append('<a href="' + notation.file_url + '" rel="external">' + notation.file_name + '</a> ');
|
||||
}
|
||||
|
||||
context.JK.dropdown($('#session-settings-language'));
|
||||
context.JK.dropdown($('#session-settings-musician-access'));
|
||||
|
|
@ -67,7 +77,7 @@
|
|||
|
||||
var data = {};
|
||||
|
||||
data.genre = $('#session-settings-genre').val();
|
||||
data.genre = context.JK.GenreSelectorHelper.getSelectedGenres('#session-settings-genre')[0];
|
||||
data.name = $('#session-settings-name').val();
|
||||
data.description = $('#session-settings-description').val();
|
||||
data.language = $('#session-settings-language').val();
|
||||
|
|
@ -105,6 +115,78 @@
|
|||
rest.updateSession($('#session-settings-id').val(), data).done(settingsSaved);
|
||||
}
|
||||
|
||||
function changeSelectedFiles() {
|
||||
var fileNames = [];
|
||||
var files = $inputFiles.get(0).files;
|
||||
var error = false;
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
var name = files.item(i).name;
|
||||
var ext = name.split('.').pop();
|
||||
if ($.inArray(ext, ["pdf", "png", "jpg", "jpeg", "gif", "xml", "mxl", "txt"]) == -1) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
fileNames.push(name);
|
||||
}
|
||||
|
||||
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.");
|
||||
$inputFiles.replaceWith($inputFiles.clone(true));
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
// upload as soon as user picks their files.
|
||||
uploadNotations($inputFiles.get(0).files)
|
||||
.done(function() {
|
||||
context._.each(fileNames, function(fileName) {
|
||||
$selectedFilenames.append(fileName);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function uploadNotations(notations) {
|
||||
var formData = new FormData();
|
||||
$.each(notations, function(i, file) {
|
||||
formData.append('files[]', file);
|
||||
});
|
||||
|
||||
formData.append('client_id', app.clientId);
|
||||
|
||||
$btnSelectFiles.text('UPLOADING...').data('uploading', true)
|
||||
$uploadSpinner.show();
|
||||
return rest.uploadMusicNotations(formData)
|
||||
.done(function(response) {
|
||||
var error_files = [];
|
||||
$.each(response, function(i, music_notation) {
|
||||
if (music_notation.errors) {
|
||||
//error_files.push(createSessionSettings.notations[i].name);
|
||||
}
|
||||
})
|
||||
if (error_files.length > 0) {
|
||||
app.notifyAlert("Failed to upload notations.", error_files.join(', '));
|
||||
}
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, "Unable to upload music notations");
|
||||
})
|
||||
.always(function() {
|
||||
$btnSelectFiles.text('SELECT FILES...').data('uploading', null)
|
||||
$uploadSpinner.hide();
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSelectFiles(event) {
|
||||
if($btnSelectFiles.data('uploading')) {
|
||||
logger.debug("ignoring click of SELECT FILES... while uploading")
|
||||
return false;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
$('#session-select-files').trigger('click');
|
||||
return false;
|
||||
}
|
||||
|
||||
function settingsSaved(response) {
|
||||
// No response returned from this call. 204.
|
||||
sessionScreen.refreshCurrentSession(true);
|
||||
|
|
@ -113,6 +195,9 @@
|
|||
|
||||
function events() {
|
||||
$('#session-settings-dialog-submit').on('click', saveSettings);
|
||||
|
||||
$inputFiles.on('change', changeSelectedFiles);
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
}
|
||||
|
||||
this.initialize = function() {
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
app.layout.showDialog('share-dialog');
|
||||
return app.layout.showDialog('share-dialog');
|
||||
}
|
||||
|
||||
// function initDialog() {
|
||||
|
|
|
|||
|
|
@ -26,25 +26,25 @@
|
|||
function launchCommentDialog(options) {
|
||||
var commentDialog = new JK.CommentDialog(JK.app, options);
|
||||
commentDialog.initialize();
|
||||
commentDialog.showDialog();
|
||||
return commentDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchShareDialog(entityId, entityType) {
|
||||
var shareDialog = new JK.ShareDialog(JK.app, entityId, entityType);
|
||||
shareDialog.initialize(JK.FacebookHelperInstance);
|
||||
shareDialog.showDialog();
|
||||
return shareDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRsvpSubmitDialog(sessionId) {
|
||||
var rsvpDialog = new JK.RsvpSubmitDialog(JK.app, sessionId);
|
||||
rsvpDialog.initialize();
|
||||
rsvpDialog.showDialog();
|
||||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRsvpCancelDialog(sessionId, rsvpRequestId) {
|
||||
var rsvpDialog = new JK.RsvpCancelDialog(JK.app, sessionId, rsvpRequestId);
|
||||
rsvpDialog.initialize();
|
||||
rsvpDialog.showDialog();
|
||||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
this.addSessionLike = addSessionLike;
|
||||
|
|
|
|||
|
|
@ -936,8 +936,11 @@
|
|||
|
||||
context.JK.guardAgainstBrowser = function(app, args) {
|
||||
if(!gon.isNativeClient) {
|
||||
logger.debug("guarding against normal browser on screen thaht requires native client")
|
||||
app.layout.showDialog('launch-app-dialog', args)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -10,8 +10,15 @@
|
|||
var ui = new context.JK.UIHelper(app);
|
||||
var $btnAction = $("#btn-action");
|
||||
|
||||
var LATENCY = {
|
||||
GOOD : {description: "GOOD", style: "latency-green", min: 0.0, max: 20.0},
|
||||
MEDIUM : {description: "MEDIUM", style: "latency-yellow", min: 20.0, max: 40.0},
|
||||
POOR : {description: "POOR", style: "latency-red", min: 40.0, max: 10000000000.0},
|
||||
UNREACHABLE: {description: "UNREACHABLE", style: "latency-grey", min: -1, max: -1},
|
||||
UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2}
|
||||
};
|
||||
|
||||
function addComment(musicSessionId) {
|
||||
console.log("here");
|
||||
var comment = $("#txtSessionInfoComment").val();
|
||||
if ($.trim(comment).length > 0) {
|
||||
rest.addSessionInfoComment(musicSessionId, comment)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
var ASSIGNMENT = context.JK.ASSIGNMENT;
|
||||
var VOICE_CHAT = context.JK.VOICE_CHAT;
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
|
||||
gearUtils.SKIPPED_NETWORK_TEST = -1; // we store a negative 1 to mean that we let the user skip.
|
||||
|
||||
gearUtils.skippedNetworkTest = false; // we allow someone to play in session (for one client run) if it's our fault they can't network test score
|
||||
|
||||
// checks if it's an assigned OUTPUT or ASSIGNED CHAT
|
||||
gearUtils.isChannelAssigned = function (channel) {
|
||||
|
|
@ -271,4 +276,88 @@
|
|||
app.notifyServerError(jqXHR, "Unable to sync audio latency")
|
||||
});
|
||||
}
|
||||
|
||||
// if the user has a good user network score, immediately returns with a resolved deferred object.
|
||||
// if not, the user will have the network test dialog prompted... once it's closed, then you'll be told reject() if score is still bad, or resolve() if now good
|
||||
gearUtils.guardAgainstBadNetworkScore = function(app) {
|
||||
var deferred = new $.Deferred();
|
||||
|
||||
if (!gearUtils.validNetworkScore()) {
|
||||
// invalid network test score. They have to score to move on
|
||||
app.layout.showDialog('network-test').one(EVENTS.DIALOG_CLOSED, function() {
|
||||
if(gearUtils.validNetworkScore()) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
deferred.resolve();
|
||||
}
|
||||
return deferred;
|
||||
}
|
||||
|
||||
// XXX this isn't quite right... it needs to check if a good device is *active*
|
||||
// but seen too many problems so far with the backend not reporting any profile active
|
||||
gearUtils.hasGoodActiveProfile = function(app) {
|
||||
return context.JK.hasOneConfiguredDevice() && context.JK.TrackHelpers.getUserTracks(context.jamClient).length > 0
|
||||
}
|
||||
|
||||
// if the user does not have a currently active, good profile, then they are made to deal with it
|
||||
gearUtils.guardAgainstInvalidGearConfiguration = function(app) {
|
||||
var deferred = new $.Deferred();
|
||||
|
||||
if (!gearUtils.hasGoodActiveProfile()) {
|
||||
app.layout.showDialog('gear-wizard').one(EVENTS.DIALOG_CLOSED, function() {
|
||||
if(gearUtils.hasGoodActiveProfile() && gearUtils.validNetworkScore()) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
// tests both device config, and network score
|
||||
gearUtils.guardAgainstInvalidConfiguration = function(app) {
|
||||
var deferred = new $.Deferred();
|
||||
gearUtils.guardAgainstInvalidGearConfiguration(app)
|
||||
.fail(function() {
|
||||
deferred.reject();
|
||||
})
|
||||
.done(function() {
|
||||
gearUtils.guardAgainstBadNetworkScore(app)
|
||||
.fail(function() {
|
||||
deferred.reject();
|
||||
})
|
||||
.done(function() {
|
||||
deferred.resolve();
|
||||
})
|
||||
})
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
||||
gearUtils.skipNetworkTest = function() {
|
||||
context.jamClient.SetNetworkTestScore(gearUtils.SKIPPED_NETWORK_TEST);
|
||||
gearUtils.skippedNetworkTest = true;
|
||||
}
|
||||
|
||||
gearUtils.isNetworkTestSkipped = function() {
|
||||
return gearUtils.skippedNetworkTest;
|
||||
}
|
||||
|
||||
gearUtils.validNetworkScore = function() {
|
||||
return gearUtils.skippedNetworkTest || context.jamClient.GetNetworkTestScore() >= 2;
|
||||
}
|
||||
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
@ -54,6 +54,7 @@
|
|||
*= require ./textMessageDialog
|
||||
*= require ./acceptFriendRequestDialog
|
||||
*= require ./launchAppDialog
|
||||
*= require ./editRecordingDialog
|
||||
*= require ./iconInstrumentSelect
|
||||
*= require ./terms
|
||||
*= require ./createSession
|
||||
|
|
|
|||
|
|
@ -340,6 +340,41 @@ a.arrow-down {
|
|||
width:200px;
|
||||
}
|
||||
|
||||
.btn-select-files {
|
||||
margin-top: 10px;
|
||||
margin-left:0;
|
||||
width:110px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.spinner-small.upload-spinner {
|
||||
display:none;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.select-files-section {
|
||||
position:absolute;
|
||||
}
|
||||
|
||||
#settings-selected-filenames {
|
||||
font-size:12px;
|
||||
|
||||
span {
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
overflow:hidden;
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-files-section {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
#session-controls {
|
||||
width:100%;
|
||||
padding:6px 0px 11px 0px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
@import "client/common";
|
||||
|
||||
#edit-recording-dialog {
|
||||
|
||||
min-height:330px;
|
||||
|
||||
input, textarea {
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-top:20px;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
margin-top:0;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
float:right;
|
||||
clear:both;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
label[for="name"] {
|
||||
|
||||
}
|
||||
input[name="name"] {
|
||||
margin-top:5px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
label[for="description"] {
|
||||
|
||||
}
|
||||
textarea[name="description"] {
|
||||
margin-top:5px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
label[for="genre"] {
|
||||
display:inline;
|
||||
float:left;
|
||||
line-height:26px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
select[name="genre"] {
|
||||
float:left;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
.genre-selector {
|
||||
float:left;
|
||||
.dropdown-wrapper {
|
||||
margin-left:5px;
|
||||
}
|
||||
}
|
||||
|
||||
label[for="is_public"] {
|
||||
display: inline;
|
||||
float:right;
|
||||
line-height: 26px;
|
||||
padding-right: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
select[name="is_public"] {
|
||||
float:right;
|
||||
}
|
||||
div[purpose="is_public"] {
|
||||
float:right;
|
||||
.icheckbox_minimal {
|
||||
float:right;
|
||||
margin-top:4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -2,4 +2,9 @@
|
|||
.recording-current {
|
||||
position:absolute; // solves a problem with duration wrapping--only in firefox
|
||||
}
|
||||
|
||||
.btn-refresh-holder {
|
||||
float:right;
|
||||
margin-right:10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -66,4 +66,3 @@
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -328,6 +328,7 @@ input[type="text"], input[type="password"]{
|
|||
|
||||
textarea {
|
||||
font-size:15px;
|
||||
padding:3px;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -317,4 +317,60 @@
|
|||
|
||||
#btn-add-friend {
|
||||
display:none;
|
||||
}
|
||||
|
||||
#profile-history {
|
||||
padding:0 10px 0 20px;
|
||||
width:100%;
|
||||
position:relative;
|
||||
height:100%;
|
||||
@include border_box_sizing;
|
||||
|
||||
#user-feed-controls {
|
||||
width:100%;
|
||||
@include border_box_sizing;
|
||||
position:relative;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.btn-refresh-holder {
|
||||
left: 95%; // 5 * 19% to right-align 5 user blocks (in conjunction with the margin-left
|
||||
margin-left: -65px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.filter-body {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
left: 20px;
|
||||
position: absolute;
|
||||
width: 95%;
|
||||
padding-top:0;
|
||||
margin-top:10px;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.profile-wrapper {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.feed-entry .feed-details {
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
.recording-current {
|
||||
position:absolute; // solves a problem with duration wrapping--only in firefox
|
||||
}
|
||||
|
||||
.content-body-scroller {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
.no-feed-msg {
|
||||
text-align:center
|
||||
}
|
||||
}
|
||||
|
|
@ -22,9 +22,15 @@ table.findsession-table, table.local-recordings {
|
|||
}
|
||||
|
||||
td.latency {
|
||||
padding-top: 15px !important;
|
||||
text-align:center !important;
|
||||
}
|
||||
|
||||
td.latency div.center {
|
||||
display: inline-block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.noborder {
|
||||
border-right:none;
|
||||
}
|
||||
|
|
@ -65,6 +71,7 @@ table.findsession-table, table.local-recordings {
|
|||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#868686;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-green {
|
||||
|
|
@ -74,6 +81,7 @@ table.findsession-table, table.local-recordings {
|
|||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#71a43b;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-yellow {
|
||||
|
|
@ -83,6 +91,7 @@ table.findsession-table, table.local-recordings {
|
|||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#cc9900;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-red {
|
||||
|
|
@ -92,6 +101,7 @@ table.findsession-table, table.local-recordings {
|
|||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#980006;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.avatar-tiny {
|
||||
|
|
|
|||
|
|
@ -272,6 +272,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
a.edit-recording-dialog {
|
||||
font-size:12px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.is_private {
|
||||
display:none;
|
||||
font-size:12px;
|
||||
font-style:italic;
|
||||
&.enabled {
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
|
||||
.play-count {
|
||||
margin-right:10px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -589,4 +589,8 @@ strong {
|
|||
fieldset.login-error .login-error-msg {
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
body.jam.web.welcome .no-websocket-connection {
|
||||
display:none;
|
||||
}
|
||||
|
|
@ -1,23 +1,54 @@
|
|||
/*.session-controls {
|
||||
background-color:#471f18;
|
||||
}
|
||||
|
||||
.session-controls.inprogress {
|
||||
background-color:#4C742E;
|
||||
}
|
||||
|
||||
.session-status-ended, .session-status {
|
||||
float:left;
|
||||
font-size:18px;
|
||||
}
|
||||
|
||||
.session-status-inprogress {
|
||||
float:left;
|
||||
font-size:15px;
|
||||
color:#cccc00;
|
||||
margin-left:20px;
|
||||
}*/
|
||||
|
||||
#btnPlayPause {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
table.musicians {
|
||||
margin-top:-3px;
|
||||
}
|
||||
|
||||
table.musicians td {
|
||||
border-right:none;
|
||||
border-top:none;
|
||||
padding:2px;
|
||||
vertical-align:middle !important;
|
||||
}
|
||||
|
||||
.latency-grey {
|
||||
width: 50px;
|
||||
height: 10px;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#868686;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-green {
|
||||
width: 50px;
|
||||
height: 10px;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#71a43b;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-yellow {
|
||||
width: 50px;
|
||||
height: 10px;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#cc9900;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.latency-red {
|
||||
width: 40px;
|
||||
height: 10px;
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-weight:200;
|
||||
font-size:11px;
|
||||
background-color:#980006;
|
||||
text-align:center;
|
||||
}
|
||||
|
|
@ -19,30 +19,20 @@ class ApiClaimedRecordingsController < ApiController
|
|||
end
|
||||
|
||||
def update
|
||||
|
||||
if @claimed_recording.user_id != current_user.id
|
||||
raise PermissionError, 'only owner of claimed_recording can update it'
|
||||
end
|
||||
|
||||
begin
|
||||
@claimed_recording.update_fields(current_user, params)
|
||||
respond_with responder: ApiResponder, :status => 204
|
||||
rescue
|
||||
render :json => { :message => "claimed_recording could not be updated" }, :status => 403
|
||||
end
|
||||
@claimed_recording.update_fields(current_user, params)
|
||||
respond_with @claimed_recording
|
||||
end
|
||||
|
||||
def delete
|
||||
if @claimed_recording.user_id != current_user.id
|
||||
raise PermissionError, 'only owner of claimed_recording can update it'
|
||||
end
|
||||
#begin
|
||||
#@claimed_recording.discard(current_user)
|
||||
#render :json => {}, :status => 204
|
||||
# respond_with responder: ApiResponder, :status => 204
|
||||
#rescue
|
||||
#render :json => { :message => "claimed_recording could not be deleted" }, :status => 403
|
||||
#end
|
||||
@claimed_recording.discard(current_user)
|
||||
render :json => {}, :status => 200
|
||||
end
|
||||
|
||||
def download
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ class ApiMusicSessionsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def scheduled
|
||||
@music_sessions = MusicSession.scheduled(current_user)
|
||||
end
|
||||
|
|
@ -175,7 +174,7 @@ class ApiMusicSessionsController < ApiController
|
|||
@music_session.music_session,
|
||||
params[:name],
|
||||
params[:description],
|
||||
params[:genre],
|
||||
params[:genre] ? Genre.find(params[:genre]) : nil,
|
||||
params[:language],
|
||||
params[:musician_access],
|
||||
params[:approval_required],
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ class ApiRecordingsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def parse_filename
|
||||
@recorded_track = RecordedTrack.find_by_recording_id_and_client_track_id!(params[:id], params[:track_id])
|
||||
|
|
|
|||
|
|
@ -47,9 +47,15 @@ class MusicSessionsController < ApplicationController
|
|||
|
||||
# run these 3 queries only if the user has access to the page
|
||||
if @can_view
|
||||
@approved_rsvps = @music_session.approved_rsvps
|
||||
@open_slots = @music_session.open_slots
|
||||
@pending_invitations = @music_session.pending_invitations
|
||||
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
|
||||
end
|
||||
|
||||
render :layout => "web"
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ glue :recording do
|
|||
|
||||
child(:claimed_recordings => :claimed_recordings) {
|
||||
|
||||
attributes :id, :name, :description, :is_public, :genre_id, :has_mix?
|
||||
attributes :id, :name, :description, :is_public, :genre_id, :has_mix?, :user_id
|
||||
|
||||
child(:user => :creator) {
|
||||
attributes :id, :first_name, :last_name, :photo_url
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@ else
|
|||
[item.genre.description] # XXX: need to return single genre; not array
|
||||
end
|
||||
|
||||
child(:music_notations => :music_notations) {
|
||||
attributes :id, :file_name
|
||||
|
||||
node do |music_notation|
|
||||
{ file_url: music_notation["file_url"] }
|
||||
end
|
||||
}
|
||||
|
||||
if :is_recording?
|
||||
node do |music_session|
|
||||
{ :recording => partial("api_recordings/show", :object => music_session.recording) }
|
||||
|
|
@ -44,7 +52,6 @@ else
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
child({:invitations => :invitations}) {
|
||||
attributes :id, :sender_id, :receiver_id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ if !current_user
|
|||
else
|
||||
|
||||
attributes :id, :music_session_id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat,
|
||||
:band_id, :user_id, :genre_id, :created_at, :like_count, :comment_count, :scheduled_start, :scheduled_duration,
|
||||
:band_id, :user_id, :genre_id, :created_at, :like_count, :comment_count, :play_count, :scheduled_start, :scheduled_duration,
|
||||
:language, :recurring_mode, :language_description, :scheduled_start_time, :access_description, :timezone, :timezone_description,
|
||||
:musician_access_description, :fan_access_description, :session_removed_at, :legal_policy, :open_rsvps
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ child(:comments => :comments) {
|
|||
|
||||
child(:claimed_recordings => :claimed_recordings) {
|
||||
|
||||
attributes :id, :name, :description, :is_public, :genre_id
|
||||
attributes :id, :name, :description, :is_public, :genre_id, :has_mix?, :user_id
|
||||
|
||||
node :share_url do |claimed_recording|
|
||||
unless claimed_recording.share_token.nil?
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
<!-- generic banner for use by an code -->
|
||||
<div class="overlay" id="banner_overlay"></div>
|
||||
<div id="banner" class="dialog-overlay-sm" data-type="">
|
||||
|
||||
<!-- dialog header -->
|
||||
<div class="content-head">
|
||||
<%= image_tag("content/icon_alert.png", :height => '24', :width => '24', :class => "content-icon") %><h1></h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="dialog-inner">
|
||||
|
||||
</div>
|
||||
<!-- end right column -->
|
||||
<br clear="all" class="end-content">
|
||||
|
||||
<div class="right buttons">
|
||||
<a class="button-orange close-btn">CLOSE</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="template-app-in-read-only-volume">
|
||||
<div class="template-app-in-read-only-volume">
|
||||
<p> The JamKazam application is running in a read-only volume. This stops the automatic update feature
|
||||
from working, and may cause other issues because it is not a supported configuration.</p>
|
||||
<p> So let's fix it. Don't worry--it's easy to do. Please read on.</p>
|
||||
<p> First, here's almost certainly what happened to cause this problem: after JamKazam.dmg was downloaded, it was then double-clicked and a window opened showing the contents of the dmg.
|
||||
The JamKazam application icon was double-clicked inside that opened window. Unfortunately, that isn't OK.</p>
|
||||
<p>Instead, do this to move JamKazam to a good location, and run it from there:</p>
|
||||
<ol>
|
||||
<li class="download-dmg">Download the latest mac installer from the <a href="/downloads">Downloads</a> page.<br/><em>(the download will have a filename ending in .dmg)</em></li>
|
||||
<li>Double-click the downloaded dmg file to open it.</li>
|
||||
<li>In the resulting screen, drag the JamKazam icon to the Applications folder. It will show a progress bar as it copies.</li>
|
||||
<li>Double-click the Applications folder to go into it.</li>
|
||||
<li>If you are still running the JamKazam application, you will need to stop it before executing the last step.</li>
|
||||
<li>Find the JamKazam application in the Applications folder, and double-click the icon to launch it!</li>
|
||||
</ol>
|
||||
<!---<p>The following animation shows the the steps, after once you've downloaded the JamKazam '.dmg'.</p>-->
|
||||
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#banner_overlay.overlay
|
||||
#banner.dialog-overlay-sm{ 'data-type' => '' }
|
||||
.content-head
|
||||
= image_tag("content/icon_alert.png", :height => '24', :width => '24', :class => "content-icon")
|
||||
%h1
|
||||
|
||||
.dialog-inner
|
||||
|
||||
%br.end-content{ clear: 'all'}
|
||||
|
||||
.right.buttons
|
||||
%a.button-orange.close-btn CLOSE
|
||||
%a.button-orange.yes-btn YES
|
||||
%a.button-grey.no-btn CANCEL
|
||||
|
||||
%script{type: 'text/template', id: 'template-app-in-read-only-volume'}
|
||||
.template-app-in-read-only-volume
|
||||
%p The JamKazam application is running in a read-only volume. This stops the automatic update feature from working, and may cause other issues because it is not a supported configuration.
|
||||
%p So let's fix it. Don't worry--it's easy to do--please read on.
|
||||
%p First, here's almost certainly what happened to cause this problem: after JamKazam.dmg was downloaded, it was then double-clicked and a window opened showing the contents of the dmg. The JamKazam application icon was double-clicked inside that opened window. Unfortunately, that isn't OK.
|
||||
%p Instead, do this to move JamKazam to a good location, and run it from there:
|
||||
%ol
|
||||
%li.download-dmg
|
||||
Download the latest mac installer from the
|
||||
%a{href:"/downloads"}Downloads
|
||||
page.
|
||||
%br
|
||||
%em (the download will have a filename ending in .dmg)
|
||||
%li Double-click the downloaded dmg file to open it.
|
||||
%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!
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.dialog.configure-tracks{ layout: 'dialog', 'layout-id' => 'edit-recording', id: 'edit-recording-dialog'}
|
||||
.content-head
|
||||
= image_tag "content/icon_add.png", {:width => 19, :height => 19, :class => 'content-icon' }
|
||||
%h1 Edit Recording
|
||||
.dialog-inner
|
||||
%form
|
||||
.field
|
||||
%label{for: 'name'} Recording name:
|
||||
%input{type: 'text', name: 'name'}
|
||||
.field
|
||||
%label{for: 'description'} Description:
|
||||
%textarea{name: 'description', rows: '4'}
|
||||
.field.genre-selector
|
||||
%label{for: 'genre'} Genre:
|
||||
%select{name:'genre'}
|
||||
.field{purpose: 'is_public'}
|
||||
%input{type: 'checkbox', name: 'is_public'}
|
||||
%label{for: 'is_public'} Public Recording
|
||||
|
||||
.buttons
|
||||
%a.button-grey.cancel-btn CANCEL
|
||||
%a.button-orange.delete-btn DELETE
|
||||
%a.button-orange.save-btn UPDATE
|
||||
%br{clear: 'all'}
|
||||
|
|
@ -81,14 +81,14 @@
|
|||
<td width="30%">
|
||||
<table class="musician-groups" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td class="bold">{name}</td>
|
||||
<td align="right" width="75">({genres})</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">{description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">Notation Files:</td>
|
||||
<td>Notation Files:</td>
|
||||
<td>{notation_files}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -121,21 +121,19 @@
|
|||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="10%" align="center">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
{latency}
|
||||
</table>
|
||||
<td width="10%" class="latency">
|
||||
<div class="center">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
{latency}
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
<tr><td class="bold">Chat Language:</td></tr>
|
||||
<tr><td>{language}</td></tr>
|
||||
<tr><td class="bold">Musician Access:</td></tr>
|
||||
<tr><td>{musician_access}</td></tr>
|
||||
<tr><td class="bold">Fan Access:</td></tr>
|
||||
<tr><td>{fan_access}</td></tr>
|
||||
<tr><td class="bold">Legal Policy:</td></tr>
|
||||
<tr><td>{legal_policy}</td></tr>
|
||||
<tr><td><span class="bold">Chat Language:</span><br/>{language}</td></tr>
|
||||
<tr><td><span class="bold">Musician Access:</span><br/>{musician_access}</td></tr>
|
||||
<tr><td><span class="bold">Fan Access:</span><br/>{fan_access}</td></tr>
|
||||
<tr><td><span class="bold">Legal Policy:</span><br/>{legal_policy}</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="noborder" style="text-align:center; vertical-align:middle;">
|
||||
|
|
@ -152,7 +150,7 @@
|
|||
<td width="30%">
|
||||
<table class="musician-groups" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td class="bold">{name}</td>
|
||||
<td align="right" width="75">({genres})</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -182,31 +180,21 @@
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Invited:</td>
|
||||
<td>
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
{pending_invitations}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="10%" align="center">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
{latency}
|
||||
</table>
|
||||
<td width="10%" class="latency pt10">
|
||||
<div class="center">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
{latency}
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<table class="musicians" cellpadding="0" cellspacing="0">
|
||||
<tr><td class="bold">Chat Language:</td></tr>
|
||||
<tr><td>{language}</td></tr>
|
||||
<tr><td class="bold">Musician Access:</td></tr>
|
||||
<tr><td>{musician_access}</td></tr>
|
||||
<tr><td class="bold">Fan Access:</td></tr>
|
||||
<tr><td>{fan_access}</td></tr>
|
||||
<tr><td class="bold">Legal Policy:</td></tr>
|
||||
<tr><td>{legal_policy}</td></tr>
|
||||
<tr><td><span class="bold">Chat Language:</span><br/>{language}</td></tr>
|
||||
<tr><td><span class="bold">Musician Access:</span><br/>{musician_access}</td></tr>
|
||||
<tr><td><span class="bold">Fan Access:</span><br/>{fan_access}</td></tr>
|
||||
<tr><td><span class="bold">Legal Policy:</span><br/>{legal_policy}</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="noborder" style="text-align:center; vertical-align:middle;">
|
||||
|
|
@ -249,10 +237,6 @@
|
|||
</tr>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="template-pending-invitations">
|
||||
<img src="{avatar_url}" />
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="template-latency">
|
||||
<tr class="mb15">
|
||||
<td class="{latency_style}">
|
||||
|
|
|
|||
|
|
@ -88,9 +88,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="profile-history" class="profile-wrapper">
|
||||
<%= form_tag('', {:id => 'user-feed-form', :class => 'inner-content'}) do %>
|
||||
<%= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_FEED, :id => 'user-feed-controls'}) %>
|
||||
<div class="filter-body">
|
||||
<div class="content-body-scroller">
|
||||
<br clear="all" />
|
||||
<div class="profile-wrapper">
|
||||
<div class="feed-content"></div>
|
||||
<a href="/api/feeds?page=1" class="btn-next-pager">Next</a>
|
||||
<div id="end-of-user-feeds-list" class="end-of-list">No more feed entries</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
</div>
|
||||
<div id="profile-bands" class="profile-wrapper profile-body-content">
|
||||
<br clear="all" />
|
||||
|
|
|
|||
|
|
@ -54,12 +54,20 @@
|
|||
.clearall.left.w25.ib.mb10
|
||||
Notation Files:
|
||||
.right.w75.ib.mb10
|
||||
List of existing notation files goes here
|
||||
.w40.left
|
||||
.selected-files-section
|
||||
%div{:id => "settings-selected-filenames"}
|
||||
.right.ib.mb10
|
||||
%a.button-orange.btn-select-files SELECT FILES...
|
||||
%input.hidden{:type => "file", :id => "settings-select-files", :value => "Select Files...", :accept => ".pdf, .png, .jpg, .jpeg, .gif, .xml, .mxl, .txt"}
|
||||
.spinner-small.upload-spinner
|
||||
|
||||
.clearall.right.mt10
|
||||
%a.button-orange{:href => 'TBD', :rel => 'external'} HELP
|
||||
%a.button-grey{'layout-action' => "close"} CANCEL
|
||||
%a.button-orange{:id => "session-settings-dialog-submit", :href => "#"} UPDATE SETTINGS
|
||||
%a.button-orange{:id => "session-settings-dialog-submit"} UPDATE SETTINGS
|
||||
|
||||
.clearall
|
||||
|
||||
%br/
|
||||
%br{:clear => 'all'}/
|
||||
|
|
@ -72,8 +72,8 @@
|
|||
<% end -%>
|
||||
|
||||
<% if :feed == filter_label %>
|
||||
<div class="right mr10">
|
||||
<a class="button-grey btn-refresh-entries" href="/client#/feed" id="btn-refresh-feed">REFRESH</a>
|
||||
<div class="btn-refresh-holder">
|
||||
<a class="button-grey btn-refresh-entries" href="/client#/feed">REFRESH</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
<%= render "account_sessions" %>
|
||||
<%= render "account_session_detail" %>
|
||||
<%= render "configure_tracks_dialog" %>
|
||||
<%= render "edit_recording_dialog" %>
|
||||
<%= render "invitationDialog" %>
|
||||
<%= render "inviteMusicians" %>
|
||||
<%= render "hoverBand" %>
|
||||
|
|
@ -131,6 +132,9 @@
|
|||
if (this.didInitAfterConnect) return;
|
||||
this.didInitAfterConnect = true
|
||||
|
||||
// This is a helper class with a singleton. No need to instantiate.
|
||||
JK.GenreSelectorHelper.initialize(JK.app);
|
||||
|
||||
var recordingManager = new JK.RecordingManager();
|
||||
|
||||
var facebookHelper = new JK.FacebookHelper(JK.app);
|
||||
|
|
@ -158,6 +162,8 @@
|
|||
var launchAppDialog = new JK.LaunchAppDialog(JK.app);
|
||||
launchAppDialog.initialize();
|
||||
|
||||
var editRecordingDialog = new JK.EditRecordingDialog(JK.app);
|
||||
editRecordingDialog.initialize();
|
||||
|
||||
var userDropdown = new JK.UserDropdown(JK.app);
|
||||
JK.UserDropdown = userDropdown;
|
||||
|
|
@ -207,9 +213,6 @@
|
|||
var searchResultScreen = new JK.SearchResultScreen(JK.app);
|
||||
searchResultScreen.initialize();
|
||||
|
||||
// This is a helper class with a singleton. No need to instantiate.
|
||||
JK.GenreSelectorHelper.initialize();
|
||||
|
||||
var inviteMusiciansUtil1 = new JK.InviteMusiciansUtil(JK.app);
|
||||
inviteMusiciansUtil1.initialize(friendSelectorDialog);
|
||||
// var createSessionScreen = new JK.CreateSessionScreen(JK.app);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<%= render "layouts/social_meta" %>
|
||||
<% end %>
|
||||
</head>
|
||||
<body class="web jam">
|
||||
<body class="web jam <%= yield(:page_name) %>">
|
||||
<%= javascript_include_tag "web/web" %>
|
||||
<div class="dialog-overlay op70" style="display:none; width:100%; height:100%; z-index:99;"></div>
|
||||
|
||||
|
|
@ -108,6 +108,7 @@
|
|||
<% end %>
|
||||
|
||||
JK.app = JK.JamKazam();
|
||||
|
||||
var jamServer = new JK.JamServer(JK.app, $.noop);
|
||||
jamServer.initialize();
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
%strong Notation Files:
|
||||
.right.w75.ib.mb10.notations
|
||||
- @music_session.music_notations.each do |n|
|
||||
%a.gold{:href => n.file_url}= n.file_name
|
||||
%a.gold{:href => n.file_url, :target => "_blank"}= n.file_name
|
||||
.clearall.left.w20.ib.mb10
|
||||
%strong Language:
|
||||
.right.w75.ib.mb10.language
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
%a.gold{:href => "#{@music_session.legal_policy_url}", :target => "_blank"} View full legal details
|
||||
)
|
||||
|
||||
%br{clear:'all'}
|
||||
%br{clear:'all'}/
|
||||
|
||||
.landing-sidebar
|
||||
%br/
|
||||
|
|
@ -69,11 +69,11 @@
|
|||
%br/
|
||||
.left.w65.ib
|
||||
%strong RSVPs
|
||||
.right.w30.ib.f11.center Your latency
|
||||
.right.w30.ib.f11 Your latency
|
||||
- if @approved_rsvps.blank?
|
||||
None
|
||||
- @approved_rsvps.each_with_index do |rsvp, index|
|
||||
.clearall.left.w65.h20.ib.mb10.rsvp-details
|
||||
.clearall.left.w100.h20.ib.mb10.rsvp-details
|
||||
.avatar-tiny{'hoveraction' => "musician", 'user-id' => rsvp.id}
|
||||
- if rsvp.photo_url.nil?
|
||||
= image_tag 'shared/avatar_generic.png', :alt => ""
|
||||
|
|
@ -84,13 +84,35 @@
|
|||
.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
|
||||
|
||||
%br{:clear => "all"}/
|
||||
%br/
|
||||
.left.w65.ib.still-needed
|
||||
%strong Still Needed
|
||||
- if @open_slots.blank?
|
||||
.clearall.left.w65.h20.ib.mb10
|
||||
.clearall.left.w100.h20.ib.mb10
|
||||
All slots are taken
|
||||
- else
|
||||
- @open_slots.each do |slot|
|
||||
|
|
@ -141,4 +163,3 @@
|
|||
var ss = new window.JK.ShowSessionInfo(JK.app);
|
||||
ss.initialize("#{@music_session.id}");
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
%script{type: 'text/template', id: 'template-feed-recording'}
|
||||
.feed-entry.recording-entry{:'data-claimed-recording-id' => '{{data.candidate_claimed_recording.id}}' }
|
||||
.feed-entry.recording-entry{:'data-claimed-recording-id' => '{{data.candidate_claimed_recording.id}}', :'data-recording-id' => '{{data.feed_item.id}}' }
|
||||
/ avatar
|
||||
.avatar-small.ib
|
||||
%a{:hoveraction => "{{data.feed_item.helpers.artist_hoveraction}}", :profileaction => "{{data.feed_item.helpers.artist_hoveraction}}", :"{{data.feed_item.helpers.artist_datakey}}" => "{{data.feed_item.helpers.artist_id}}"}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
.left.ml20.w15
|
||||
.title{hoveraction: 'recording', :'recording-id' => '{{data.candidate_claimed_recording.id}}' }
|
||||
%a{:href => "/recordings/{{data.candidate_claimed_recording.id}}", :rel => "external"} RECORDING
|
||||
%a.edit-recording-dialog{href: "#"} (edit)
|
||||
.artist
|
||||
%a.artist{:hoveraction => '{{data.feed_item.helpers.artist_hoveraction}}', :profileaction => "{{data.feed_item.helpers.artist_hoveraction}}", :'{{data.feed_item.helpers.artist_datakey}}' => '{{data.feed_item.helpers.artist_id}}'}
|
||||
= '{{data.feed_item.helpers.artist_name}}'
|
||||
|
|
@ -16,7 +17,8 @@
|
|||
/ name and description
|
||||
.left.ml20.w30
|
||||
.name.dotdotdot
|
||||
= '{{data.feed_item.helpers.name}}'
|
||||
%span.name-text {{data.feed_item.helpers.name}}
|
||||
%span.is_private (private)
|
||||
.description.dotdotdot
|
||||
= '{{data.feed_item.helpers.description}}'
|
||||
/ timeline and controls
|
||||
|
|
@ -54,7 +56,7 @@
|
|||
0:00
|
||||
/ end recording play controls
|
||||
/ genre and social
|
||||
.left.small= '{{data.feed_item.helpers.genre}}'
|
||||
.left.small.genre= '{{data.feed_item.helpers.genre}}'
|
||||
.right.small.feed-details
|
||||
%a{title: 'Share', class: 'btn-share'}
|
||||
= image_tag 'content/icon_share.png', :height => "12", :width => "7"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
- provide(:page_name, 'welcome')
|
||||
|
||||
.welcome
|
||||
.landing-tag
|
||||
%h1 Play music together over the Internet as if in the same room
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class MaxMindManager < BaseManager
|
|||
#end
|
||||
|
||||
# returns an ordered array of Region objects (region, regionname, countrycode)
|
||||
Region.get_all(country).map { |r| r.region }
|
||||
Region.get_all(country).map { |r| { region: r.region, name: r.regionname } }
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ FactoryGirl.define do
|
|||
legal_terms true
|
||||
genre JamRuby::Genre.first
|
||||
band nil
|
||||
language 'en'
|
||||
language 'eng'
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ describe "Feed", :js => true, :type => :feature, :capybara_feature => true do
|
|||
find('div.comment-text', text: comment)
|
||||
find('#dialog-close-button', '[layout-id="comment-dialog"]').trigger(:click)
|
||||
|
||||
find('#btn-refresh-feed').trigger(:click)
|
||||
find('[layout-id="feed"] .btn-refresh-entries').trigger(:click)
|
||||
find('span.comments').should have_content('1')
|
||||
|
||||
# Likes
|
||||
|
|
@ -142,7 +142,7 @@ describe "Feed", :js => true, :type => :feature, :capybara_feature => true do
|
|||
find('div.comment-text', text: comment)
|
||||
find('#dialog-close-button', '[layout-id="comment-dialog"]').trigger(:click)
|
||||
|
||||
find('#btn-refresh-feed').trigger(:click)
|
||||
find('[layout-id="feed"] .btn-refresh-entries').trigger(:click)
|
||||
find('span.comments').should have_content('1')
|
||||
|
||||
# Likes
|
||||
|
|
@ -173,12 +173,6 @@ describe "Feed", :js => true, :type => :feature, :capybara_feature => true do
|
|||
find("#user-profile h2[id=profile-username]", text: user.name)
|
||||
end
|
||||
|
||||
# it "should render play widget" do
|
||||
|
||||
# it " and allow recording playback" do
|
||||
# end
|
||||
# end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,15 +1,25 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Reset Password", :js => true, :type => :feature, :capybara_feature => true do
|
||||
describe "Launch App", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:ams) { FactoryGirl.create(:active_music_session, creator: user) }
|
||||
|
||||
before(:each) do
|
||||
ActiveMusicSession.delete_all
|
||||
MusicSession.delete_all
|
||||
end
|
||||
|
||||
share_examples_for :launch_not_supported do |options|
|
||||
it "should indicate not supported" do
|
||||
sign_in_poltergeist user
|
||||
ams.touch if options[:need_session]
|
||||
visit options[:screen_path]
|
||||
if options[:actions]
|
||||
options[:actions].call(page)
|
||||
end
|
||||
should have_selector('h1', text: 'Application Notice')
|
||||
if options[:gear_modal] && options[:gear_modal] == true
|
||||
should have_selector('p', text: 'To configure your audio gear, you must use the JamKazam application. Please download and install the application if you have not done so already.')
|
||||
|
|
@ -25,7 +35,11 @@ describe "Reset Password", :js => true, :type => :feature, :capybara_feature =>
|
|||
share_examples_for :launch_supported do |options|
|
||||
it "should indicate supported" do
|
||||
sign_in_poltergeist user
|
||||
ams.touch if options[:need_session]
|
||||
visit options[:screen_path]
|
||||
if options[:actions]
|
||||
options[:actions].call(page)
|
||||
end
|
||||
should have_selector('h1', text: 'Application Notice')
|
||||
if options[:gear_modal] && options[:gear_modal] == true
|
||||
should have_selector('p', text: 'To configure your audio gear, you must use the JamKazam application.')
|
||||
|
|
@ -38,12 +52,15 @@ describe "Reset Password", :js => true, :type => :feature, :capybara_feature =>
|
|||
end
|
||||
|
||||
describe "unsupported" do
|
||||
|
||||
before do
|
||||
# emulate mac safari
|
||||
page.driver.headers = { 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/7.0.2 Safari/537.74.9'}
|
||||
end
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/createSession'
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/findSession'
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="quick-start"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="immediately"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="start-scheduled"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/findSession', actions: lambda { |page| page.find('.join-link').trigger(:click) }, need_session: true
|
||||
it_behaves_like :launch_not_supported, screen_path: '/client#/account/audio', gear_modal: true
|
||||
end
|
||||
|
||||
|
|
@ -52,8 +69,10 @@ describe "Reset Password", :js => true, :type => :feature, :capybara_feature =>
|
|||
# emulate chrome
|
||||
page.driver.headers = { 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36'}
|
||||
end
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/createSession'
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/findSession'
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="quick-start"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="immediately"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/createSession', actions: lambda { |page| page.find('li[create-type="start-scheduled"] ins').trigger(:click); page.find('.btn-next').trigger(:click) }
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/findSession', actions: lambda { |page| page.find('.join-link').trigger(:click) }, need_session: true
|
||||
it_behaves_like :launch_supported, screen_path: '/client#/account/audio', gear_modal: true
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,196 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Profile History", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
|
||||
before do
|
||||
MusicSession.delete_all
|
||||
Recording.delete_all
|
||||
sign_in_poltergeist user
|
||||
stub_const("APP_CONFIG", web_config)
|
||||
end
|
||||
|
||||
it "loads empty history" do
|
||||
nav_profile_history(user)
|
||||
|
||||
find('.no-feed-msg', text: 'This user has no history.')
|
||||
end
|
||||
|
||||
|
||||
# the same feedHelper instance is used to show any user's feed. so we need to make sure bouncing back and forth
|
||||
# between feeds is safe
|
||||
it "between users" do
|
||||
create_session(creator: user)
|
||||
formal_leave_by(user)
|
||||
user2 = FactoryGirl.create(:user)
|
||||
|
||||
nav_profile_history(user)
|
||||
find('.feed-entry.music-session-history-entry')
|
||||
visit Nav.feed # to get around bug where you can't cause a screen to update if it's the same screen, different params
|
||||
nav_profile_history(user2)
|
||||
should_not have_selector('.feed-entry.music-session-history-entry')
|
||||
find('.no-feed-msg', text: 'This user has no history.')
|
||||
end
|
||||
|
||||
describe "sessions" do
|
||||
|
||||
before(:each) do
|
||||
create_session(creator: user)
|
||||
formal_leave_by(user)
|
||||
end
|
||||
|
||||
it "should render stats" do
|
||||
nav_profile_history(user)
|
||||
|
||||
# initial stats
|
||||
find('span.plays').should have_content('0')
|
||||
find('span.comments').should have_content('0')
|
||||
find('span.likes').should have_content('0')
|
||||
|
||||
# Comments
|
||||
find('a.btn-comment').trigger(:click)
|
||||
comment = 'this sounds great'
|
||||
fill_in "txtComment", with: comment
|
||||
find('#btn-add-comment').trigger(:click)
|
||||
find('div.comment-text', text: comment)
|
||||
find('#dialog-close-button', '[layout-id="comment-dialog"]').trigger(:click)
|
||||
find('span.comments').should have_content('1')
|
||||
|
||||
# Likes
|
||||
find('a.btn-like').trigger(:click)
|
||||
find('span.likes').should have_content('1')
|
||||
end
|
||||
|
||||
it "should render details" do
|
||||
nav_profile_history(user)
|
||||
find('.feed-details a.details').trigger(:click)
|
||||
|
||||
# confirm user avatar exists
|
||||
find("a.avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"] img")
|
||||
|
||||
# confirm user name exists
|
||||
find("a.musician-name[user-id=\"#{user.id}\"][hoveraction=\"musician\"]", text: user.name)
|
||||
|
||||
# confirm instrument icons exist
|
||||
find("img[instrument-id=\"electric guitar\"]")
|
||||
|
||||
# confirm hover bubbles show
|
||||
find("a.avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"]").hover_intent
|
||||
|
||||
# confirm navigate to user profile page
|
||||
find(".avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"]").trigger(:click)
|
||||
find("#user-profile h2[id=profile-username]", text: user.name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "recordings" do
|
||||
|
||||
before(:each) do
|
||||
start_recording_with(user)
|
||||
stop_recording
|
||||
claim_recording("my recording", "my recording description")
|
||||
formal_leave_by(user)
|
||||
MusicSession.delete_all
|
||||
end
|
||||
|
||||
# it "should render avatar" do
|
||||
# it " and link to profile" do
|
||||
# end
|
||||
|
||||
# it " and render artist hover bubble" do
|
||||
# end
|
||||
# end
|
||||
|
||||
# it "should render description" do
|
||||
# it " and link to recording landing" do
|
||||
# end
|
||||
|
||||
# it " and render recording hover bubble" do
|
||||
# end
|
||||
# end
|
||||
|
||||
# it "should render artist name" do
|
||||
# it " and link to profile" do
|
||||
# end
|
||||
|
||||
# it " and render artist hover bubble"
|
||||
# end
|
||||
|
||||
it "should render stats" do
|
||||
nav_profile_history(user)
|
||||
|
||||
# initial stats
|
||||
find('span.plays').should have_content('0')
|
||||
find('span.comments').should have_content('0')
|
||||
find('span.likes').should have_content('0')
|
||||
|
||||
# ensure Share icon exists
|
||||
find('a.btn-share')
|
||||
|
||||
# Comments
|
||||
find('a.btn-comment').trigger(:click)
|
||||
comment = 'this sounds great'
|
||||
fill_in "txtComment", with: comment
|
||||
find('#btn-add-comment').trigger(:click)
|
||||
find('div.comment-text', text: comment)
|
||||
find('#dialog-close-button', '[layout-id="comment-dialog"]').trigger(:click)
|
||||
|
||||
find('span.comments').should have_content('1')
|
||||
|
||||
# Likes
|
||||
find('a.btn-like').trigger(:click)
|
||||
find('span.likes').should have_content('1')
|
||||
end
|
||||
|
||||
it "should render details" do
|
||||
nav_profile_history(user)
|
||||
|
||||
find('.feed-details a.details').trigger(:click)
|
||||
|
||||
# confirm user avatar exists
|
||||
find("a.avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"] img")
|
||||
|
||||
# confirm user name exists
|
||||
find("a.musician-name[user-id=\"#{user.id}\"][hoveraction=\"musician\"]", text: user.name)
|
||||
|
||||
# confirm instrument icons exist
|
||||
find("img[instrument-id=\"electric guitar\"]")
|
||||
|
||||
|
||||
# confirm hover bubbles show
|
||||
find("a.avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"]").hover_intent
|
||||
|
||||
# confirm navigate to user profile page
|
||||
find(".avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"]").trigger(:click)
|
||||
find("#user-profile h2[id=profile-username]", text: user.name)
|
||||
end
|
||||
|
||||
it "should allow edit and delete" do
|
||||
nav_profile_history(user)
|
||||
|
||||
# edit it's name
|
||||
find('.edit-recording-dialog').trigger(:click)
|
||||
find('h1', text: 'Edit Recording')
|
||||
fill_in 'name', with: 'some crazy name'
|
||||
find('.save-btn').trigger(:click)
|
||||
should_not have_selector('h1', text: 'Edit Recording')
|
||||
find('.name-text', text:'some crazy name')
|
||||
|
||||
# now delete it
|
||||
find('.edit-recording-dialog').trigger(:click)
|
||||
find('h1', text: 'Edit Recording')
|
||||
find('.delete-btn').trigger(:click)
|
||||
# confirm...
|
||||
find('.yes-btn').trigger(:click)
|
||||
should_not have_selector('h1', text: 'Edit Recording')
|
||||
should_not have_selector('.feed-entry.recording-entry')
|
||||
|
||||
ClaimedRecording.first.discarded.should == true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -85,7 +85,7 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
if options[:show_cta]
|
||||
find('#btn-action', :text => options[:button_text])
|
||||
else
|
||||
expect {find('#btn-action')}.to raise_error(Capybara::ElementNotFound)
|
||||
should_not have_selector('#btn-action')
|
||||
end
|
||||
|
||||
# session details
|
||||
|
|
@ -124,66 +124,56 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
@music_session.save
|
||||
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
fast_signin(@non_session_invitee, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_declined_user, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_approved_user, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
fast_signin(@session_creator, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
|
||||
it "should render only for session invitees for sessions with closed RSVPs before session starts" do
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
fast_signin(@non_session_invitee, @url)
|
||||
ensure_failure # NON-INVITEE SHOULD NOT BE ABLE TO VIEW FOR CLOSED RSVPs
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_declined_user, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_approved_user, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
fast_signin(@session_creator, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
|
||||
########### AFTER SESSION STARTS ###########
|
||||
|
|
@ -196,100 +186,85 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
@music_session.save!
|
||||
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
ensure_failure
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
fast_signin(@non_session_invitee, @url)
|
||||
ensure_failure
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_declined_user, @url)
|
||||
ensure_failure
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_approved_user, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
fast_signin(@session_creator, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
|
||||
# musician_access = true, approval_required = false
|
||||
it "should allow anyone to view for 'at will' option after session starts" do
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
fast_signin(@non_session_invitee, @url)
|
||||
ensure_failure # NON-INVITEE SHOULD NOT BE ABLE TO VIEW FOR CLOSED RSVPs
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_declined_user, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_approved_user, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
fast_signin(@session_creator, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
|
||||
# musician_access = true, approval_required = true
|
||||
it "should allow anyone to view for 'join by approval' option after session starts" do
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
fast_signin(@non_session_invitee, @url)
|
||||
ensure_failure # NON-INVITEE SHOULD NOT BE ABLE TO VIEW FOR CLOSED RSVPs
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_declined_user, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
fast_signin(@rsvp_approved_user, @url)
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
fast_signin(@session_creator, @url)
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
|
||||
it "should show no call to action button if user has not RSVPed and all slots are taken" do
|
||||
|
|
@ -299,10 +274,9 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
# approve slot 2 as well to make all slots taken for this session
|
||||
RsvpRequest.update({:id => @rsvp1.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs2.id, :accept => true}]}, @session_creator)
|
||||
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
fast_signin(@session_invitee, @url)
|
||||
expect {find('#btn-action')}.to raise_error(Capybara::ElementNotFound)
|
||||
sign_out_poltergeist
|
||||
fast_signout
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ describe MaxMindManager do
|
|||
it "looks up regions successfully" do
|
||||
regions = MaxMindManager.regions("US")
|
||||
regions.length.should == 4
|
||||
regions.first.should == "AB"
|
||||
regions.last.should == "DE"
|
||||
regions.first[:region].should == "AB"
|
||||
regions.last[:region].should == "DE"
|
||||
end
|
||||
|
||||
it "looks up cities successfully" do
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ describe MusicSessionManager do
|
|||
|
||||
it "updates a session properly" do
|
||||
active_music_session = @music_session_manager.create(music_session, @user, @connection.client_id, "description", true, false, true, true, @band, [@genre], @tracks, true, 10)
|
||||
@music_session_manager.update(music_session, "updated description", nil, nil, nil, nil, nil)
|
||||
@music_session_manager.update(music_session, nil, "updated description", nil, nil, nil, nil, nil, nil)
|
||||
music_session.reload
|
||||
music_session.description.should == "updated description"
|
||||
# Verify that this didnt change
|
||||
music_session.approval_required.should == false
|
||||
genre2 = FactoryGirl.create(:genre)
|
||||
@music_session_manager.update(music_session, nil, [@genre, genre2], nil, nil, nil, nil)
|
||||
@music_session_manager.update(music_session, nil, nil, @genre, nil, nil, nil, nil, nil)
|
||||
music_session.reload
|
||||
music_session.description.should == "updated description"
|
||||
music_session.genre.should == @genre
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ describe "Active Music Session API ", :type => :api do
|
|||
end
|
||||
|
||||
it "updated genres" do
|
||||
put "/api/sessions/#{music_session.id}.json", {:genres => ["jazz"]}.to_json, "CONTENT_TYPE" => 'application/json'
|
||||
put "/api/sessions/#{music_session.id}.json", {:genre => "jazz"}.to_json, "CONTENT_TYPE" => 'application/json'
|
||||
last_response.status.should eql(204)
|
||||
get "/api/sessions/#{music_session.id}.json", "CONTENT_TYPE" => 'application/json'
|
||||
updated_session = JSON.parse(last_response.body)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,35 @@ def web_config
|
|||
def external_root_url
|
||||
"#{external_protocol}#{external_hostname}#{(external_port == 80 || external_port == 443) ? '' : ':' + external_port.to_s}"
|
||||
end
|
||||
|
||||
|
||||
def aws_bucket
|
||||
JAMKAZAM_TESTING_BUCKET
|
||||
end
|
||||
|
||||
def aws_access_key_id
|
||||
'AKIAJESQY24TOT542UHQ'
|
||||
end
|
||||
|
||||
def aws_secret_access_key
|
||||
'h0V0ffr3JOp/UtgaGrRfAk25KHNiO9gm8Pj9m6v3'
|
||||
end
|
||||
|
||||
def aws_region
|
||||
'us-east-1'
|
||||
end
|
||||
|
||||
def aws_bucket_public
|
||||
'jamkazam-testing-public'
|
||||
end
|
||||
|
||||
def aws_cache
|
||||
'315576000'
|
||||
end
|
||||
|
||||
def max_audio_downloads
|
||||
10
|
||||
end
|
||||
end
|
||||
klass.new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -110,6 +110,17 @@ def sign_in_poltergeist(user, options = {})
|
|||
page.should have_no_selector('.no-websocket-connection') if validate
|
||||
end
|
||||
|
||||
# skip the typical login form, which redirects to /client (sloooow). Just sets the cookie, and puts you where you want to be
|
||||
def fast_signin(user, url)
|
||||
page.driver.set_cookie(:remember_token, user.remember_token)
|
||||
visit url
|
||||
end
|
||||
|
||||
#skip the 'hunt' for Sign Out, and redirect after. Just empty cookie, and go to '/'
|
||||
def fast_signout
|
||||
page.driver.set_cookie(:remember_token, '')
|
||||
visit '/'
|
||||
end
|
||||
|
||||
def sign_out()
|
||||
if Capybara.javascript_driver == :poltergeist
|
||||
|
|
@ -570,3 +581,8 @@ def garbage length
|
|||
length.times { output << special_characters.sample }
|
||||
output.slice(0, length)
|
||||
end
|
||||
|
||||
def nav_profile_history(user)
|
||||
visit Nav.profile(user)
|
||||
find('#profile-history-link').trigger(:click)
|
||||
end
|
||||
Loading…
Reference in New Issue