* merged
This commit is contained in:
parent
6f463b7b6c
commit
61f0bd2aa0
|
|
@ -70,6 +70,14 @@ module JamRuby
|
||||||
self.music_sessions.size
|
self.music_sessions.size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def latitude
|
||||||
|
lat
|
||||||
|
end
|
||||||
|
|
||||||
|
def longitude
|
||||||
|
lng
|
||||||
|
end
|
||||||
|
|
||||||
def recent_history
|
def recent_history
|
||||||
recordings = Recording
|
recordings = Recording
|
||||||
.joins(:claimed_recordings)
|
.joins(:claimed_recordings)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,19 @@ module JamRuby
|
||||||
{city: city, state: state, country: country, addr: addr, locidispid: (locid.nil? || ispid.nil?) ? nil : Score.compute_locidispid(locid, ispid) }
|
{city: city, state: state, country: country, addr: addr, locidispid: (locid.nil? || ispid.nil?) ? nil : Score.compute_locidispid(locid, ispid) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# returns a display- friendly bit of info about this location
|
||||||
|
def info
|
||||||
|
country_model = Country.where(countrycode: countrycode).first
|
||||||
|
region_model = Region.where(region: region, countrycode: countrycode).first
|
||||||
|
{
|
||||||
|
countrycode: countrycode,
|
||||||
|
country: country_model ? country_model.countryname : nil,
|
||||||
|
regioncode: region,
|
||||||
|
region: region_model ? region_model.regionname : nil,
|
||||||
|
city: city
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def self.createx(locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode)
|
def self.createx(locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode)
|
||||||
c = connection.raw_connection
|
c = connection.raw_connection
|
||||||
c.exec_params("insert into #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode, geog) values($1, $2, $3, $4, $5, $6, $7, $8, $9, ST_SetSRID(ST_MakePoint($7, $6), 4326)::geography)",
|
c.exec_params("insert into #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode, geog) values($1, $2, $3, $4, $5, $6, $7, $8, $9, ST_SetSRID(ST_MakePoint($7, $6), 4326)::geography)",
|
||||||
|
|
@ -82,8 +95,8 @@ module JamRuby
|
||||||
# it isn't reasonable for both to be 0...
|
# it isn't reasonable for both to be 0...
|
||||||
latlng = [geo.latitude, geo.longitude]
|
latlng = [geo.latitude, geo.longitude]
|
||||||
end
|
end
|
||||||
elsif current_user and current_user.locidispid and current_user.locidispid != 0
|
elsif current_user and current_user.last_jam_locidispid and current_user.last_jam_locidispid != 0
|
||||||
location = GeoIpLocations.find_by_locid(current_user.locidispid/1000000)
|
location = GeoIpLocations.find_by_locid(current_user.last_jam_locidispid/1000000)
|
||||||
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
|
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
|
||||||
# it isn't reasonable for both to be 0...
|
# it isn't reasonable for both to be 0...
|
||||||
latlng = [location.latitude, location.longitude]
|
latlng = [location.latitude, location.longitude]
|
||||||
|
|
@ -99,7 +112,7 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
if latlng
|
if latlng
|
||||||
relation = relation.where(['latitude IS NOT NULL AND longitude IS NOT NULL']).within(distance, origin: latlng)
|
relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']).within(distance, origin: latlng)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
relation
|
relation
|
||||||
|
|
|
||||||
|
|
@ -99,12 +99,13 @@ module JamRuby
|
||||||
M_ORDER_PLAYS = ['Most Plays', :plays]
|
M_ORDER_PLAYS = ['Most Plays', :plays]
|
||||||
M_ORDER_PLAYING = ['Playing Now', :playing]
|
M_ORDER_PLAYING = ['Playing Now', :playing]
|
||||||
M_ORDER_LATENCY = ['Latency To Me', :latency]
|
M_ORDER_LATENCY = ['Latency To Me', :latency]
|
||||||
M_ORDERINGS = [M_ORDER_LATENCY, M_ORDER_FOLLOWS, M_ORDER_PLAYS]
|
M_ORDER_DISTANCE = ['Distance To Me', :distance]
|
||||||
|
M_ORDERINGS = [M_ORDER_LATENCY, M_ORDER_DISTANCE, M_ORDER_FOLLOWS, M_ORDER_PLAYS]
|
||||||
ORDERINGS = B_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING]
|
ORDERINGS = B_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING]
|
||||||
M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] }
|
M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] }
|
||||||
B_ORDERING_KEYS = B_ORDERINGS.collect { |oo| oo[1] }
|
B_ORDERING_KEYS = B_ORDERINGS.collect { |oo| oo[1] }
|
||||||
|
|
||||||
DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]]
|
DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [[25.to_s, 25], [50.to_s, 50], [100.to_s, 100], [250.to_s, 250], [500.to_s, 500], [1000.to_s, 1000] ]
|
||||||
|
|
||||||
# the values for score ranges are raw roundtrip scores. david often talks of one way scores (<= 20 is good), but
|
# the values for score ranges are raw roundtrip scores. david often talks of one way scores (<= 20 is good), but
|
||||||
# the client reports scores as roundtrip and the server uses those values throughout
|
# the client reports scores as roundtrip and the server uses those values throughout
|
||||||
|
|
@ -117,6 +118,7 @@ module JamRuby
|
||||||
ANY_SCORE = ''
|
ANY_SCORE = ''
|
||||||
M_SCORE_OPTS = [['Any', ANY_SCORE], ['Good', GOOD_SCORE], ['Moderate', MODERATE_SCORE], ['Poor', POOR_SCORE], ['Unacceptable', UNACCEPTABLE_SCORE]]
|
M_SCORE_OPTS = [['Any', ANY_SCORE], ['Good', GOOD_SCORE], ['Moderate', MODERATE_SCORE], ['Poor', POOR_SCORE], ['Unacceptable', UNACCEPTABLE_SCORE]]
|
||||||
M_SCORE_DEFAULT = ANY_SCORE
|
M_SCORE_DEFAULT = ANY_SCORE
|
||||||
|
M_DISTANCE_DEFAULT = 500
|
||||||
|
|
||||||
F_SORT_RECENT = ['Most Recent', :date]
|
F_SORT_RECENT = ['Most Recent', :date]
|
||||||
F_SORT_OLDEST = ['Most Liked', :likes]
|
F_SORT_OLDEST = ['Most Liked', :likes]
|
||||||
|
|
@ -148,10 +150,7 @@ module JamRuby
|
||||||
# distance - defunct!
|
# distance - defunct!
|
||||||
# city - defunct!
|
# city - defunct!
|
||||||
# remote_ip - defunct!
|
# remote_ip - defunct!
|
||||||
def self.musician_filter(params={}, user=nil, conn=nil)
|
def self.musician_filter(params={}, user=nil)
|
||||||
# puts "================ params #{params.inspect}"
|
|
||||||
# puts "================ user #{user.inspect}"
|
|
||||||
# puts "================ conn #{conn.inspect}"
|
|
||||||
|
|
||||||
rel = User.musicians # not musicians_geocoded on purpose; we allow 'unknowns' to surface in the search page
|
rel = User.musicians # not musicians_geocoded on purpose; we allow 'unknowns' to surface in the search page
|
||||||
rel = rel.select('users.*')
|
rel = rel.select('users.*')
|
||||||
|
|
@ -173,11 +172,23 @@ module JamRuby
|
||||||
score_limit = l
|
score_limit = l
|
||||||
end
|
end
|
||||||
|
|
||||||
# puts "================ score_limit #{score_limit}"
|
locidispid = user.nil? ? 0 : (user.last_jam_locidispid || 0)
|
||||||
|
|
||||||
locidispid = ((conn and conn.client_type == 'client') ? conn.locidispid : ((user and user.musician) ? user.last_jam_locidispid : nil))
|
# user can override their location with these 3 values
|
||||||
|
country = params[:country]
|
||||||
|
region = params[:region]
|
||||||
|
city = params[:city]
|
||||||
|
|
||||||
# puts "================ locidispid #{locidispid}"
|
my_locid = nil # this is used for distance searches only
|
||||||
|
|
||||||
|
if country && region && city
|
||||||
|
geoiplocation = GeoIpLocations.where(countrycode: country, region: region, city: city).first
|
||||||
|
my_locid = geoiplocation.locid
|
||||||
|
end
|
||||||
|
|
||||||
|
unless my_locid
|
||||||
|
my_locid = locidispid/1000000 # if the user didn't specify a location to search on, user their account locidispid
|
||||||
|
end
|
||||||
|
|
||||||
unless locidispid.nil?
|
unless locidispid.nil?
|
||||||
# score_join of left allows for null scores, whereas score_join of inner requires a score however good or bad
|
# score_join of left allows for null scores, whereas score_join of inner requires a score however good or bad
|
||||||
|
|
@ -229,10 +240,18 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
ordering = self.order_param(params)
|
ordering = self.order_param(params)
|
||||||
# puts "================ ordering #{ordering}"
|
|
||||||
case ordering
|
case ordering
|
||||||
when :latency
|
when :latency
|
||||||
# nothing to do. the sort added below 'current_scores.score ASC NULLS LAST' handles this
|
# nothing to do. the sort added below 'current_scores.score ASC NULLS LAST' handles this
|
||||||
|
when :distance
|
||||||
|
# convert miles to meters for PostGIS functions
|
||||||
|
miles = params[:distance].blank? ? 500 : params[:distance].to_i
|
||||||
|
meters = miles * 1609.34
|
||||||
|
rel = rel.joins("INNER JOIN geoiplocations AS my_geo ON #{my_locid} = my_geo.locid")
|
||||||
|
rel = rel.joins("INNER JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid")
|
||||||
|
rel = rel.where("users.last_jam_locidispid/1000000 IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = #{my_locid}), #{meters}))")
|
||||||
|
rel = rel.group("my_geo.geog, other_geo.geog")
|
||||||
|
rel = rel.order('st_distance(my_geo.geog, other_geo.geog)')
|
||||||
when :plays # FIXME: double counting?
|
when :plays # FIXME: double counting?
|
||||||
# sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
# sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
||||||
rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count')
|
rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count')
|
||||||
|
|
@ -254,17 +273,10 @@ module JamRuby
|
||||||
|
|
||||||
rel = rel.order('users.created_at DESC')
|
rel = rel.order('users.created_at DESC')
|
||||||
|
|
||||||
# rel = rel.select(sel_str)
|
|
||||||
rel, page = self.relation_pagination(rel, params)
|
rel, page = self.relation_pagination(rel, params)
|
||||||
rel = rel.includes([:instruments, :followings, :friends])
|
rel = rel.includes([:instruments, :followings, :friends])
|
||||||
|
|
||||||
# puts "======================== sql #{rel.to_sql}"
|
|
||||||
objs = rel.all
|
objs = rel.all
|
||||||
# puts "======================== objs #{objs.inspect}"
|
|
||||||
# if objs.length > 0
|
|
||||||
# puts "======================== attributes #{objs[0].attributes}"
|
|
||||||
# puts "======================== score #{objs[0].score}"
|
|
||||||
# end
|
|
||||||
|
|
||||||
srch = Search.new
|
srch = Search.new
|
||||||
srch.search_type = :musicians_filter
|
srch.search_type = :musicians_filter
|
||||||
|
|
|
||||||
|
|
@ -1003,6 +1003,11 @@ module JamRuby
|
||||||
self.save
|
self.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# gets the GeoIpLocation for the user's last_jam_locidispid (where are they REALLY, vs profile info)
|
||||||
|
def geoiplocation
|
||||||
|
GeoIpLocations.find_by_locid(last_jam_locidispid / 1000000) if last_jam_locidispid
|
||||||
|
end
|
||||||
|
|
||||||
def update_last_jam(remote_ip, reason)
|
def update_last_jam(remote_ip, reason)
|
||||||
location = GeoIpLocations.lookup(remote_ip)
|
location = GeoIpLocations.lookup(remote_ip)
|
||||||
self.last_jam_addr = location[:addr]
|
self.last_jam_addr = location[:addr]
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,50 @@ FactoryGirl.define do
|
||||||
admin true
|
admin true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :austin_user do
|
||||||
|
first_name 'Austin'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Austin'
|
||||||
|
last_jam_locidispid { austin_geoip[:locidispid] }
|
||||||
|
last_jam_addr { austin_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :dallas_user do
|
||||||
|
first_name 'Dallas'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Dallas'
|
||||||
|
last_jam_locidispid { dallas_geoip[:locidispid] }
|
||||||
|
last_jam_addr { dallas_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :houston_user do
|
||||||
|
first_name 'Houston'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Houston'
|
||||||
|
last_jam_locidispid { houston_geoip[:locidispid] }
|
||||||
|
last_jam_addr { houston_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :miami_user do
|
||||||
|
first_name 'Miami'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'FL'
|
||||||
|
city 'Miami'
|
||||||
|
last_jam_locidispid { miami_geoip[:locidispid] }
|
||||||
|
last_jam_addr { miami_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :seattle_user do
|
||||||
|
first_name 'Seattle'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'WA'
|
||||||
|
city 'Seattle'
|
||||||
|
last_jam_locidispid { seattle_geoip[:locidispid] }
|
||||||
|
last_jam_addr { seattle_ip }
|
||||||
|
end
|
||||||
factory :single_user_session do
|
factory :single_user_session do
|
||||||
after(:create) do |user, evaluator|
|
after(:create) do |user, evaluator|
|
||||||
active_music_session = FactoryGirl.create(:active_music_session, :creator => user)
|
active_music_session = FactoryGirl.create(:active_music_session, :creator => user)
|
||||||
|
|
|
||||||
|
|
@ -2,356 +2,423 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe 'Musician search' do
|
describe 'Musician search' do
|
||||||
|
|
||||||
before(:each) do
|
# need a data set with actual distances
|
||||||
# @geocode1 = FactoryGirl.create(:geocoder)
|
describe "test set A" do
|
||||||
# @geocode2 = FactoryGirl.create(:geocoder)
|
|
||||||
t = Time.now - 10.minute
|
|
||||||
|
|
||||||
@user1 = FactoryGirl.create(:user, created_at: t+1.minute, last_jam_locidispid: 1)
|
before(:each) do
|
||||||
@user2 = FactoryGirl.create(:user, created_at: t+2.minute, last_jam_locidispid: 2)
|
create_phony_database
|
||||||
@user3 = FactoryGirl.create(:user, created_at: t+3.minute, last_jam_locidispid: 3)
|
|
||||||
@user4 = FactoryGirl.create(:user, created_at: t+4.minute, last_jam_locidispid: 4)
|
|
||||||
@user5 = FactoryGirl.create(:user, created_at: t+5.minute, last_jam_locidispid: 5)
|
|
||||||
@user6 = FactoryGirl.create(:user, created_at: t+6.minute) # not geocoded
|
|
||||||
@user7 = FactoryGirl.create(:user, created_at: t+7.minute, musician: false) # not musician
|
|
||||||
|
|
||||||
@musicians = []
|
|
||||||
@musicians << @user1
|
|
||||||
@musicians << @user2
|
|
||||||
@musicians << @user3
|
|
||||||
@musicians << @user4
|
|
||||||
@musicians << @user5
|
|
||||||
@musicians << @user6
|
|
||||||
|
|
||||||
@geomusicians = []
|
|
||||||
@geomusicians << @user1
|
|
||||||
@geomusicians << @user2
|
|
||||||
@geomusicians << @user3
|
|
||||||
@geomusicians << @user4
|
|
||||||
@geomusicians << @user5
|
|
||||||
|
|
||||||
# from these scores:
|
|
||||||
# user1 has scores other users in user1 location, and with user2, user3, user4
|
|
||||||
# user2 has scores with users in user3 and user4 location
|
|
||||||
# Score.delete_all
|
|
||||||
Score.createx(1, 'a', 1, 1, 'a', 1, 10)
|
|
||||||
Score.createx(1, 'a', 1, 2, 'b', 2, 20)
|
|
||||||
Score.createx(1, 'a', 1, 3, 'c', 3, 30)
|
|
||||||
Score.createx(1, 'a', 1, 4, 'd', 4, 40)
|
|
||||||
Score.createx(2, 'b', 2, 3, 'c', 3, 15)
|
|
||||||
Score.createx(2, 'b', 2, 4, 'd', 4, 70)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'default filter settings' do
|
|
||||||
|
|
||||||
it "finds all musicians" do
|
|
||||||
# expects all the musicians (geocoded)
|
|
||||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE})
|
|
||||||
results.search_type.should == :musicians_filter
|
|
||||||
results.results.count.should == @musicians.length
|
|
||||||
results.results.should eq @musicians.reverse
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "finds all musicians page 1" do
|
let!(:austin_user) { FactoryGirl.create(:austin_user) }
|
||||||
# expects all the musicians
|
let!(:dallas_user) { FactoryGirl.create(:dallas_user) }
|
||||||
results = Search.musician_filter({page: 1, score_limit: Search::TEST_SCORE})
|
let!(:miami_user) { FactoryGirl.create(:miami_user) }
|
||||||
results.search_type.should == :musicians_filter
|
let!(:seattle_user) { FactoryGirl.create(:seattle_user) }
|
||||||
results.results.count.should == @musicians.length
|
|
||||||
results.results.should eq @musicians.reverse
|
|
||||||
end
|
|
||||||
|
|
||||||
it "finds all musicians page 2" do
|
describe "search on distance" do
|
||||||
# expects no musicians (all fit on page 1)
|
|
||||||
results = Search.musician_filter({page: 2, score_limit: Search::TEST_SCORE})
|
|
||||||
results.search_type.should == :musicians_filter
|
|
||||||
results.results.count.should == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
it "finds all musicians page 1 per_page 3" do
|
it "finds self when very local search" do
|
||||||
# expects three of the musicians
|
Search.musician_filter({distance: 1, orderby: 'distance'}, austin_user).results.should == [austin_user] # just to see that distance is 0 to self
|
||||||
results = Search.musician_filter({per_page: 3, score_limit: Search::TEST_SCORE})
|
Search.musician_filter({distance: 1, orderby: 'distance'}, dallas_user).results.should == [dallas_user] # just to see that distance is 0 to self
|
||||||
results.search_type.should == :musicians_filter
|
Search.musician_filter({distance: 1, orderby: 'distance'}, miami_user).results.should == [miami_user] # just to see that distance is 0 to self
|
||||||
results.results.count.should == 3
|
Search.musician_filter({distance: 1, orderby: 'distance'}, seattle_user).results.should == [seattle_user] # just to see that distance is 0 to self
|
||||||
results.results.should eq @musicians.reverse.slice(0, 3)
|
end
|
||||||
end
|
|
||||||
|
it "finds dallas when in range of austin" do
|
||||||
it "finds all musicians page 2 per_page 3" do
|
expected_results = [austin_user, dallas_user]
|
||||||
# expects two of the musicians
|
|
||||||
results = Search.musician_filter({page: 2, per_page: 3, score_limit: Search::TEST_SCORE})
|
Search.musician_filter({distance: 500, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||||
results.search_type.should == :musicians_filter
|
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||||
results.results.count.should == 3
|
end
|
||||||
results.results.should eq @musicians.reverse.slice(3, 3)
|
|
||||||
end
|
it "finds miami when in range of austin" do
|
||||||
|
expected_results = [austin_user, dallas_user, miami_user]
|
||||||
it "finds all musicians page 3 per_page 3" do
|
|
||||||
# expects two of the musicians
|
Search.musician_filter({distance: 1500, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||||
results = Search.musician_filter({page: 3, per_page: 3, score_limit: Search::TEST_SCORE})
|
Search.musician_filter({distance: 300, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user]
|
||||||
results.search_type.should == :musicians_filter
|
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||||
results.results.count.should == 0
|
end
|
||||||
end
|
|
||||||
|
it "finds seattle when in range of austin" do
|
||||||
it "sorts musicians by followers" do
|
expected_results = [austin_user, dallas_user, miami_user, seattle_user]
|
||||||
# establish sorting order
|
|
||||||
|
Search.musician_filter({distance: 2000, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||||
# @user4
|
Search.musician_filter({distance: 1500, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user, miami_user]
|
||||||
f1 = Follow.new
|
Search.musician_filter({distance: 300, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user]
|
||||||
f1.user = @user2
|
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||||
f1.followable = @user4
|
end
|
||||||
f1.save
|
|
||||||
|
it "finds austin & dallas by user-specified location when in range" do
|
||||||
f2 = Follow.new
|
Search.musician_filter({distance: 500, orderby: 'distance', city: 'Austin', region: 'TX', country: 'US'}, austin_user).results.should == [austin_user, dallas_user]
|
||||||
f2.user = @user3
|
end
|
||||||
f2.followable = @user4
|
|
||||||
f2.save
|
it "finds dallas & austin by user-specified location when in range" do
|
||||||
|
Search.musician_filter({distance: 500, orderby: 'distance', city: 'Dallas', region: 'TX', country: 'US'}, austin_user).results.should == [dallas_user, austin_user]
|
||||||
f3 = Follow.new
|
end
|
||||||
f3.user = @user4
|
|
||||||
f3.followable = @user4
|
it "finds miami user-specified location when in range" do
|
||||||
f3.save
|
Search.musician_filter({distance: 300, orderby: 'distance', city: 'Tampa', region: 'FL', country: 'US'}, austin_user).results.should == [miami_user]
|
||||||
|
end
|
||||||
# @user3
|
|
||||||
f4 = Follow.new
|
it "finds all users with user-specified location when in range" do
|
||||||
f4.user = @user3
|
Search.musician_filter({distance: 2500, orderby: 'distance', city: 'Tampa', region: 'FL', country: 'US'}, austin_user).results.should == [miami_user, dallas_user, austin_user, seattle_user]
|
||||||
f4.followable = @user3
|
|
||||||
f4.save
|
|
||||||
|
|
||||||
f5 = Follow.new
|
|
||||||
f5.user = @user4
|
|
||||||
f5.followable = @user3
|
|
||||||
f5.save
|
|
||||||
|
|
||||||
# @user2
|
|
||||||
f6 = Follow.new
|
|
||||||
f6.user = @user1
|
|
||||||
f6.followable = @user2
|
|
||||||
f6.save
|
|
||||||
|
|
||||||
# @user4.followers.concat([@user2, @user3, @user4])
|
|
||||||
# @user3.followers.concat([@user3, @user4])
|
|
||||||
# @user2.followers.concat([@user1])
|
|
||||||
expect(@user4.followers.count).to be 3
|
|
||||||
expect(Follow.count).to be 6
|
|
||||||
|
|
||||||
# refresh the order to ensure it works right
|
|
||||||
f1 = Follow.new
|
|
||||||
f1.user = @user3
|
|
||||||
f1.followable = @user2
|
|
||||||
f1.save
|
|
||||||
|
|
||||||
f2 = Follow.new
|
|
||||||
f2.user = @user4
|
|
||||||
f2.followable = @user2
|
|
||||||
f2.save
|
|
||||||
|
|
||||||
f3 = Follow.new
|
|
||||||
f3.user = @user2
|
|
||||||
f3.followable = @user2
|
|
||||||
f3.save
|
|
||||||
|
|
||||||
# @user2.followers.concat([@user3, @user4, @user2])
|
|
||||||
results = Search.musician_filter({ :per_page => @musicians.size, score_limit: Search::TEST_SCORE, orderby: 'followed'}, @user3)
|
|
||||||
expect(results.results[0].id).to eq(@user2.id)
|
|
||||||
|
|
||||||
# check the follower count for given entry
|
|
||||||
expect(results.results[0].search_follow_count.to_i).not_to eq(0)
|
|
||||||
# check the follow relationship between current_user and result
|
|
||||||
expect(results.is_follower?(@user2)).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'paginates properly' do
|
|
||||||
# make sure pagination works right
|
|
||||||
params = { :per_page => 2, :page => 1 , score_limit: Search::TEST_SCORE}
|
|
||||||
results = Search.musician_filter(params)
|
|
||||||
expect(results.results.count).to be 2
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def make_recording(usr)
|
|
||||||
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
|
||||||
instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
|
||||||
track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument)
|
|
||||||
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
|
||||||
# music_session.connections << connection
|
|
||||||
# music_session.save
|
|
||||||
connection.join_the_session(music_session, true, nil, usr, 10)
|
|
||||||
recording = Recording.start(music_session, usr)
|
|
||||||
recording.stop
|
|
||||||
recording.reload
|
|
||||||
genre = FactoryGirl.create(:genre)
|
|
||||||
recording.claim(usr, "name", "description", genre, true)
|
|
||||||
recording.reload
|
|
||||||
recording
|
|
||||||
end
|
|
||||||
|
|
||||||
def make_session(usr)
|
|
||||||
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
|
||||||
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
|
||||||
# music_session.connections << connection
|
|
||||||
# music_session.save
|
|
||||||
connection.join_the_session(music_session, true, nil, usr, 10)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'musician stat counters' do
|
|
||||||
|
|
||||||
it "displays musicians top followings" do
|
|
||||||
f1 = Follow.new
|
|
||||||
f1.user = @user4
|
|
||||||
f1.followable = @user4
|
|
||||||
f1.save
|
|
||||||
|
|
||||||
f2 = Follow.new
|
|
||||||
f2.user = @user4
|
|
||||||
f2.followable = @user3
|
|
||||||
f2.save
|
|
||||||
|
|
||||||
f3 = Follow.new
|
|
||||||
f3.user = @user4
|
|
||||||
f3.followable = @user2
|
|
||||||
f3.save
|
|
||||||
|
|
||||||
# @user4.followers.concat([@user4])
|
|
||||||
# @user3.followers.concat([@user4])
|
|
||||||
# @user2.followers.concat([@user4])
|
|
||||||
expect(@user4.top_followings.count).to eq 3
|
|
||||||
expect(@user4.top_followings.map(&:id)).to match_array((@musicians - [@user1, @user5, @user6]).map(&:id))
|
|
||||||
end
|
|
||||||
|
|
||||||
it "friends stat shows friend count" do
|
|
||||||
# create friendship record
|
|
||||||
Friendship.save(@user1.id, @user2.id)
|
|
||||||
# search on user2
|
|
||||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user2)
|
|
||||||
friend = results.results.detect { |mm| mm.id == @user1.id }
|
|
||||||
expect(friend).to_not be_nil
|
|
||||||
expect(results.friend_count(friend)).to be 1
|
|
||||||
@user1.reload
|
|
||||||
expect(friend.friends?(@user2)).to be true
|
|
||||||
expect(results.is_friend?(@user1)).to be true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "recording stat shows recording count" do
|
|
||||||
Recording.delete_all
|
|
||||||
|
|
||||||
recording = make_recording(@user1)
|
|
||||||
expect(recording.users.length).to be 1
|
|
||||||
expect(recording.users.first).to eq(@user1)
|
|
||||||
@user1.reload
|
|
||||||
expect(@user1.recordings.length).to be 1
|
|
||||||
expect(@user1.recordings.first).to eq(recording)
|
|
||||||
expect(recording.claimed_recordings.length).to be 1
|
|
||||||
expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil
|
|
||||||
|
|
||||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE},@user1)
|
|
||||||
# puts "====================== results #{results.inspect}"
|
|
||||||
uu = results.results.detect { |mm| mm.id == @user1.id }
|
|
||||||
expect(uu).to_not be_nil
|
|
||||||
|
|
||||||
expect(results.record_count(uu)).to be 1
|
|
||||||
expect(results.session_count(uu)).to be 1
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'musician sorting' do
|
|
||||||
|
|
||||||
it "by plays" do
|
|
||||||
Recording.delete_all
|
|
||||||
|
|
||||||
make_recording(@user1)
|
|
||||||
# order results by num recordings
|
|
||||||
results = Search.musician_filter({ orderby: 'plays', score_limit: Search::TEST_SCORE}, @user2)
|
|
||||||
# puts "========= results #{results.inspect}"
|
|
||||||
expect(results.results.length).to eq(2)
|
|
||||||
expect(results.results[0].id).to eq(@user1.id)
|
|
||||||
expect(results.results[1].id).to eq(@user3.id)
|
|
||||||
|
|
||||||
# add more data and make sure order still correct
|
|
||||||
make_recording(@user3)
|
|
||||||
make_recording(@user3)
|
|
||||||
results = Search.musician_filter({ :orderby => 'plays', score_limit: Search::TEST_SCORE }, @user2)
|
|
||||||
expect(results.results.length).to eq(2)
|
|
||||||
expect(results.results[0].id).to eq(@user3.id)
|
|
||||||
expect(results.results[1].id).to eq(@user1.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "by now playing" do
|
|
||||||
pending "these tests worked, so leaving them in, but we don't currently have 'Now Playing' in the find musicians screen"
|
|
||||||
# should get 1 result with 1 active session
|
|
||||||
make_session(@user1)
|
|
||||||
results = Search.musician_filter({ :orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
|
||||||
expect(results.results.count).to be 1
|
|
||||||
expect(results.results.first.id).to eq(@user1.id)
|
|
||||||
|
|
||||||
# should get 2 results with 2 active sessions
|
|
||||||
# sort order should be created_at DESC
|
|
||||||
make_session(@user3)
|
|
||||||
results = Search.musician_filter({ :orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
|
||||||
expect(results.results.count).to be 2
|
|
||||||
expect(results.results[0].id).to eq(@user3.id)
|
|
||||||
expect(results.results[1].id).to eq(@user1.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'filter settings' do
|
|
||||||
it "searches musicisns for an instrument" do
|
|
||||||
minst = FactoryGirl.create(:musician_instrument, {
|
|
||||||
:user => @user1,
|
|
||||||
:instrument => Instrument.find('tuba') })
|
|
||||||
@user1.musician_instruments << minst
|
|
||||||
@user1.reload
|
|
||||||
ii = @user1.instruments.detect { |inst| inst.id == 'tuba' }
|
|
||||||
expect(ii).to_not be_nil
|
|
||||||
results = Search.musician_filter({ :instrument => ii.id, score_limit: Search::TEST_SCORE })
|
|
||||||
results.results.each do |rr|
|
|
||||||
expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id)
|
|
||||||
end
|
end
|
||||||
expect(results.results.count).to be 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'new users' do
|
describe "test set B" do
|
||||||
|
|
||||||
it "find three for user1" do
|
before(:each) do
|
||||||
# user2..4 are scored against user1
|
# @geocode1 = FactoryGirl.create(:geocoder)
|
||||||
ms = Search.new_musicians(@user1, Time.now - 1.week)
|
# @geocode2 = FactoryGirl.create(:geocoder)
|
||||||
ms.should_not be_nil
|
t = Time.now - 10.minute
|
||||||
ms.length.should == 3
|
|
||||||
ms.should eq [@user2, @user3, @user4]
|
@user1 = FactoryGirl.create(:user, created_at: t+1.minute, last_jam_locidispid: 1)
|
||||||
|
@user2 = FactoryGirl.create(:user, created_at: t+2.minute, last_jam_locidispid: 2)
|
||||||
|
@user3 = FactoryGirl.create(:user, created_at: t+3.minute, last_jam_locidispid: 3)
|
||||||
|
@user4 = FactoryGirl.create(:user, created_at: t+4.minute, last_jam_locidispid: 4)
|
||||||
|
@user5 = FactoryGirl.create(:user, created_at: t+5.minute, last_jam_locidispid: 5)
|
||||||
|
@user6 = FactoryGirl.create(:user, created_at: t+6.minute) # not geocoded
|
||||||
|
@user7 = FactoryGirl.create(:user, created_at: t+7.minute, musician: false) # not musician
|
||||||
|
|
||||||
|
@musicians = []
|
||||||
|
@musicians << @user1
|
||||||
|
@musicians << @user2
|
||||||
|
@musicians << @user3
|
||||||
|
@musicians << @user4
|
||||||
|
@musicians << @user5
|
||||||
|
@musicians << @user6
|
||||||
|
|
||||||
|
@geomusicians = []
|
||||||
|
@geomusicians << @user1
|
||||||
|
@geomusicians << @user2
|
||||||
|
@geomusicians << @user3
|
||||||
|
@geomusicians << @user4
|
||||||
|
@geomusicians << @user5
|
||||||
|
|
||||||
|
# from these scores:
|
||||||
|
# user1 has scores other users in user1 location, and with user2, user3, user4
|
||||||
|
# user2 has scores with users in user3 and user4 location
|
||||||
|
# Score.delete_all
|
||||||
|
Score.createx(1, 'a', 1, 1, 'a', 1, 10)
|
||||||
|
Score.createx(1, 'a', 1, 2, 'b', 2, 20)
|
||||||
|
Score.createx(1, 'a', 1, 3, 'c', 3, 30)
|
||||||
|
Score.createx(1, 'a', 1, 4, 'd', 4, 40)
|
||||||
|
Score.createx(2, 'b', 2, 3, 'c', 3, 15)
|
||||||
|
Score.createx(2, 'b', 2, 4, 'd', 4, 70)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "find two for user2" do
|
|
||||||
# user1,3,4 are scored against user1, but user4 is bad
|
context 'default filter settings' do
|
||||||
ms = Search.new_musicians(@user2, Time.now - 1.week)
|
|
||||||
ms.should_not be_nil
|
it "finds all musicians" do
|
||||||
ms.length.should == 2
|
# expects all the musicians (geocoded)
|
||||||
ms.should eq [@user3, @user1]
|
results = Search.musician_filter({score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == @musicians.length
|
||||||
|
results.results.should eq @musicians.reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds all musicians page 1" do
|
||||||
|
# expects all the musicians
|
||||||
|
results = Search.musician_filter({page: 1, score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == @musicians.length
|
||||||
|
results.results.should eq @musicians.reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds all musicians page 2" do
|
||||||
|
# expects no musicians (all fit on page 1)
|
||||||
|
results = Search.musician_filter({page: 2, score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds all musicians page 1 per_page 3" do
|
||||||
|
# expects three of the musicians
|
||||||
|
results = Search.musician_filter({per_page: 3, score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == 3
|
||||||
|
results.results.should eq @musicians.reverse.slice(0, 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds all musicians page 2 per_page 3" do
|
||||||
|
# expects two of the musicians
|
||||||
|
results = Search.musician_filter({page: 2, per_page: 3, score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == 3
|
||||||
|
results.results.should eq @musicians.reverse.slice(3, 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds all musicians page 3 per_page 3" do
|
||||||
|
# expects two of the musicians
|
||||||
|
results = Search.musician_filter({page: 3, per_page: 3, score_limit: Search::TEST_SCORE})
|
||||||
|
results.search_type.should == :musicians_filter
|
||||||
|
results.results.count.should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sorts musicians by followers" do
|
||||||
|
# establish sorting order
|
||||||
|
|
||||||
|
# @user4
|
||||||
|
f1 = Follow.new
|
||||||
|
f1.user = @user2
|
||||||
|
f1.followable = @user4
|
||||||
|
f1.save
|
||||||
|
|
||||||
|
f2 = Follow.new
|
||||||
|
f2.user = @user3
|
||||||
|
f2.followable = @user4
|
||||||
|
f2.save
|
||||||
|
|
||||||
|
f3 = Follow.new
|
||||||
|
f3.user = @user4
|
||||||
|
f3.followable = @user4
|
||||||
|
f3.save
|
||||||
|
|
||||||
|
# @user3
|
||||||
|
f4 = Follow.new
|
||||||
|
f4.user = @user3
|
||||||
|
f4.followable = @user3
|
||||||
|
f4.save
|
||||||
|
|
||||||
|
f5 = Follow.new
|
||||||
|
f5.user = @user4
|
||||||
|
f5.followable = @user3
|
||||||
|
f5.save
|
||||||
|
|
||||||
|
# @user2
|
||||||
|
f6 = Follow.new
|
||||||
|
f6.user = @user1
|
||||||
|
f6.followable = @user2
|
||||||
|
f6.save
|
||||||
|
|
||||||
|
# @user4.followers.concat([@user2, @user3, @user4])
|
||||||
|
# @user3.followers.concat([@user3, @user4])
|
||||||
|
# @user2.followers.concat([@user1])
|
||||||
|
expect(@user4.followers.count).to be 3
|
||||||
|
expect(Follow.count).to be 6
|
||||||
|
|
||||||
|
# refresh the order to ensure it works right
|
||||||
|
f1 = Follow.new
|
||||||
|
f1.user = @user3
|
||||||
|
f1.followable = @user2
|
||||||
|
f1.save
|
||||||
|
|
||||||
|
f2 = Follow.new
|
||||||
|
f2.user = @user4
|
||||||
|
f2.followable = @user2
|
||||||
|
f2.save
|
||||||
|
|
||||||
|
f3 = Follow.new
|
||||||
|
f3.user = @user2
|
||||||
|
f3.followable = @user2
|
||||||
|
f3.save
|
||||||
|
|
||||||
|
# @user2.followers.concat([@user3, @user4, @user2])
|
||||||
|
results = Search.musician_filter({:per_page => @musicians.size, score_limit: Search::TEST_SCORE, orderby: 'followed'}, @user3)
|
||||||
|
expect(results.results[0].id).to eq(@user2.id)
|
||||||
|
|
||||||
|
# check the follower count for given entry
|
||||||
|
expect(results.results[0].search_follow_count.to_i).not_to eq(0)
|
||||||
|
# check the follow relationship between current_user and result
|
||||||
|
expect(results.is_follower?(@user2)).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'paginates properly' do
|
||||||
|
# make sure pagination works right
|
||||||
|
params = {:per_page => 2, :page => 1, score_limit: Search::TEST_SCORE}
|
||||||
|
results = Search.musician_filter(params)
|
||||||
|
expect(results.results.count).to be 2
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "find two for user3" do
|
def make_recording(usr)
|
||||||
# user1..2 are scored against user3
|
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
||||||
ms = Search.new_musicians(@user3, Time.now - 1.week)
|
instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||||
ms.should_not be_nil
|
track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument)
|
||||||
ms.length.should == 2
|
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
||||||
ms.should eq [@user2, @user1]
|
# music_session.connections << connection
|
||||||
|
# music_session.save
|
||||||
|
connection.join_the_session(music_session, true, nil, usr, 10)
|
||||||
|
recording = Recording.start(music_session, usr)
|
||||||
|
recording.stop
|
||||||
|
recording.reload
|
||||||
|
genre = FactoryGirl.create(:genre)
|
||||||
|
recording.claim(usr, "name", "description", genre, true)
|
||||||
|
recording.reload
|
||||||
|
recording
|
||||||
end
|
end
|
||||||
|
|
||||||
it "find one for user4" do
|
def make_session(usr)
|
||||||
# user1..2 are scored against user4, but user2 is bad
|
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
||||||
ms = Search.new_musicians(@user4, Time.now - 1.week)
|
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
||||||
ms.should_not be_nil
|
# music_session.connections << connection
|
||||||
ms.length.should == 1
|
# music_session.save
|
||||||
ms.should eq [@user1]
|
connection.join_the_session(music_session, true, nil, usr, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "find none for user5" do
|
context 'musician stat counters' do
|
||||||
# user1..4 are not scored against user5
|
|
||||||
ms = Search.new_musicians(@user5, Time.now - 1.week)
|
it "displays musicians top followings" do
|
||||||
ms.should_not be_nil
|
f1 = Follow.new
|
||||||
ms.length.should == 0
|
f1.user = @user4
|
||||||
|
f1.followable = @user4
|
||||||
|
f1.save
|
||||||
|
|
||||||
|
f2 = Follow.new
|
||||||
|
f2.user = @user4
|
||||||
|
f2.followable = @user3
|
||||||
|
f2.save
|
||||||
|
|
||||||
|
f3 = Follow.new
|
||||||
|
f3.user = @user4
|
||||||
|
f3.followable = @user2
|
||||||
|
f3.save
|
||||||
|
|
||||||
|
# @user4.followers.concat([@user4])
|
||||||
|
# @user3.followers.concat([@user4])
|
||||||
|
# @user2.followers.concat([@user4])
|
||||||
|
expect(@user4.top_followings.count).to eq 3
|
||||||
|
expect(@user4.top_followings.map(&:id)).to match_array((@musicians - [@user1, @user5, @user6]).map(&:id))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "friends stat shows friend count" do
|
||||||
|
# create friendship record
|
||||||
|
Friendship.save(@user1.id, @user2.id)
|
||||||
|
# search on user2
|
||||||
|
results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user2)
|
||||||
|
friend = results.results.detect { |mm| mm.id == @user1.id }
|
||||||
|
expect(friend).to_not be_nil
|
||||||
|
expect(results.friend_count(friend)).to be 1
|
||||||
|
@user1.reload
|
||||||
|
expect(friend.friends?(@user2)).to be true
|
||||||
|
expect(results.is_friend?(@user1)).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "recording stat shows recording count" do
|
||||||
|
Recording.delete_all
|
||||||
|
|
||||||
|
recording = make_recording(@user1)
|
||||||
|
expect(recording.users.length).to be 1
|
||||||
|
expect(recording.users.first).to eq(@user1)
|
||||||
|
@user1.reload
|
||||||
|
expect(@user1.recordings.length).to be 1
|
||||||
|
expect(@user1.recordings.first).to eq(recording)
|
||||||
|
expect(recording.claimed_recordings.length).to be 1
|
||||||
|
expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil
|
||||||
|
|
||||||
|
results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user1)
|
||||||
|
# puts "====================== results #{results.inspect}"
|
||||||
|
uu = results.results.detect { |mm| mm.id == @user1.id }
|
||||||
|
expect(uu).to_not be_nil
|
||||||
|
|
||||||
|
expect(results.record_count(uu)).to be 1
|
||||||
|
expect(results.session_count(uu)).to be 1
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'musician sorting' do
|
||||||
|
|
||||||
|
it "by plays" do
|
||||||
|
Recording.delete_all
|
||||||
|
|
||||||
|
make_recording(@user1)
|
||||||
|
# order results by num recordings
|
||||||
|
results = Search.musician_filter({orderby: 'plays', score_limit: Search::TEST_SCORE}, @user2)
|
||||||
|
# puts "========= results #{results.inspect}"
|
||||||
|
expect(results.results.length).to eq(2)
|
||||||
|
expect(results.results[0].id).to eq(@user1.id)
|
||||||
|
expect(results.results[1].id).to eq(@user3.id)
|
||||||
|
|
||||||
|
# add more data and make sure order still correct
|
||||||
|
make_recording(@user3)
|
||||||
|
make_recording(@user3)
|
||||||
|
results = Search.musician_filter({:orderby => 'plays', score_limit: Search::TEST_SCORE}, @user2)
|
||||||
|
expect(results.results.length).to eq(2)
|
||||||
|
expect(results.results[0].id).to eq(@user3.id)
|
||||||
|
expect(results.results[1].id).to eq(@user1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "by now playing" do
|
||||||
|
pending "these tests worked, so leaving them in, but we don't currently have 'Now Playing' in the find musicians screen"
|
||||||
|
# should get 1 result with 1 active session
|
||||||
|
make_session(@user1)
|
||||||
|
results = Search.musician_filter({:orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
||||||
|
expect(results.results.count).to be 1
|
||||||
|
expect(results.results.first.id).to eq(@user1.id)
|
||||||
|
|
||||||
|
# should get 2 results with 2 active sessions
|
||||||
|
# sort order should be created_at DESC
|
||||||
|
make_session(@user3)
|
||||||
|
results = Search.musician_filter({:orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
||||||
|
expect(results.results.count).to be 2
|
||||||
|
expect(results.results[0].id).to eq(@user3.id)
|
||||||
|
expect(results.results[1].id).to eq(@user1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'filter settings' do
|
||||||
|
it "searches musicisns for an instrument" do
|
||||||
|
minst = FactoryGirl.create(:musician_instrument, {
|
||||||
|
:user => @user1,
|
||||||
|
:instrument => Instrument.find('tuba')})
|
||||||
|
@user1.musician_instruments << minst
|
||||||
|
@user1.reload
|
||||||
|
ii = @user1.instruments.detect { |inst| inst.id == 'tuba' }
|
||||||
|
expect(ii).to_not be_nil
|
||||||
|
results = Search.musician_filter({:instrument => ii.id, score_limit: Search::TEST_SCORE})
|
||||||
|
results.results.each do |rr|
|
||||||
|
expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id)
|
||||||
|
end
|
||||||
|
expect(results.results.count).to be 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'new users' do
|
||||||
|
|
||||||
|
it "find three for user1" do
|
||||||
|
# user2..4 are scored against user1
|
||||||
|
ms = Search.new_musicians(@user1, Time.now - 1.week)
|
||||||
|
ms.should_not be_nil
|
||||||
|
ms.length.should == 3
|
||||||
|
ms.should eq [@user2, @user3, @user4]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "find two for user2" do
|
||||||
|
# user1,3,4 are scored against user1, but user4 is bad
|
||||||
|
ms = Search.new_musicians(@user2, Time.now - 1.week)
|
||||||
|
ms.should_not be_nil
|
||||||
|
ms.length.should == 2
|
||||||
|
ms.should eq [@user3, @user1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "find two for user3" do
|
||||||
|
# user1..2 are scored against user3
|
||||||
|
ms = Search.new_musicians(@user3, Time.now - 1.week)
|
||||||
|
ms.should_not be_nil
|
||||||
|
ms.length.should == 2
|
||||||
|
ms.should eq [@user2, @user1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "find one for user4" do
|
||||||
|
# user1..2 are scored against user4, but user2 is bad
|
||||||
|
ms = Search.new_musicians(@user4, Time.now - 1.week)
|
||||||
|
ms.should_not be_nil
|
||||||
|
ms.length.should == 1
|
||||||
|
ms.should eq [@user1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "find none for user5" do
|
||||||
|
# user1..4 are not scored against user5
|
||||||
|
ms = Search.new_musicians(@user5, Time.now - 1.week)
|
||||||
|
ms.should_not be_nil
|
||||||
|
ms.length.should == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ def ip_from_num(num)
|
||||||
end
|
end
|
||||||
|
|
||||||
def austin_ip
|
def austin_ip
|
||||||
IPAddr.new(0x0FFFFFFF, Socket::AF_INET).to_s
|
IPAddr.new(austin_ip_as_num, Socket::AF_INET).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def austin_ip_as_num
|
def austin_ip_as_num
|
||||||
|
|
@ -177,35 +177,64 @@ def austin_ip_as_num
|
||||||
end
|
end
|
||||||
|
|
||||||
def dallas_ip
|
def dallas_ip
|
||||||
IPAddr.new(0x1FFFFFFF, Socket::AF_INET).to_s
|
IPAddr.new(dallas_ip_as_num, Socket::AF_INET).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def dallas_ip_as_num
|
def dallas_ip_as_num
|
||||||
0x1FFFFFFF
|
0x1FFFFFFF
|
||||||
end
|
end
|
||||||
|
|
||||||
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
def houston_ip
|
||||||
def austin_geoip
|
IPAddr.new(houston_ip_as_num, Socket::AF_INET).to_s
|
||||||
geoiplocation = GeoIpLocations.find_by_locid(17192)
|
end
|
||||||
geoipblock = GeoIpBlocks.find_by_locid(17192)
|
|
||||||
|
def houston_ip_as_num
|
||||||
|
0x2FFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def miami_ip
|
||||||
|
IPAddr.new(miami_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def miami_ip_as_num
|
||||||
|
0x5FFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_ip
|
||||||
|
IPAddr.new(seattle_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_ip_as_num
|
||||||
|
0xAFFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_geoip(locid)
|
||||||
|
geoiplocation = GeoIpLocations.find_by_locid(locid)
|
||||||
|
geoipblock = GeoIpBlocks.find_by_locid(locid)
|
||||||
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
||||||
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
||||||
end
|
end
|
||||||
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
|
def austin_geoip
|
||||||
|
create_geoip(17192)
|
||||||
|
end
|
||||||
|
|
||||||
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
def dallas_geoip
|
def dallas_geoip
|
||||||
geoiplocation = GeoIpLocations.find_by_locid(667)
|
create_geoip(667)
|
||||||
geoipblock = GeoIpBlocks.find_by_locid(667)
|
|
||||||
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
|
||||||
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
def houston_geoip
|
def houston_geoip
|
||||||
geoiplocation = GeoIpLocations.find_by_locid(30350)
|
create_geoip(30350)
|
||||||
geoipblock = GeoIpBlocks.find_by_locid(30350)
|
end
|
||||||
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
|
||||||
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
def miami_geoip
|
||||||
|
create_geoip(23565)
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_geoip
|
||||||
|
create_geoip(1539)
|
||||||
end
|
end
|
||||||
|
|
||||||
# attempts to make the creation of a score more straightforward.
|
# attempts to make the creation of a score more straightforward.
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,12 @@ group :development, :test do
|
||||||
gem 'rspec-rails', '2.14.2'
|
gem 'rspec-rails', '2.14.2'
|
||||||
gem "activerecord-import", "~> 0.4.1"
|
gem "activerecord-import", "~> 0.4.1"
|
||||||
gem 'guard-rspec', '0.5.5'
|
gem 'guard-rspec', '0.5.5'
|
||||||
gem 'jasmine', '1.3.1'
|
# gem 'jasmine', '1.3.1'
|
||||||
gem 'pry'
|
gem 'pry'
|
||||||
gem 'execjs', '1.4.0'
|
gem 'execjs', '1.4.0'
|
||||||
gem 'factory_girl_rails', '4.1.0' # in dev because in use by rake task
|
gem 'factory_girl_rails', '4.1.0' # in dev because in use by rake task
|
||||||
gem 'database_cleaner', '1.3.0' #in dev because in use by rake task
|
gem 'database_cleaner', '1.3.0' #in dev because in use by rake task
|
||||||
|
gem 'teaspoon'
|
||||||
end
|
end
|
||||||
group :unix do
|
group :unix do
|
||||||
gem 'therubyracer' #, '0.11.0beta8'
|
gem 'therubyracer' #, '0.11.0beta8'
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
var self = this;
|
var self = this;
|
||||||
var reloadAudioTimeout = null;
|
var reloadAudioTimeout = null;
|
||||||
var $root;
|
var $root;
|
||||||
|
var $dialog;
|
||||||
|
var $addNewGearBtn;
|
||||||
var userId;
|
var userId;
|
||||||
var showingGearWizard = false;
|
var showingGearWizard = false;
|
||||||
var cancelRescanFunc = null;
|
var cancelRescanFunc = null;
|
||||||
|
|
@ -88,7 +90,13 @@
|
||||||
context.JK.guardAgainstBrowser(app, {d1: 'gear'});
|
context.JK.guardAgainstBrowser(app, {d1: 'gear'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
populateAccountAudio()
|
var profiles = populateAccountAudio();
|
||||||
|
if(profiles.length == 1) {
|
||||||
|
setTimeout(function() {
|
||||||
|
context.JK.prodBubble($addNewGearBtn, 'no-audio-profiles', {}, {positions: ['bottom'], offsetParent: $addNewGearBtn.closest('.screen')});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +123,8 @@
|
||||||
var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: cleansedProfiles}, {variable: 'data'});
|
var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: cleansedProfiles}, {variable: 'data'});
|
||||||
|
|
||||||
appendAudio(template);
|
appendAudio(template);
|
||||||
|
|
||||||
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendAudio(template) {
|
function appendAudio(template) {
|
||||||
|
|
@ -202,16 +212,16 @@
|
||||||
|
|
||||||
function handleStartAudioQualification() {
|
function handleStartAudioQualification() {
|
||||||
|
|
||||||
if(true) {
|
app.afterFtue = function() {
|
||||||
app.afterFtue = function() { showingGearWizard = false; populateAccountAudio() };
|
showingGearWizard = false;
|
||||||
app.cancelFtue = function() { showingGearWizard = false; populateAccountAudio() };
|
if(populateAccountAudio().length == 1) {
|
||||||
showingGearWizard = true;
|
app.layout.showDialog('join-test-session');
|
||||||
app.layout.startNewFtue();
|
}
|
||||||
}
|
};
|
||||||
else {
|
app.cancelFtue = function() { showingGearWizard = false; populateAccountAudio() };
|
||||||
app.setWizardStep(1);
|
showingGearWizard = true;
|
||||||
app.layout.showDialog('ftue');
|
app.layout.startNewFtue();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadAudio() {
|
function reloadAudio() {
|
||||||
|
|
@ -309,8 +319,11 @@
|
||||||
'beforeShow': beforeShow,
|
'beforeShow': beforeShow,
|
||||||
'afterShow': afterShow
|
'afterShow': afterShow
|
||||||
};
|
};
|
||||||
|
|
||||||
app.bindScreen('account/audio', screenBindings);
|
app.bindScreen('account/audio', screenBindings);
|
||||||
|
|
||||||
|
$dialog = $('#account-audio-profile')
|
||||||
|
$addNewGearBtn = $dialog.find('a[data-purpose=add-profile]');
|
||||||
events();
|
events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
var api = context.JK.Rest();
|
var api = context.JK.Rest();
|
||||||
var userId;
|
var userId;
|
||||||
var user = {};
|
var user = {};
|
||||||
|
var selectLocation = null;
|
||||||
var recentUserDetail = null;
|
var recentUserDetail = null;
|
||||||
var loadingCitiesData = false;
|
var loadingCitiesData = false;
|
||||||
var loadingRegionsData = false;
|
var loadingRegionsData = false;
|
||||||
|
|
@ -252,28 +253,8 @@
|
||||||
$('#account-profile-content-scroller').on('click', '#account-edit-profile-cancel', function(evt) { evt.stopPropagation(); navToAccount(); return false; } );
|
$('#account-profile-content-scroller').on('click', '#account-edit-profile-cancel', function(evt) { evt.stopPropagation(); navToAccount(); return false; } );
|
||||||
$('#account-profile-content-scroller').on('click', '#account-edit-profile-submit', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
$('#account-profile-content-scroller').on('click', '#account-edit-profile-submit', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
||||||
$('#account-profile-content-scroller').on('submit', '#account-edit-email-form', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
$('#account-profile-content-scroller').on('submit', '#account-edit-email-form', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
||||||
$('#account-profile-content-scroller').on('change', 'select[name=country]', function(evt) { evt.stopPropagation(); handleCountryChanged(); return false; } );
|
|
||||||
$('#account-profile-content-scroller').on('change', 'select[name=region]', function(evt) { evt.stopPropagation(); handleRegionChanged(); return false; } );
|
|
||||||
$('#account-profile-content-scroller').on('click', '#account-change-avatar', function(evt) { evt.stopPropagation(); navToAvatar(); return false; } );
|
$('#account-profile-content-scroller').on('click', '#account-change-avatar', function(evt) { evt.stopPropagation(); navToAvatar(); return false; } );
|
||||||
}
|
}
|
||||||
|
|
||||||
function regionListFailure(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(jqXHR.status == 422) {
|
|
||||||
logger.debug("no regions found for country: " + recentUserDetail.country);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
app.ajaxError(arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function cityListFailure(jqXHR, textStatus, errorThrown) {
|
|
||||||
if(jqXHR.status == 422) {
|
|
||||||
logger.debug("no cities found for country/region: " + recentUserDetail.country + "/" + recentUserDetail.state);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
app.ajaxError(arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function renderAccountProfile() {
|
function renderAccountProfile() {
|
||||||
|
|
||||||
$.when( api.getUserDetail(),
|
$.when( api.getUserDetail(),
|
||||||
|
|
@ -285,43 +266,8 @@
|
||||||
// show page; which can be done quickly at this point
|
// show page; which can be done quickly at this point
|
||||||
populateAccountProfile(userDetail, instruments);
|
populateAccountProfile(userDetail, instruments);
|
||||||
|
|
||||||
var country = userDetail.country;
|
selectLocation = new context.JK.SelectLocation(getCountryElement(), getRegionElement(), getCityElement(), app);
|
||||||
|
selectLocation.load(userDetail.country, userDetail.state, userDetail.city)
|
||||||
if(!country) {
|
|
||||||
// this case shouldn't happen because sign up makes you pick a location. This is just 'in case', so that the UI is more error-resilient
|
|
||||||
country = 'US';
|
|
||||||
}
|
|
||||||
|
|
||||||
loadingCountriesData = true;
|
|
||||||
loadingRegionsData = true;
|
|
||||||
loadingCitiesData = true;
|
|
||||||
|
|
||||||
// make the 3 slower requests, which only matter if the user wants to affect their ISP or location
|
|
||||||
|
|
||||||
api.getCountries()
|
|
||||||
.done(function(countriesx) { populateCountriesx(countriesx["countriesx"], userDetail.country); } )
|
|
||||||
.fail(app.ajaxError)
|
|
||||||
.always(function() { loadingCountriesData = false; })
|
|
||||||
|
|
||||||
var country = userDetail.country;
|
|
||||||
var state = userDetail.state;
|
|
||||||
|
|
||||||
if(country) {
|
|
||||||
api.getRegions( { country: country } )
|
|
||||||
.done(function(regions) { populateRegions(regions["regions"], userDetail.state); } )
|
|
||||||
.fail(regionListFailure)
|
|
||||||
.always(function() { loadingRegionsData = false; })
|
|
||||||
|
|
||||||
if(state) {
|
|
||||||
api.getCities( { country: country, region: state })
|
|
||||||
.done(function(cities) {
|
|
||||||
populateCities(cities["cities"], userDetail.city)
|
|
||||||
})
|
|
||||||
.fail(cityListFailure)
|
|
||||||
.always(function() { loadingCitiesData = false;})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
context.JK.dropdown($('select'));
|
context.JK.dropdown($('select'));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||||
// GO AFTER THE REQUIRES BELOW.
|
// GO AFTER THE REQUIRES BELOW.
|
||||||
//
|
//
|
||||||
|
//= require bind-polyfill
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery.monkeypatch
|
//= require jquery.monkeypatch
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
|
|
@ -34,6 +35,7 @@
|
||||||
//= require jquery.browser
|
//= require jquery.browser
|
||||||
//= require jquery.custom-protocol
|
//= require jquery.custom-protocol
|
||||||
//= require jstz
|
//= require jstz
|
||||||
|
//= require class
|
||||||
//= require AAC_underscore
|
//= require AAC_underscore
|
||||||
//= require AAA_Log
|
//= require AAA_Log
|
||||||
//= require globals
|
//= require globals
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,13 @@
|
||||||
context.JK.onBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceDisconnected);
|
context.JK.onBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCancel() {
|
||||||
|
if($btnCancel.is('.disabled')) return false;
|
||||||
|
|
||||||
|
$dialog.data('result', 'cancel');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function beforeHide() {
|
function beforeHide() {
|
||||||
context.JK.offBackendEvent(ALERT_NAMES.USB_CONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceConnected);
|
context.JK.offBackendEvent(ALERT_NAMES.USB_CONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceConnected);
|
||||||
context.JK.offBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceDisconnected);
|
context.JK.offBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'audio-profile-invalid-dialog', onUsbDeviceDisconnected);
|
||||||
|
|
@ -166,14 +173,6 @@
|
||||||
app.layout.closeDialog('audio-profile-invalid-dialog');
|
app.layout.closeDialog('audio-profile-invalid-dialog');
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
|
|
||||||
$btnCancel.click(function() {
|
|
||||||
if($(this).is('.disabled')) return false;
|
|
||||||
|
|
||||||
$dialog.data('result', 'cancel');
|
|
||||||
app.layout.closeDialog('audio-profile-invalid-dialog');
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
|
@ -182,7 +181,8 @@
|
||||||
'beforeShow': beforeShow,
|
'beforeShow': beforeShow,
|
||||||
'afterShow' : afterShow,
|
'afterShow' : afterShow,
|
||||||
'beforeHide' : beforeHide,
|
'beforeHide' : beforeHide,
|
||||||
'afterHide': afterHide
|
'afterHide': afterHide,
|
||||||
|
'onCancel' : onCancel
|
||||||
};
|
};
|
||||||
|
|
||||||
app.bindDialog('audio-profile-invalid-dialog', dialogBindings);
|
app.bindDialog('audio-profile-invalid-dialog', dialogBindings);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
(function (context, $) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
context.JK = context.JK || {};
|
||||||
|
context.JK.ChangeSearchLocationDialog = function (app) {
|
||||||
|
var logger = context.JK.logger;
|
||||||
|
var rest = context.JK.Rest();
|
||||||
|
var $dialog = null;
|
||||||
|
var initialized = false;
|
||||||
|
var $countries = null;
|
||||||
|
var $regions = null;
|
||||||
|
var $cities = null;
|
||||||
|
var selectLocation = null;
|
||||||
|
var $resetLocation = null;
|
||||||
|
var $btnSave = null;
|
||||||
|
|
||||||
|
function getSelection() {
|
||||||
|
var countryVal = $countries.val();
|
||||||
|
var regionVal = $regions.val();
|
||||||
|
var cityVal = $cities.val();
|
||||||
|
|
||||||
|
if(countryVal && regionVal && cityVal) {
|
||||||
|
// if any bit of info is not set, then null out info; user didn't pick a full set of data
|
||||||
|
var $country = $($countries).find('option:selected');
|
||||||
|
var $region = $($regions).find('option:selected');
|
||||||
|
|
||||||
|
return {
|
||||||
|
countrycode : countryVal,
|
||||||
|
regioncode : regionVal,
|
||||||
|
city: cityVal,
|
||||||
|
country: $country.text(),
|
||||||
|
region: $region.text()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function events() {
|
||||||
|
$btnSave.click(function() {
|
||||||
|
|
||||||
|
var selection = getSelection();
|
||||||
|
|
||||||
|
app.user().done(function(user) {
|
||||||
|
if(selection != null &&
|
||||||
|
selection.countrycode == user.country &&
|
||||||
|
selection.regioncode == user.state &&
|
||||||
|
selection.city == user.city) {
|
||||||
|
// if this is the same location on the user's account, suppress selection
|
||||||
|
selection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog.data('result', selection);
|
||||||
|
app.layout.closeDialog('change-search-location')
|
||||||
|
})
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
$resetLocation.click(function() {
|
||||||
|
app.user().done(function(user) {
|
||||||
|
selectLocation.load(user.country, user.state, user.city);
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeShow() {
|
||||||
|
$dialog.data('result', null);
|
||||||
|
|
||||||
|
if(!initialized) {
|
||||||
|
initialized = true;
|
||||||
|
app.user().done(function(user) {
|
||||||
|
selectLocation = new context.JK.SelectLocation($countries, $regions, $cities, app);
|
||||||
|
selectLocation.load(user.country, user.state, user.city);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeHide() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedLocation() {
|
||||||
|
return searchLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize() {
|
||||||
|
var dialogBindings = {
|
||||||
|
'beforeShow': beforeShow,
|
||||||
|
'beforeHide': beforeHide
|
||||||
|
};
|
||||||
|
|
||||||
|
app.bindDialog('change-search-location', dialogBindings);
|
||||||
|
|
||||||
|
$dialog = $('#change-search-location-dialog');
|
||||||
|
$countries = $dialog.find('select[name="country"]')
|
||||||
|
$regions = $dialog.find('select[name="region"]')
|
||||||
|
$cities = $dialog.find('select[name="city"]')
|
||||||
|
$resetLocation = $dialog.find('.reset-location');
|
||||||
|
$btnSave = $dialog.find('.btnSave')
|
||||||
|
|
||||||
|
events();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.initialize = initialize;
|
||||||
|
this.getSelectedLocation = getSelectedLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
})(window, jQuery);
|
||||||
|
|
@ -119,13 +119,10 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$btnCancel.click(function() {
|
$btnCancel.click(function() {
|
||||||
if(voiceChatHelper.cancel()) {
|
app.layout.cancelDialog('configure-tracks');
|
||||||
app.layout.closeDialog('configure-tracks')
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//$btnAddNewGear.click(function() {
|
//$btnAddNewGear.click(function() {
|
||||||
|
|
||||||
// return false;
|
// return false;
|
||||||
|
|
@ -206,10 +203,14 @@
|
||||||
function afterShow() {
|
function afterShow() {
|
||||||
sessionUtils.SessionPageEnter();
|
sessionUtils.SessionPageEnter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCancel() {
|
||||||
|
return voiceChatHelper.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
function afterHide() {
|
function afterHide() {
|
||||||
voiceChatHelper.beforeHide();
|
voiceChatHelper.beforeHide();
|
||||||
sessionUtils.SessionPageLeave();
|
sessionUtils.SessionPageLeave();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
|
@ -217,7 +218,8 @@
|
||||||
var dialogBindings = {
|
var dialogBindings = {
|
||||||
'beforeShow' : beforeShow,
|
'beforeShow' : beforeShow,
|
||||||
'afterShow' : afterShow,
|
'afterShow' : afterShow,
|
||||||
'afterHide': afterHide
|
'afterHide': afterHide,
|
||||||
|
'onCancel' : onCancel
|
||||||
};
|
};
|
||||||
|
|
||||||
app.bindDialog('configure-tracks', dialogBindings);
|
app.bindDialog('configure-tracks', dialogBindings);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
var $description = null;
|
var $description = null;
|
||||||
var $genre = null;
|
var $genre = null;
|
||||||
var $isPublic = null;
|
var $isPublic = null;
|
||||||
var $cancelBtn = null;
|
|
||||||
var $saveBtn = null;
|
var $saveBtn = null;
|
||||||
var $deleteBtn = null;
|
var $deleteBtn = null;
|
||||||
|
|
||||||
|
|
@ -129,14 +128,9 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
app.layout.closeDialog('edit-recording');
|
|
||||||
}
|
|
||||||
|
|
||||||
function events() {
|
function events() {
|
||||||
$saveBtn.click(attemptUpdate);
|
$saveBtn.click(attemptUpdate);
|
||||||
$deleteBtn.click(attemptDelete);
|
$deleteBtn.click(attemptDelete);
|
||||||
$cancelBtn.click(cancel)
|
|
||||||
$form.submit(false);
|
$form.submit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +145,6 @@
|
||||||
|
|
||||||
$dialog = $('#edit-recording-dialog');
|
$dialog = $('#edit-recording-dialog');
|
||||||
$form = $dialog.find('form');
|
$form = $dialog.find('form');
|
||||||
$cancelBtn = $dialog.find('.cancel-btn');
|
|
||||||
$saveBtn = $dialog.find('.save-btn');
|
$saveBtn = $dialog.find('.save-btn');
|
||||||
$deleteBtn = $dialog.find('.delete-btn');
|
$deleteBtn = $dialog.find('.delete-btn');
|
||||||
$name = $dialog.find('input[name="name"]');
|
$name = $dialog.find('input[name="name"]');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
(function (context, $) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
context.JK = context.JK || {};
|
||||||
|
context.JK.GettingStartedDialog = function (app) {
|
||||||
|
var logger = context.JK.logger;
|
||||||
|
var rest = context.JK.Rest();
|
||||||
|
var invitationDialog = null;
|
||||||
|
var $dialog = null;
|
||||||
|
var $dontShowAgain = null;
|
||||||
|
var $setupGearBtn = null;
|
||||||
|
|
||||||
|
|
||||||
|
function registerEvents() {
|
||||||
|
|
||||||
|
$setupGearBtn.click(function() {
|
||||||
|
if (gon.isNativeClient) {
|
||||||
|
app.layout.closeDialog('getting-started');
|
||||||
|
window.location = '/client#/account/audio'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.JK.guardAgainstBrowser(app, {d1: 'gear'});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
|
||||||
|
$('#getting-started-dialog a.facebook-invite').on('click', function (e) {
|
||||||
|
invitationDialog.showFacebookDialog(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#getting-started-dialog a.google-invite').on('click', function (e) {
|
||||||
|
invitationDialog.showGoogleDialog();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#getting-started-dialog a.email-invite').on('click', function (e) {
|
||||||
|
invitationDialog.showEmailDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeShow() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeHide() {
|
||||||
|
|
||||||
|
if ($dontShowAgain.is(':checked')) {
|
||||||
|
app.updateUserModel({show_whats_next: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeButtons() {
|
||||||
|
|
||||||
|
context.JK.checkbox($dontShowAgain);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize(invitationDialogInstance) {
|
||||||
|
var dialogBindings = {
|
||||||
|
'beforeShow': beforeShow,
|
||||||
|
'beforeHide': beforeHide
|
||||||
|
};
|
||||||
|
|
||||||
|
app.bindDialog('getting-started', dialogBindings);
|
||||||
|
|
||||||
|
$dialog = $('#getting-started-dialog');
|
||||||
|
$dontShowAgain = $dialog.find('#show_getting_started');
|
||||||
|
$setupGearBtn = $dialog.find('.setup-gear-btn')
|
||||||
|
|
||||||
|
registerEvents();
|
||||||
|
|
||||||
|
invitationDialog = invitationDialogInstance;
|
||||||
|
|
||||||
|
initializeButtons();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.initialize = initialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
})(window, jQuery);
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
(function (context, $) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
context.JK = context.JK || {};
|
||||||
|
context.JK.JoinTestSessionDialog = function (app) {
|
||||||
|
var logger = context.JK.logger;
|
||||||
|
var rest = context.JK.Rest();
|
||||||
|
var $dialog = null;
|
||||||
|
var $joinTestSessionBtn = null;
|
||||||
|
|
||||||
|
function joinSession(sessionId) {
|
||||||
|
app.layout.closeDialog('join-test-session')
|
||||||
|
$joinTestSessionBtn.removeClass('disabled');
|
||||||
|
context.JK.GA.trackSessionCount(true, true, 0);
|
||||||
|
|
||||||
|
// we redirect to the session screen, which handles the REST call to POST /participants.
|
||||||
|
logger.debug("joining session screen: " + sessionId)
|
||||||
|
context.location = '/client#/session/' + sessionId;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createSession(sessionId) {
|
||||||
|
var data = {};
|
||||||
|
|
||||||
|
data.name = 'First Session';
|
||||||
|
data.description = 'This is my first ever session on JamKazam, so please be gentle. :)';
|
||||||
|
data.genres = ['other']
|
||||||
|
data.musician_access = true;
|
||||||
|
data.approval_required = false;
|
||||||
|
data.fan_access = true;
|
||||||
|
data.fan_chat = true;
|
||||||
|
data.legal_policy = 'Standard'
|
||||||
|
data.legal_terms = true;
|
||||||
|
data.language = 'eng';
|
||||||
|
data.start = new Date().toDateString() + ' ' + context.JK.formatUtcTime(new Date(), false);
|
||||||
|
data.duration = "60";
|
||||||
|
data.recurring_mode = 'once'
|
||||||
|
data.music_notations = [];
|
||||||
|
data.timezone = 'Central Time (US & Canada),America/Chicago'
|
||||||
|
data.open_rsvps = true
|
||||||
|
data.rsvp_slots = [];
|
||||||
|
|
||||||
|
// auto pick an 'other' instrument
|
||||||
|
var otherId = context.JK.server_to_client_instrument_map.Other.server_id; // get server ID
|
||||||
|
var otherInstrumentInfo = context.JK.instrument_id_to_instrument[otherId]; // get display name
|
||||||
|
var beginnerLevel = 1; // default to beginner
|
||||||
|
var instruments = [ {id: otherId, name: otherInstrumentInfo.display, level: beginnerLevel} ];
|
||||||
|
$.each(instruments, function(index, instrument) {
|
||||||
|
var slot = {};
|
||||||
|
slot.instrument_id = instrument.id;
|
||||||
|
slot.proficiency_level = instrument.level;
|
||||||
|
slot.approve = true;
|
||||||
|
data.rsvp_slots.push(slot);
|
||||||
|
});
|
||||||
|
|
||||||
|
data.isUnstructuredRsvp = true;
|
||||||
|
|
||||||
|
rest.createScheduledSession(data)
|
||||||
|
.done(function(response) {
|
||||||
|
logger.debug("created test session on server");
|
||||||
|
//$('#create-session-buttons .btn-next').off('click');
|
||||||
|
var newSessionId = response.id;
|
||||||
|
|
||||||
|
joinSession(newSessionId);
|
||||||
|
})
|
||||||
|
.fail(function(jqXHR){
|
||||||
|
$joinTestSessionBtn.removeClass('disabled');
|
||||||
|
logger.debug("unable to schedule a test session")
|
||||||
|
app.notifyServerError(jqXHR, "Unable to schedule a test session");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerEvents() {
|
||||||
|
|
||||||
|
$joinTestSessionBtn.click(function() {
|
||||||
|
|
||||||
|
if($joinTestSessionBtn.is('.disabled')) return false;
|
||||||
|
|
||||||
|
$joinTestSessionBtn.addClass('disabled');
|
||||||
|
|
||||||
|
createSession();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeShow() {
|
||||||
|
$joinTestSessionBtn.removeClass('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeHide() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function initialize() {
|
||||||
|
var dialogBindings = {
|
||||||
|
'beforeShow': beforeShow,
|
||||||
|
'beforeHide': beforeHide
|
||||||
|
};
|
||||||
|
|
||||||
|
app.bindDialog('join-test-session', dialogBindings);
|
||||||
|
|
||||||
|
$dialog = $('#join-test-session-dialog');
|
||||||
|
$joinTestSessionBtn = $dialog.find('.join-test-session')
|
||||||
|
|
||||||
|
registerEvents();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.initialize = initialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
})(window, jQuery);
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
var logger = context.JK.logger;
|
var logger = context.JK.logger;
|
||||||
|
|
||||||
var $dialog = null;
|
var $dialog = null;
|
||||||
var $btnCancel = null;
|
|
||||||
var $btnClose = null;
|
var $btnClose = null;
|
||||||
var $btnHelp = null;
|
var $btnHelp = null;
|
||||||
var networkTest = new context.JK.NetworkTest(app);
|
var networkTest = new context.JK.NetworkTest(app);
|
||||||
|
|
@ -37,13 +36,10 @@
|
||||||
$btnClose.removeClass('button-grey').addClass('button-orange');
|
$btnClose.removeClass('button-grey').addClass('button-orange');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCancel() {
|
||||||
|
// should we stop this if the test is going?
|
||||||
|
}
|
||||||
function events() {
|
function events() {
|
||||||
$btnCancel.on('click', function() {
|
|
||||||
// should we stop this if the test is going?
|
|
||||||
app.layout.closeDialog('network-test')
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
|
|
||||||
$btnClose.on('click', function(e) {
|
$btnClose.on('click', function(e) {
|
||||||
if(!networkTest.isScoring()) {
|
if(!networkTest.isScoring()) {
|
||||||
app.layout.closeDialog('network-test');
|
app.layout.closeDialog('network-test');
|
||||||
|
|
@ -77,7 +73,6 @@
|
||||||
app.bindDialog('network-test', dialogBindings);
|
app.bindDialog('network-test', dialogBindings);
|
||||||
|
|
||||||
$dialog = $('#network-test-dialog');
|
$dialog = $('#network-test-dialog');
|
||||||
$btnCancel = $dialog.find('.btn-cancel');
|
|
||||||
$btnHelp = $dialog.find('.btn-help');
|
$btnHelp = $dialog.find('.btn-help');
|
||||||
$btnClose = $dialog.find('.btn-close');
|
$btnClose = $dialog.find('.btn-close');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
initializeStun(app);
|
initializeStun(app);
|
||||||
|
|
||||||
operationalEvents(app);
|
operationalEvents(app);
|
||||||
|
|
||||||
|
handleGettingStarted(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
function watchPreferencesEvent(app) {
|
function watchPreferencesEvent(app) {
|
||||||
|
|
@ -107,8 +109,11 @@
|
||||||
JK.UserDropdown = userDropdown;
|
JK.UserDropdown = userDropdown;
|
||||||
userDropdown.initialize(invitationDialog);
|
userDropdown.initialize(invitationDialog);
|
||||||
|
|
||||||
var whatsNextDialog = new JK.WhatsNextDialog(app);
|
var gettingStartedDialog = new JK.GettingStartedDialog(app);
|
||||||
whatsNextDialog.initialize(invitationDialog);
|
gettingStartedDialog.initialize(invitationDialog);
|
||||||
|
|
||||||
|
var joinTestSessionDialog = new JK.JoinTestSessionDialog(app);
|
||||||
|
joinTestSessionDialog.initialize();
|
||||||
|
|
||||||
var videoDialog = new JK.VideoDialog(app);
|
var videoDialog = new JK.VideoDialog(app);
|
||||||
videoDialog.initialize();
|
videoDialog.initialize();
|
||||||
|
|
@ -167,7 +172,18 @@
|
||||||
JK.JamServer.registerMessageCallback(JK.MessageType.STOP_APPLICATION, function(header, payload) {
|
JK.JamServer.registerMessageCallback(JK.MessageType.STOP_APPLICATION, function(header, payload) {
|
||||||
context.jamClient.ShutdownApplication();
|
context.jamClient.ShutdownApplication();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGettingStarted(app) {
|
||||||
|
app.user()
|
||||||
|
.done(function(userProfile) {
|
||||||
|
if (userProfile.show_whats_next &&
|
||||||
|
window.location.pathname.indexOf(gon.client_path) == 0 &&
|
||||||
|
!app.layout.isDialogShowing('getting-started'))
|
||||||
|
{
|
||||||
|
app.layout.showDialog('getting-started');
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
})(window, jQuery);
|
})(window, jQuery);
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
var logger = context.JK.logger;
|
var logger = context.JK.logger;
|
||||||
var rest = context.JK.Rest();
|
var rest = context.JK.Rest();
|
||||||
|
var EVENTS = context.JK.EVENTS;
|
||||||
var musicians = {};
|
var musicians = {};
|
||||||
var musicianList;
|
var musicianList;
|
||||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||||
|
|
@ -16,60 +17,139 @@
|
||||||
var $results = null;
|
var $results = null;
|
||||||
var $spinner = null;
|
var $spinner = null;
|
||||||
var $endMusicianList = null;
|
var $endMusicianList = null;
|
||||||
|
var $templateAccountSessionLatency = null;
|
||||||
var helpBubble = context.JK.HelpBubbleHelper;
|
var helpBubble = context.JK.HelpBubbleHelper;
|
||||||
var sessionUtils = context.JK.SessionUtils;
|
var sessionUtils = context.JK.SessionUtils;
|
||||||
|
var $musicianSearchCity = null;
|
||||||
|
var $musicianFilterCity = null;
|
||||||
|
var $musicianChangeFilterCity = null;
|
||||||
|
var $musicianQueryScore = null;
|
||||||
|
var $musicianDistance = null;
|
||||||
|
var $musicianLatencyOrDistanceLabel = null;
|
||||||
|
var $refreshBtn = null;
|
||||||
|
var searchLocationOverride = null;
|
||||||
|
var currentRequest = null;
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
$spinner.show();
|
var options = {
|
||||||
did_show_musician_page = true;
|
srch_m: 1,
|
||||||
var queryString = 'srch_m=1&page=' + page_num + '&';
|
page: page_num
|
||||||
|
}
|
||||||
|
|
||||||
// order by
|
// order by
|
||||||
var orderby = $('#musician_order_by').val();
|
var orderby = $('#musician_order_by').val();
|
||||||
if (typeof orderby != 'undefined' && orderby.length > 0) {
|
if (typeof orderby != 'undefined' && orderby.length > 0) {
|
||||||
queryString += "orderby=" + orderby + '&';
|
options['orderby'] = orderby;
|
||||||
}
|
}
|
||||||
|
|
||||||
// instrument filter
|
// instrument filter
|
||||||
var instrument = $('#musician_instrument').val();
|
var instrument = $('#musician_instrument').val();
|
||||||
if (typeof instrument != 'undefined' && !(instrument === '')) {
|
if (typeof instrument != 'undefined' && !(instrument === '')) {
|
||||||
queryString += "instrument=" + instrument + '&';
|
options['instrument'] = instrument;
|
||||||
}
|
}
|
||||||
|
|
||||||
// score filter
|
// score filter
|
||||||
var query_param = $('#musician_query_score').val();
|
var query_param = $musicianQueryScore.val();
|
||||||
if (query_param !== null) {
|
if (query_param !== null) {
|
||||||
queryString += "score_limit=" + query_param + '&';
|
options['score_limit'] = query_param;
|
||||||
}
|
}
|
||||||
rest.searchMusicians(queryString)
|
|
||||||
|
var distance = $musicianDistance.val();
|
||||||
|
if (distance !== null) {
|
||||||
|
options['distance'] = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(searchLocationOverride) {
|
||||||
|
options['country'] = searchLocationOverride.countrycode;
|
||||||
|
options['region'] = searchLocationOverride.regioncode;
|
||||||
|
options['city'] = searchLocationOverride.city;
|
||||||
|
}
|
||||||
|
|
||||||
|
$spinner.show();
|
||||||
|
$refreshBtn.addClass('disabled')
|
||||||
|
currentRequest = rest.searchMusicians(options)
|
||||||
.done(afterLoadMusicians)
|
.done(afterLoadMusicians)
|
||||||
.fail(app.ajaxError)
|
.fail(function(jqXHR) {
|
||||||
.always(function() {$spinner.hide()})
|
if(jqXHR.status === 0 && jqXHR.statusText === 'abort') {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
app.ajaxError(arguments);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.always(function() {currentRequest = null; $spinner.hide(); $refreshBtn.removeClass('disabled')})
|
||||||
|
}
|
||||||
|
|
||||||
|
function abortCurrentRequest() {
|
||||||
|
if(currentRequest) {
|
||||||
|
currentRequest.abort()
|
||||||
|
currentRequest = null;
|
||||||
|
$spinner.hide();
|
||||||
|
$refreshBtn.removeClass('disabled')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshDisplay() {
|
function refreshDisplay() {
|
||||||
|
abortCurrentRequest();
|
||||||
clearResults();
|
clearResults();
|
||||||
|
setupSearch();
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user clicked refresh
|
||||||
|
function manualRefresh() {
|
||||||
|
if(!$refreshBtn.is('.disabled')) {
|
||||||
|
refreshDisplay();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeSearchLocation() {
|
||||||
|
app.layout.showDialog('change-search-location').one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||||
|
if(data.canceled) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
searchLocationOverride = data.result;
|
||||||
|
displayUserCity();
|
||||||
|
refreshDisplay();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayUserCity() {
|
||||||
|
app.user().done(function(user) {
|
||||||
|
var location = searchLocationOverride || user.location;
|
||||||
|
var unknown = 'unknown location';
|
||||||
|
var result = unknown;
|
||||||
|
if(location) {
|
||||||
|
var region = location['region'] ? location['region'] : location['regioncode']
|
||||||
|
if(!region) { region = 'n/a'; }
|
||||||
|
var city = location['city'];
|
||||||
|
result = city + ', ' + region;
|
||||||
|
}
|
||||||
|
$musicianFilterCity.text(result);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function afterLoadMusicians(mList) {
|
function afterLoadMusicians(mList) {
|
||||||
|
did_show_musician_page = true;
|
||||||
|
|
||||||
// display the 'no musicians' banner if appropriate
|
// display the 'no musicians' banner if appropriate
|
||||||
var $noMusiciansFound = $('#musicians-none-found');
|
var $noMusiciansFound = $('#musicians-none-found');
|
||||||
musicianList = mList;
|
musicianList = mList;
|
||||||
|
|
||||||
|
if (musicianList.musicians.length == 0) {
|
||||||
// @FIXME: This needs to pivot on musicianList.musicians.length
|
|
||||||
if (musicianList.length == 0) {
|
|
||||||
$noMusiciansFound.show();
|
$noMusiciansFound.show();
|
||||||
musicians = [];
|
musicians = [];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$noMusiciansFound.hide();
|
$noMusiciansFound.hide();
|
||||||
musicians = musicianList['musicians'];
|
musicians = musicianList.musicians;
|
||||||
if (!(typeof musicians === 'undefined')) {
|
if (!(typeof musicians === 'undefined')) {
|
||||||
$('#musician-filter-city').text(musicianList['city']);
|
if (-1 == page_count) {
|
||||||
if (0 == page_count) {
|
|
||||||
page_count = musicianList['page_count'];
|
page_count = musicianList['page_count'];
|
||||||
}
|
}
|
||||||
renderMusicians();
|
renderMusicians();
|
||||||
|
|
@ -102,7 +182,6 @@
|
||||||
function renderMusicians() {
|
function renderMusicians() {
|
||||||
var ii, len;
|
var ii, len;
|
||||||
var mTemplate = $('#template-find-musician-row').html();
|
var mTemplate = $('#template-find-musician-row').html();
|
||||||
var fTemplate = $('#template-musician-follow-info').html();
|
|
||||||
var aTemplate = $('#template-musician-action-btns').html();
|
var aTemplate = $('#template-musician-action-btns').html();
|
||||||
var mVals, musician, renderings = '';
|
var mVals, musician, renderings = '';
|
||||||
var instr_logos, instr;
|
var instr_logos, instr;
|
||||||
|
|
@ -122,19 +201,6 @@
|
||||||
}
|
}
|
||||||
instr_logos += '<img src="' + instr + '"/>';
|
instr_logos += '<img src="' + instr + '"/>';
|
||||||
}
|
}
|
||||||
follows = '';
|
|
||||||
followVals = {};
|
|
||||||
for (var jj = 0, ilen = musician['followings'].length; jj < ilen; jj++) {
|
|
||||||
aFollow = musician['followings'][jj];
|
|
||||||
followVals = {
|
|
||||||
user_id: aFollow.user_id,
|
|
||||||
musician_name: aFollow.name,
|
|
||||||
profile_url: '/client#/profile/' + aFollow.user_id,
|
|
||||||
avatar_url: context.JK.resolveAvatarUrl(aFollow.photo_url)
|
|
||||||
};
|
|
||||||
follows += context.JK.fillTemplate(fTemplate, followVals);
|
|
||||||
if (2 == jj) break;
|
|
||||||
}
|
|
||||||
var actionVals = {
|
var actionVals = {
|
||||||
profile_url: "/client#/profile/" + musician.id,
|
profile_url: "/client#/profile/" + musician.id,
|
||||||
friend_class: 'button-' + (musician['is_friend'] ? 'grey' : 'orange'),
|
friend_class: 'button-' + (musician['is_friend'] ? 'grey' : 'orange'),
|
||||||
|
|
@ -147,9 +213,12 @@
|
||||||
};
|
};
|
||||||
var musician_actions = context.JK.fillTemplate(aTemplate, actionVals);
|
var musician_actions = context.JK.fillTemplate(aTemplate, actionVals);
|
||||||
|
|
||||||
var full_score = musician['full_score'];
|
var latencyBadge = context._.template(
|
||||||
|
$templateAccountSessionLatency.html(),
|
||||||
|
$.extend(sessionUtils.createLatency(musician), musician),
|
||||||
|
{variable: 'data'}
|
||||||
|
);
|
||||||
|
|
||||||
var scoreInfo = sessionUtils.scoreInfo(full_score, false)
|
|
||||||
mVals = {
|
mVals = {
|
||||||
avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
|
avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
|
||||||
profile_url: "/client#/profile/" + musician.id,
|
profile_url: "/client#/profile/" + musician.id,
|
||||||
|
|
@ -162,12 +231,9 @@
|
||||||
recording_count: musician['recording_count'],
|
recording_count: musician['recording_count'],
|
||||||
session_count: musician['session_count'],
|
session_count: musician['session_count'],
|
||||||
musician_id: musician['id'],
|
musician_id: musician['id'],
|
||||||
musician_follow_template: follows,
|
|
||||||
musician_action_template: musician_actions,
|
musician_action_template: musician_actions,
|
||||||
musician_one_way_score: score_to_text(full_score),
|
latency_badge: latencyBadge,
|
||||||
musician_score_color: scoreInfo.icon_name,
|
musician_first_name: musician['first_name']
|
||||||
musician_score_color_alt: scoreInfo.description,
|
|
||||||
latency_style: scoreInfo.latency_style
|
|
||||||
};
|
};
|
||||||
var $rendering = $(context.JK.fillTemplate(mTemplate, mVals))
|
var $rendering = $(context.JK.fillTemplate(mTemplate, mVals))
|
||||||
|
|
||||||
|
|
@ -178,9 +244,10 @@
|
||||||
context.JK.helpBubble($('.friend-count', $rendering), 'musician-friend-count', {}, options);
|
context.JK.helpBubble($('.friend-count', $rendering), 'musician-friend-count', {}, options);
|
||||||
context.JK.helpBubble($('.recording-count', $rendering), 'musician-recording-count', {}, options);
|
context.JK.helpBubble($('.recording-count', $rendering), 'musician-recording-count', {}, options);
|
||||||
context.JK.helpBubble($('.session-count', $rendering), 'musician-session-count', {}, options);
|
context.JK.helpBubble($('.session-count', $rendering), 'musician-session-count', {}, options);
|
||||||
helpBubble.scoreBreakdown($('.score-count', $rendering), false, full_score, myAudioLatency, musician['audio_latency'], musician['score'], scoreOptions);
|
helpBubble.scoreBreakdown($('.latency', $rendering), false, musician['full_score'], myAudioLatency, musician['audio_latency'], musician['score'], scoreOptions);
|
||||||
|
|
||||||
$results.append($rendering);
|
$results.append($rendering);
|
||||||
|
$rendering.find('.biography').dotdotdot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -195,7 +262,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterShow(data) {
|
function afterShow(data) {
|
||||||
refreshDisplay();
|
if(!did_show_musician_page) {
|
||||||
|
// cache page because query is slow, and user may have paginated a bunch
|
||||||
|
refreshDisplay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearResults() {
|
function clearResults() {
|
||||||
|
|
@ -203,7 +273,23 @@
|
||||||
$('#musician-filter-results .musician-list-result').remove();
|
$('#musician-filter-results .musician-list-result').remove();
|
||||||
$endMusicianList.hide();
|
$endMusicianList.hide();
|
||||||
page_num = 1;
|
page_num = 1;
|
||||||
page_count = 0;
|
page_count = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupSearch() {
|
||||||
|
var orderby = $('#musician_order_by').val();
|
||||||
|
if(orderby == 'distance') {
|
||||||
|
$musicianSearchCity.show();
|
||||||
|
$musicianDistance.closest('.easydropdown-wrapper').show();
|
||||||
|
$musicianQueryScore.closest('.easydropdown-wrapper').hide();
|
||||||
|
$musicianLatencyOrDistanceLabel.text('Distance:')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$musicianSearchCity.hide();
|
||||||
|
$musicianDistance.closest('.easydropdown-wrapper').hide();
|
||||||
|
$musicianQueryScore.closest('.easydropdown-wrapper').show();
|
||||||
|
$musicianLatencyOrDistanceLabel.text('Latency:')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function friendMusician(evt) {
|
function friendMusician(evt) {
|
||||||
|
|
@ -267,11 +353,18 @@
|
||||||
|
|
||||||
|
|
||||||
function events() {
|
function events() {
|
||||||
$('#musician_query_score').change(refreshDisplay);
|
$musicianQueryScore.change(refreshDisplay);
|
||||||
$('#musician_instrument').change(refreshDisplay);
|
$('#musician_instrument').change(refreshDisplay);
|
||||||
$('#musician_order_by').change(refreshDisplay);
|
$('#musician_order_by').change(refreshDisplay);
|
||||||
|
$musicianDistance.change(refreshDisplay);
|
||||||
|
$musicianChangeFilterCity.click(changeSearchLocation);
|
||||||
|
$refreshBtn.click(manualRefresh)
|
||||||
|
|
||||||
$('#musician-filter-results').closest('.content-body-scroller').bind('scroll', function () {
|
$('#musician-filter-results').closest('.content-body-scroller').bind('scroll', function () {
|
||||||
|
|
||||||
|
// do not check scroll when filling out initial results, which we can tell if page_count == -1
|
||||||
|
if(page_count == -1) {return};
|
||||||
|
|
||||||
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
|
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
|
||||||
if (page_num < page_count) {
|
if (page_num < page_count) {
|
||||||
page_num += 1;
|
page_num += 1;
|
||||||
|
|
@ -298,8 +391,17 @@
|
||||||
$results = $screen.find('#musician-filter-results');
|
$results = $screen.find('#musician-filter-results');
|
||||||
$spinner = $screen.find('.paginate-wait')
|
$spinner = $screen.find('.paginate-wait')
|
||||||
$endMusicianList = $screen.find('#end-of-musician-list')
|
$endMusicianList = $screen.find('#end-of-musician-list')
|
||||||
|
$templateAccountSessionLatency = $("#template-account-session-latency")
|
||||||
|
$musicianSearchCity = $('#musician-search-city');
|
||||||
|
$musicianFilterCity = $('#musician-filter-city');
|
||||||
|
$musicianChangeFilterCity = $('#musician-change-filter-city');
|
||||||
|
$musicianQueryScore = $('#musician_query_score');
|
||||||
|
$musicianDistance = $('#musician_distance');
|
||||||
|
$musicianLatencyOrDistanceLabel = $screen.find('.latency-or-distance')
|
||||||
|
$refreshBtn = $screen.find('.btn-refresh-entries');
|
||||||
events();
|
events();
|
||||||
|
setupSearch();
|
||||||
|
displayUserCity();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialize = initialize;
|
this.initialize = initialize;
|
||||||
|
|
|
||||||
|
|
@ -1189,13 +1189,10 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchMusicians(queryString) {
|
function searchMusicians(query) {
|
||||||
// squelch nulls and undefines
|
|
||||||
queryString = !!queryString ? queryString : "";
|
|
||||||
|
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
type: "GET",
|
type: "GET",
|
||||||
url: "/api/search.json?" + queryString
|
url: "/api/search.json?" + $.param(query)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,16 @@
|
||||||
context.location = url;
|
context.location = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateUserModel = function(userUpdateData) {
|
||||||
|
|
||||||
|
var update = rest.updateUser(userUpdateData)
|
||||||
|
update.done(function() {
|
||||||
|
logger.debug("updating user info")
|
||||||
|
userDeferred = update; // update the global user object if this succeeded
|
||||||
|
})
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
// call .done/.fail on this to wait for safe user data
|
// call .done/.fail on this to wait for safe user data
|
||||||
this.user = function() {
|
this.user = function() {
|
||||||
return userDeferred;
|
return userDeferred;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//= require bind-polyfill
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery.monkeypatch
|
//= require jquery.monkeypatch
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
|
|
|
||||||
|
|
@ -427,15 +427,40 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog(dialog) {
|
function cancel(evt) {
|
||||||
|
var $target = $(evt.currentTarget).closest('[layout]');
|
||||||
|
var layoutId = $target.attr('layout-id');
|
||||||
|
var isDialog = ($target.attr('layout') === 'dialog');
|
||||||
|
if (isDialog) {
|
||||||
|
cancelDialog(layoutId);
|
||||||
|
} else {
|
||||||
|
// ?
|
||||||
|
logger.warn("unable to handle cancel layout-action for %o", $target)
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelDialog(dialog) {
|
||||||
|
logger.debug("cancelling dialog: " + dialog);
|
||||||
|
var $dialog = $('[layout-id="' + dialog + '"]');
|
||||||
|
var result = dialogEvent(dialog, 'onCancel');
|
||||||
|
if(result !== false) {
|
||||||
|
closeDialog(dialog, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.debug("dialog refused cancel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDialog(dialog, canceled) {
|
||||||
logger.debug("closing dialog: " + dialog);
|
logger.debug("closing dialog: " + dialog);
|
||||||
var $dialog = $('[layout-id="' + dialog + '"]');
|
var $dialog = $('[layout-id="' + dialog + '"]');
|
||||||
dialogEvent(dialog, 'beforeHide');
|
dialogEvent(dialog, 'beforeHide');
|
||||||
var $overlay = $('.dialog-overlay');
|
var $overlay = $('.dialog-overlay');
|
||||||
unstackDialogs($overlay);
|
unstackDialogs($overlay);
|
||||||
$dialog.hide();
|
$dialog.hide();
|
||||||
$dialog.triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length, result: $dialog.data('result') });
|
$dialog.triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length, result: $dialog.data('result'), canceled: canceled });
|
||||||
$(context).triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length, result: $dialog.data('result') });
|
$(context).triggerHandler(EVENTS.DIALOG_CLOSED, {name: dialog, dialogCount: openDialogs.length, result: $dialog.data('result'), canceled: canceled });
|
||||||
dialogEvent(dialog, 'afterHide');
|
dialogEvent(dialog, 'afterHide');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,8 +575,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if no arguments passed, then see if any dialog is showing
|
||||||
|
// if string passed, see if dialog is showing (even if buried) of a given name
|
||||||
function isDialogShowing() {
|
function isDialogShowing() {
|
||||||
return openDialogs.length > 0;
|
if(arguments.length == 1) {
|
||||||
|
// user passed in dialog id
|
||||||
|
var dialogId = arguments[0];
|
||||||
|
context._.each(openDialogs, function(dialog) {
|
||||||
|
if($(dialog).attr('layout-id') == dialogId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// user passed in nothing
|
||||||
|
return openDialogs.length > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function currentDialog() {
|
function currentDialog() {
|
||||||
|
|
@ -690,7 +730,7 @@
|
||||||
// var step = 0;
|
// var step = 0;
|
||||||
//setWizardStep(step);
|
//setWizardStep(step);
|
||||||
//wizardShowFunctions[step]();
|
//wizardShowFunctions[step]();
|
||||||
showDialog('gear-wizard');
|
return showDialog('gear-wizard');
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWizardStep(targetStepId) {
|
function setWizardStep(targetStepId) {
|
||||||
|
|
@ -718,6 +758,22 @@
|
||||||
context.JK.GA.virtualPageView(location.pathname + location.search + location.hash);
|
context.JK.GA.virtualPageView(location.pathname + location.search + location.hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onHandleKey(e) {
|
||||||
|
|
||||||
|
if (e.keyCode == 27 /** esc */)
|
||||||
|
{
|
||||||
|
if(isDialogShowing()) {
|
||||||
|
var $dialog = currentDialog();
|
||||||
|
if(!$dialog) {
|
||||||
|
logger.error("unable to find current dialog on ESC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelDialog($dialog.attr('layout-id'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleDialogState() {
|
function handleDialogState() {
|
||||||
var rawDialogState = $.cookie('dialog_state');
|
var rawDialogState = $.cookie('dialog_state');
|
||||||
try {
|
try {
|
||||||
|
|
@ -756,11 +812,13 @@
|
||||||
});
|
});
|
||||||
$('body').on('click', '[layout-link]', linkClicked);
|
$('body').on('click', '[layout-link]', linkClicked);
|
||||||
$('[layout-action="close"]').on('click', close);
|
$('[layout-action="close"]').on('click', close);
|
||||||
|
$('[layout-action="cancel"]').on('click', cancel);
|
||||||
$('[layout-sidebar-expander]').on('click', toggleSidebar);
|
$('[layout-sidebar-expander]').on('click', toggleSidebar);
|
||||||
$('[layout-panel="expanded"] [layout-panel="header"]').on('click', panelHeaderClicked);
|
$('[layout-panel="expanded"] [layout-panel="header"]').on('click', panelHeaderClicked);
|
||||||
$('[layout-wizard-link]').on('click', wizardLinkClicked);
|
$('[layout-wizard-link]').on('click', wizardLinkClicked);
|
||||||
$('[tab-target]').on('click', tabClicked);
|
$('[tab-target]').on('click', tabClicked);
|
||||||
$(context).on('hashchange', trackLocationChange);
|
$(context).on('hashchange', trackLocationChange);
|
||||||
|
$(document).keyup(onHandleKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public functions
|
// public functions
|
||||||
|
|
@ -960,6 +1018,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeDialog = closeDialog;
|
this.closeDialog = closeDialog;
|
||||||
|
this.cancelDialog = cancelDialog;
|
||||||
|
|
||||||
this.handleDialogState = handleDialogState;
|
this.handleDialogState = handleDialogState;
|
||||||
this.queueDialog = queueDialog;
|
this.queueDialog = queueDialog;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,271 @@
|
||||||
|
(function (context, $) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
context.JK = context.JK || {};
|
||||||
|
|
||||||
|
context.JK.SelectLocation = Class.extend({
|
||||||
|
|
||||||
|
init: function ($countries, $regions, $cities, app) {
|
||||||
|
this.api = context.JK.Rest();
|
||||||
|
this.logger = context.JK.logger;
|
||||||
|
this.loadingCitiesData = false;
|
||||||
|
this.loadingRegionsData = false;
|
||||||
|
this.loadingCountriesData = false;
|
||||||
|
this.nilOptionStr = '<option value=""></option>';
|
||||||
|
this.nilOptionText = 'n/a';
|
||||||
|
this.$countries = $countries;
|
||||||
|
this.$regions = $regions;
|
||||||
|
this.$cities = $cities;
|
||||||
|
this.app = app;
|
||||||
|
|
||||||
|
$countries.on('change', function (evt) {
|
||||||
|
evt.stopPropagation();
|
||||||
|
this.handleCountryChanged();
|
||||||
|
return false;
|
||||||
|
}.bind(this));
|
||||||
|
$regions.on('change', function (evt) {
|
||||||
|
evt.stopPropagation();
|
||||||
|
this.handleRegionChanged();
|
||||||
|
return false;
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
load: function (country, region, city) {
|
||||||
|
|
||||||
|
this.country = country;
|
||||||
|
this.region = region;
|
||||||
|
this.city = city;
|
||||||
|
|
||||||
|
if (!country) {
|
||||||
|
// this case shouldn't happen because sign up makes you pick a location. This is just 'in case', so that the UI is more error-resilient
|
||||||
|
this.logger.debug("user has no specified country: " + country)
|
||||||
|
country = 'US';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingCountriesData = true;
|
||||||
|
this.loadingRegionsData = true;
|
||||||
|
this.loadingCitiesData = true;
|
||||||
|
|
||||||
|
// make the 3 slower requests, which only matter if the user wants to affect their ISP or location
|
||||||
|
|
||||||
|
this.api.getCountries()
|
||||||
|
.done(function (countriesx) {
|
||||||
|
this.populateCountriesx(countriesx["countriesx"], country);
|
||||||
|
}.bind(this))
|
||||||
|
.fail(this.app.ajaxError)
|
||||||
|
.always(function () {
|
||||||
|
this.loadingCountriesData = false;
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
|
if (country) {
|
||||||
|
this.api.getRegions({ country: country })
|
||||||
|
.done(function (regions) {
|
||||||
|
this.populateRegions(regions["regions"], region);
|
||||||
|
}.bind(this))
|
||||||
|
.fail(this.regionListFailure.bind(this))
|
||||||
|
.always(function () {
|
||||||
|
this.loadingRegionsData = false;
|
||||||
|
}.bind(this))
|
||||||
|
|
||||||
|
if (region) {
|
||||||
|
this.api.getCities({ country: country, region: region })
|
||||||
|
.done(function (cities) {
|
||||||
|
this.populateCities(cities["cities"], this.city)
|
||||||
|
}.bind(this))
|
||||||
|
.fail(this.cityListFailure.bind(this))
|
||||||
|
.always(function () {
|
||||||
|
this.loadingCitiesData = false;
|
||||||
|
}.bind(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCountryChanged: function () {
|
||||||
|
var selectedCountry = this.$countries.val()
|
||||||
|
var selectedRegion = this.$regions.val()
|
||||||
|
var cityElement = this.$cities
|
||||||
|
|
||||||
|
this.updateRegionList(selectedCountry, this.$regions);
|
||||||
|
this.updateCityList(selectedCountry, null, cityElement);
|
||||||
|
},
|
||||||
|
handleRegionChanged: function () {
|
||||||
|
var selectedCountry = this.$countries.val()
|
||||||
|
var selectedRegion = this.$regions.val()
|
||||||
|
var cityElement = this.$cities;
|
||||||
|
|
||||||
|
this.updateCityList(selectedCountry, selectedRegion, cityElement);
|
||||||
|
},
|
||||||
|
updateRegionList: function (selectedCountry, regionElement) {
|
||||||
|
// only update region
|
||||||
|
if (selectedCountry) {
|
||||||
|
// set city disabled while updating
|
||||||
|
regionElement.attr('disabled', true).easyDropDown('disable');
|
||||||
|
this.loadingRegionsData = true;
|
||||||
|
|
||||||
|
regionElement.children().remove()
|
||||||
|
regionElement.append($(this.nilOptionStr).text('loading...'))
|
||||||
|
|
||||||
|
this.api.getRegions({ country: selectedCountry })
|
||||||
|
.done(this.getRegionsDone.bind(this))
|
||||||
|
.error(function (err) {
|
||||||
|
regionElement.children().remove()
|
||||||
|
regionElement.append($(this.nilOptionStr).text(this.nilOptionText))
|
||||||
|
}.bind(this))
|
||||||
|
.always(function () {
|
||||||
|
console.log("regions load: this.loadingRegionsData; " + this.loadingRegionsData)
|
||||||
|
this.loadingRegionsData = false;
|
||||||
|
}.bind(this))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regionElement.children().remove()
|
||||||
|
regionElement.append($(this.nilOptionStr).text(this.nilOptionText))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateCityList: function (selectedCountry, selectedRegion, cityElement) {
|
||||||
|
|
||||||
|
// only update cities
|
||||||
|
if (selectedCountry && selectedRegion) {
|
||||||
|
// set city disabled while updating
|
||||||
|
cityElement.attr('disabled', true).easyDropDown('disable');
|
||||||
|
this.loadingCitiesData = true;
|
||||||
|
|
||||||
|
cityElement.children().remove()
|
||||||
|
cityElement.append($(this.nilOptionStr).text('loading...'))
|
||||||
|
|
||||||
|
this.api.getCities({ country: selectedCountry, region: selectedRegion })
|
||||||
|
.done(this.getCitiesDone.bind(this))
|
||||||
|
.error(function (err) {
|
||||||
|
cityElement.children().remove()
|
||||||
|
cityElement.append($(this.nilOptionStr).text(this.nilOptionText))
|
||||||
|
}.bind(this))
|
||||||
|
.always(function () {
|
||||||
|
this.loadingCitiesData = false;
|
||||||
|
}.bind(this))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cityElement.children().remove();
|
||||||
|
cityElement.append($(this.nilOptionStr).text(this.nilOptionText));
|
||||||
|
context.JK.dropdown(cityElement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getCitiesDone: function (data) {
|
||||||
|
this.populateCities(data['cities'], this.city);
|
||||||
|
},
|
||||||
|
getRegionsDone: function (data) {
|
||||||
|
this.populateRegions(data['regions'], this.region);
|
||||||
|
this.updateCityList(this.$countries.val(), this.$regions.val(), this.$cities);
|
||||||
|
},
|
||||||
|
writeCountry: function (index, countryx) {
|
||||||
|
if (!countryx.countrycode) return;
|
||||||
|
|
||||||
|
var option = $(this.nilOptionStr);
|
||||||
|
option.text(countryx.countryname);
|
||||||
|
option.attr("value", countryx.countrycode);
|
||||||
|
|
||||||
|
if (countryx.countrycode == this.country) {
|
||||||
|
this.foundCountry = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$countries.append(option);
|
||||||
|
},
|
||||||
|
populateCountriesx: function (countriesx) {
|
||||||
|
|
||||||
|
// countriesx has the format [{countrycode: "US", countryname: "United States"}, ...]
|
||||||
|
|
||||||
|
this.foundCountry = false;
|
||||||
|
this.$countries.children().remove();
|
||||||
|
|
||||||
|
var nilOption = $(this.nilOptionStr);
|
||||||
|
nilOption.text(this.nilOptionText);
|
||||||
|
this.$countries.append(nilOption);
|
||||||
|
|
||||||
|
$.each(countriesx, this.writeCountry.bind(this));
|
||||||
|
|
||||||
|
if (!this.foundCountry) {
|
||||||
|
this.logger.warn("user has no country in the database. user's country:" + this.country)
|
||||||
|
// in this case, the user has a country that is not in the database
|
||||||
|
// this can happen in a development/test scenario, but let's assume it can
|
||||||
|
// happen in production too.
|
||||||
|
var option = $(this.nilOptionStr);
|
||||||
|
option.text(this.country);
|
||||||
|
option.attr("value", this.country);
|
||||||
|
this.$countries.append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$countries.val(this.country);
|
||||||
|
this.$countries.attr("disabled", null).easyDropDown('enable');
|
||||||
|
|
||||||
|
context.JK.dropdown(this.$countries);
|
||||||
|
},
|
||||||
|
|
||||||
|
writeRegion: function (index, region) {
|
||||||
|
if (!region) return;
|
||||||
|
|
||||||
|
var option = $(this.nilOptionStr)
|
||||||
|
option.text(region['name'])
|
||||||
|
option.attr("value", region['region'])
|
||||||
|
|
||||||
|
this.$regions.append(option)
|
||||||
|
},
|
||||||
|
|
||||||
|
populateRegions: function (regions, userRegion) {
|
||||||
|
this.$regions.children().remove()
|
||||||
|
|
||||||
|
var nilOption = $(this.nilOptionStr);
|
||||||
|
nilOption.text(this.nilOptionText);
|
||||||
|
this.$regions.append(nilOption);
|
||||||
|
|
||||||
|
$.each(regions, this.writeRegion.bind(this))
|
||||||
|
|
||||||
|
this.$regions.val(userRegion)
|
||||||
|
this.$regions.attr("disabled", null).easyDropDown('enable');
|
||||||
|
|
||||||
|
context.JK.dropdown(this.$regions);
|
||||||
|
},
|
||||||
|
|
||||||
|
writeCity: function (index, city) {
|
||||||
|
if (!city) return;
|
||||||
|
|
||||||
|
var option = $(this.nilOptionStr)
|
||||||
|
option.text(city)
|
||||||
|
option.attr("value", city)
|
||||||
|
|
||||||
|
this.$cities.append(option)
|
||||||
|
},
|
||||||
|
|
||||||
|
populateCities: function (cities, userCity) {
|
||||||
|
this.$cities.children().remove();
|
||||||
|
|
||||||
|
var nilOption = $(this.nilOptionStr);
|
||||||
|
nilOption.text(this.nilOptionText);
|
||||||
|
this.$cities.append(nilOption);
|
||||||
|
|
||||||
|
$.each(cities, this.writeCity.bind(this))
|
||||||
|
|
||||||
|
this.$cities.val(userCity)
|
||||||
|
this.$cities.attr("disabled", null).easyDropDown('enable');
|
||||||
|
|
||||||
|
context.JK.dropdown(this.$cities);
|
||||||
|
},
|
||||||
|
|
||||||
|
regionListFailure: function (jqXHR, textStatus, errorThrown) {
|
||||||
|
if (jqXHR.status == 422) {
|
||||||
|
this.logger.debug("no regions found for country: " + this.country);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.app.ajaxError(arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cityListFailure: function (jqXHR, textStatus, errorThrown) {
|
||||||
|
if (jqXHR.status == 422) {
|
||||||
|
this.logger.debug("no cities found for country/region: " + this.country + "/" + this.region);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.app.ajaxError(arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})(window, jQuery);
|
||||||
|
|
||||||
|
|
@ -90,13 +90,16 @@
|
||||||
|
|
||||||
var $row = $(context.JK.fillTemplate($activeSessionTemplate.html(), sessionVals));
|
var $row = $(context.JK.fillTemplate($activeSessionTemplate.html(), sessionVals));
|
||||||
var $offsetParent = $(tbGroup).closest('.content');
|
var $offsetParent = $(tbGroup).closest('.content');
|
||||||
var $latencyBadge = $row.find('.latency-value');
|
var $latencyBadges = $row.find('.latency-value');
|
||||||
var full_score = $latencyBadge.attr('data-full-score') || null;
|
context._.each($latencyBadges, function(latencyBadge) {
|
||||||
var internet_score = $latencyBadge.attr('data-internet-score') || null;
|
var $latencyBadge = $(latencyBadge);
|
||||||
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
|
var full_score = $latencyBadge.attr('data-full-score') || null;
|
||||||
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
|
var internet_score = $latencyBadge.attr('data-internet-score') || null;
|
||||||
var scoreOptions = {offsetParent: $offsetParent};
|
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
|
||||||
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
|
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
|
||||||
|
var scoreOptions = {offsetParent: $offsetParent};
|
||||||
|
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
|
||||||
|
});
|
||||||
|
|
||||||
$(tbGroup).append($row);
|
$(tbGroup).append($row);
|
||||||
|
|
||||||
|
|
@ -200,13 +203,16 @@
|
||||||
var $row = $(context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals));
|
var $row = $(context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals));
|
||||||
|
|
||||||
var $offsetParent = $(tbGroup).closest('.content');
|
var $offsetParent = $(tbGroup).closest('.content');
|
||||||
var $latencyBadge = $row.find('.latency-value');
|
var $latencyBadges = $row.find('.latency-value');
|
||||||
var full_score = $latencyBadge.attr('data-full-score') || null;
|
context._.each($latencyBadges, function(latencyBadge) {
|
||||||
var internet_score = $latencyBadge.attr('data-internet-score') || null;
|
var $latencyBadge = $(latencyBadge);
|
||||||
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
|
var full_score = $latencyBadge.attr('data-full-score') || null;
|
||||||
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
|
var internet_score = $latencyBadge.attr('data-internet-score') || null;
|
||||||
var scoreOptions = {offsetParent: $offsetParent};
|
var audio_latency = $latencyBadge.attr('data-audio-latency') || null;
|
||||||
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
|
var latencyBadgeUserId = $latencyBadge.attr('data-user-id');
|
||||||
|
var scoreOptions = {offsetParent: $offsetParent};
|
||||||
|
helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// initial page load
|
// initial page load
|
||||||
|
|
|
||||||
|
|
@ -515,6 +515,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWindowBackgrounded(type, text) {
|
function onWindowBackgrounded(type, text) {
|
||||||
|
app.user()
|
||||||
|
.done(function(userProfile) {
|
||||||
|
if(userProfile.show_whats_next &&
|
||||||
|
window.location.pathname.indexOf(gon.client_path) == 0 &&
|
||||||
|
!app.layout.isDialogShowing('getting-started')) {
|
||||||
|
app.layout.showDialog('getting-started');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if(!inSession()) return;
|
if(!inSession()) return;
|
||||||
|
|
||||||
// the window was closed; just attempt to nav to home, which will cause all the right REST calls to happen
|
// the window was closed; just attempt to nav to home, which will cause all the right REST calls to happen
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
var rest = new JK.Rest();
|
var rest = new JK.Rest();
|
||||||
var userMe = null;
|
var userMe = null;
|
||||||
var invitationDialog = null;
|
var invitationDialog = null;
|
||||||
var notYetShownWhatsNext = true;
|
var nowYetShownGettingStarted = true;
|
||||||
|
|
||||||
function menuHoverIn() {
|
function menuHoverIn() {
|
||||||
$('ul.shortcuts', this).show();
|
$('ul.shortcuts', this).show();
|
||||||
|
|
@ -77,7 +77,6 @@
|
||||||
// TODO - Setting global variable for local user.
|
// TODO - Setting global variable for local user.
|
||||||
context.JK.userMe = r;
|
context.JK.userMe = r;
|
||||||
updateHeader();
|
updateHeader();
|
||||||
handleWhatsNext(userMe);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,17 +85,6 @@
|
||||||
showAvatar();
|
showAvatar();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWhatsNext(userProfile) {
|
|
||||||
if (notYetShownWhatsNext && gon.isNativeClient && userProfile.show_whats_next) {
|
|
||||||
notYetShownWhatsNext = false;
|
|
||||||
console.log("window.location.pathname", window.location.pathname, gon.client_path, window.location.pathname.indexOf(gon.client_url));
|
|
||||||
if(window.location.pathname.indexOf(gon.client_path) == 0) {
|
|
||||||
app.layout.showDialog('whatsNext');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initially show avatar
|
// initially show avatar
|
||||||
function showAvatar() {
|
function showAvatar() {
|
||||||
var photoUrl = context.JK.resolveAvatarUrl(userMe.photo_url);
|
var photoUrl = context.JK.resolveAvatarUrl(userMe.photo_url);
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
var helpText = context._.template($('#template-help-' + templateName).html(), data, { variable: 'data' });
|
var $template = $('#template-help-' + templateName);
|
||||||
|
if($template.length == 0) throw "no template by the name " + templateName;
|
||||||
|
var helpText = context._.template($template.html(), data, { variable: 'data' });
|
||||||
var holder = $('<div class="hover-bubble help-bubble"></div>');
|
var holder = $('<div class="hover-bubble help-bubble"></div>');
|
||||||
holder.append(helpText);
|
holder.append(helpText);
|
||||||
context.JK.hoverBubble($element, helpText, options);
|
context.JK.hoverBubble($element, helpText, options);
|
||||||
|
|
@ -136,7 +138,7 @@
|
||||||
if(!options) options = {};
|
if(!options) options = {};
|
||||||
options['trigger'] = 'none';
|
options['trigger'] = 'none';
|
||||||
options['clickAnywhereToClose'] = false
|
options['clickAnywhereToClose'] = false
|
||||||
if(!options['duration']) options['duration'] = 4000;
|
if(!options['duration']) options['duration'] = 6000;
|
||||||
|
|
||||||
var existingTimer = $element.data("prodTimer");
|
var existingTimer = $element.data("prodTimer");
|
||||||
if(existingTimer) {
|
if(existingTimer) {
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@
|
||||||
context.JK.onBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'voice_chat_helper', onInvalidAudioDevice);
|
context.JK.onBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'voice_chat_helper', onInvalidAudioDevice);
|
||||||
registerVuCallbacks();
|
registerVuCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
function beforeHide() {
|
function beforeHide() {
|
||||||
context.JK.offBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'voice_chat_helper', onInvalidAudioDevice);
|
context.JK.offBackendEvent(ALERT_NAMES.AUDIO_DEVICE_NOT_PRESENT, 'voice_chat_helper', onInvalidAudioDevice);
|
||||||
jamClient.FTUERegisterVUCallbacks('', '', '');
|
jamClient.FTUERegisterVUCallbacks('', '', '');
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//= require bind-polyfill
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery.monkeypatch
|
//= require jquery.monkeypatch
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
|
|
|
||||||
|
|
@ -475,42 +475,6 @@ div[layout-id="ftue3"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#whatsnext-dialog {
|
|
||||||
|
|
||||||
height:auto;
|
|
||||||
|
|
||||||
.ftue-inner h2 {
|
|
||||||
font-weight:normal;
|
|
||||||
color:#ed3618;
|
|
||||||
margin-bottom:6px;
|
|
||||||
font-size:1.7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ftue-inner table td.whatsnext {
|
|
||||||
font-size:12px;
|
|
||||||
padding:10px;
|
|
||||||
width:50%;
|
|
||||||
font-weight:300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ftue-inner table td.whatsnext {
|
|
||||||
font-size:12px;
|
|
||||||
padding:10px;
|
|
||||||
width:50%;
|
|
||||||
font-weight:300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ftue-inner table a {
|
|
||||||
text-decoration:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ftue-inner table {
|
|
||||||
border-collapse:separate;
|
|
||||||
border-spacing: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.ftue-inner {
|
.ftue-inner {
|
||||||
width:750px;
|
width:750px;
|
||||||
padding:25px;
|
padding:25px;
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,4 @@
|
||||||
.filter-element {
|
@import 'common';
|
||||||
float:left;
|
|
||||||
margin-left: 5px;
|
|
||||||
|
|
||||||
&.wrapper {
|
|
||||||
margin-top: 5px;
|
|
||||||
&.right {
|
|
||||||
float: right;
|
|
||||||
> a {
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @FIXME labeel is overriding from #session-controls.
|
|
||||||
&.desc {
|
|
||||||
margin-top: 3px;
|
|
||||||
padding-top: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ .easydropdown-wrapper {
|
|
||||||
float:left;
|
|
||||||
margin-left:2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#musicians-screen {
|
#musicians-screen {
|
||||||
|
|
||||||
|
|
@ -35,6 +11,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-refresh-holder {
|
||||||
|
float:right;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
.paginate-wait {
|
.paginate-wait {
|
||||||
display:none;
|
display:none;
|
||||||
margin:auto;
|
margin:auto;
|
||||||
|
|
@ -46,26 +27,144 @@
|
||||||
vertical-align:top;
|
vertical-align:top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
.musician-avatar {
|
||||||
|
width:63px;
|
||||||
|
}
|
||||||
|
|
||||||
#musician-filter-results {
|
.musician-profile, .musician-stats {
|
||||||
margin: 0 10px 0px 10px;
|
width:150px;
|
||||||
}
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.musician-wrapper {
|
.musician-stats {
|
||||||
-ms-overflow-style: none;
|
margin-top:10px;
|
||||||
overflow: initial;
|
}
|
||||||
height: 100%;
|
.musician-info {
|
||||||
width: 100%;
|
margin-top: 12px;
|
||||||
}
|
margin-right:0;
|
||||||
|
}
|
||||||
|
|
||||||
.musician-list-result {
|
.button-row {
|
||||||
padding-top: 5px;
|
float:none;
|
||||||
padding-right: 5px;
|
}
|
||||||
padding-left: 5px;
|
|
||||||
|
.latency-holder {
|
||||||
table.musicians {
|
position:absolute;
|
||||||
margin-top:12px;
|
top: 53px;
|
||||||
|
width:100%;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency {
|
||||||
|
min-width: 50px;
|
||||||
|
display:inline-block;
|
||||||
|
padding:4px;
|
||||||
|
font-family:Arial, Helvetica, sans-serif;
|
||||||
|
font-weight:200;
|
||||||
|
font-size:11px;
|
||||||
|
text-align:center;
|
||||||
|
@include border-radius(2px);
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-unknown {
|
||||||
|
background-color:$latencyBadgeUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-unacceptable {
|
||||||
|
background-color:$latencyBadgeUnacceptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-good {
|
||||||
|
background-color:$latencyBadgeGood;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-fair{
|
||||||
|
background-color:$latencyBadgeFair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-poor {
|
||||||
|
background-color:$latencyBadgePoor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
.latency {
|
||||||
|
font-size: 15px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 3px;
|
||||||
|
width: 100%;
|
||||||
|
@include border-radius(2px);
|
||||||
|
width:130px;
|
||||||
|
position:absolute;
|
||||||
|
top: 63px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
.biography {
|
||||||
|
height:73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.musician-wrapper {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
overflow: initial;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.musician-latency {
|
||||||
|
width: 136px;
|
||||||
|
height:100px;
|
||||||
|
margin-right:35px;
|
||||||
|
text-align:center;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-help {
|
||||||
|
margin-top:8px;
|
||||||
|
line-height:14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.musician-list-result {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
height: 123px;
|
||||||
|
|
||||||
|
table.musicians {
|
||||||
|
margin-top:12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#musician-filter-results {
|
||||||
|
margin: 0 10px 0px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-element {
|
||||||
|
float:left;
|
||||||
|
margin-left: 5px;
|
||||||
|
|
||||||
|
&.wrapper {
|
||||||
|
margin-top: 5px;
|
||||||
|
&.right {
|
||||||
|
float: right;
|
||||||
|
> a {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @FIXME labeel is overriding from #session-controls.
|
||||||
|
&.desc {
|
||||||
|
margin-top: 3px;
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .easydropdown-wrapper {
|
||||||
|
float:left;
|
||||||
|
margin-left:2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,18 @@ small, .small {font-size:11px;}
|
||||||
text-decoration:none;
|
text-decoration:none;
|
||||||
line-height:12px;
|
line-height:12px;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: transparent;
|
||||||
|
border: solid 1px #868686;
|
||||||
|
outline: solid 2px transparent;
|
||||||
|
color:#ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled:hover {
|
||||||
|
background-color: #515151;
|
||||||
|
color:#ccc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-grey:hover {
|
.button-grey:hover {
|
||||||
|
|
@ -215,8 +227,6 @@ small, .small {font-size:11px;}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled:hover {
|
&.disabled:hover {
|
||||||
//background-color:darken(#f16750, 20%);
|
|
||||||
//color:#FFF;
|
|
||||||
background-color: #515151;
|
background-color: #515151;
|
||||||
color:#ccc;
|
color:#ccc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
table.findsession-table, table.local-recordings, #account-session-detail {
|
table.findsession-table, table.local-recordings, #account-session-detail {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.latency-unacceptable {
|
.latency-unacceptable {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
@import "client/common";
|
||||||
|
|
||||||
|
#change-search-location-dialog {
|
||||||
|
|
||||||
|
height:300px;
|
||||||
|
min-height:300px;
|
||||||
|
width:390px;
|
||||||
|
min-width:390px;
|
||||||
|
|
||||||
|
form {
|
||||||
|
width:100%;
|
||||||
|
@include border_box_sizing;
|
||||||
|
|
||||||
|
.column {
|
||||||
|
|
||||||
|
float:left;
|
||||||
|
@include border_box_sizing;
|
||||||
|
|
||||||
|
&:nth-of-type(1) {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field{
|
||||||
|
margin-bottom:5px;
|
||||||
|
}
|
||||||
|
a.reset-location {
|
||||||
|
margin: 5px 0 0 130px;
|
||||||
|
font-size:12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display:inline-block;
|
||||||
|
width:130px;
|
||||||
|
line-height:26px;
|
||||||
|
vertical-align:top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
font-size:16px;
|
||||||
|
line-height:18px;
|
||||||
|
margin-bottom:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.easydropdown {
|
||||||
|
width:150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
@import "client/common";
|
||||||
|
|
||||||
|
#whatsnext-dialog, #getting-started-dialog {
|
||||||
|
|
||||||
|
height:auto;
|
||||||
|
width:auto;
|
||||||
|
|
||||||
|
.ftue-inner h2 {
|
||||||
|
font-weight:normal;
|
||||||
|
color:#ed3618;
|
||||||
|
margin-bottom:6px;
|
||||||
|
font-size:1.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icheckbox_minimal {
|
||||||
|
display:inline-block;
|
||||||
|
position:relative;
|
||||||
|
top:3px;
|
||||||
|
margin-right:3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-getting-started {
|
||||||
|
position:absolute;
|
||||||
|
margin-left:-280px;
|
||||||
|
right:50%;
|
||||||
|
top:-2px;
|
||||||
|
width:280px;
|
||||||
|
color:rgb(170, 170, 170);
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width:97%;
|
||||||
|
margin:20px 1.5%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
font-size:12px;
|
||||||
|
font-weight:300;
|
||||||
|
margin:10px 0;
|
||||||
|
@include border_box_sizing;
|
||||||
|
|
||||||
|
.column {
|
||||||
|
@include border_box_sizing;
|
||||||
|
width:47%;
|
||||||
|
float:left;
|
||||||
|
background-color:black;
|
||||||
|
padding: 10px;
|
||||||
|
height:140px;
|
||||||
|
margin: 0 1.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.full {
|
||||||
|
.column {
|
||||||
|
width:97%;
|
||||||
|
margin:0 1.5%;
|
||||||
|
height:78px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.find-connect {
|
||||||
|
.column {
|
||||||
|
height:128px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.setup-gear {
|
||||||
|
.action-button {
|
||||||
|
float:right;
|
||||||
|
margin-top:2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.learn-more {
|
||||||
|
height:80px;
|
||||||
|
margin-bottom:20px;
|
||||||
|
|
||||||
|
.blurb a {
|
||||||
|
margin-left:5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dialog-buttons {
|
||||||
|
margin-top:35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
margin-top:10px;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blurb {
|
||||||
|
line-height:1.3em;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
width:100%;
|
||||||
|
margin:0 auto;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-buttons {
|
||||||
|
text-align:center;
|
||||||
|
width:100;
|
||||||
|
margin:0 auto;
|
||||||
|
height:24px;
|
||||||
|
line-height:24px;
|
||||||
|
vertical-align:middle;
|
||||||
|
|
||||||
|
a {
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height:24px;
|
||||||
|
height:24px;
|
||||||
|
margin:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
vertical-align: top;
|
||||||
|
line-height:24px;
|
||||||
|
height:24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
@include border_box_sizing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ftue-inner table a {
|
||||||
|
text-decoration:none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
@import "client/common";
|
||||||
|
|
||||||
|
#join-test-session-dialog{
|
||||||
|
|
||||||
|
width:600px;
|
||||||
|
min-height:inherit;
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-style:italic;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight:normal;
|
||||||
|
color:#ed3618;
|
||||||
|
margin-bottom:6px;
|
||||||
|
font-size:1.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
margin: 20px 0;
|
||||||
|
line-height:1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
line-height:1em;
|
line-height:1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
.launch-buttons {
|
||||||
margin:20px 0;
|
margin:20px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#whatsnext-dialog {
|
|
||||||
.icheckbox_minimal {
|
|
||||||
display:inline-block;
|
|
||||||
position:relative;
|
|
||||||
top:3px;
|
|
||||||
margin-right:3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,15 +7,10 @@ class ApiSearchController < ApiController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
|
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
|
||||||
# puts "================== params #{params.to_s}"
|
|
||||||
query = params.clone
|
query = params.clone
|
||||||
query[:remote_ip] = request.remote_ip
|
query[:remote_ip] = request.remote_ip
|
||||||
if 1 == query[Search::PARAM_MUSICIAN].to_i
|
if 1 == query[Search::PARAM_MUSICIAN].to_i
|
||||||
clientid = query[:clientid]
|
@search = Search.musician_filter(query, current_user)
|
||||||
conn = (clientid ? Connection.where(client_id: clientid, user_id: current_user.id).first : nil)
|
|
||||||
# puts "================== query #{query.inspect}"
|
|
||||||
@search = Search.musician_filter(query, current_user, conn)
|
|
||||||
# puts "================== search #{@search.inspect}"
|
|
||||||
else
|
else
|
||||||
@search = Search.band_filter(query, current_user)
|
@search = Search.band_filter(query, current_user)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ class ApiUsersController < ApiController
|
||||||
|
|
||||||
def udp_reachable
|
def udp_reachable
|
||||||
Connection.transaction do
|
Connection.transaction do
|
||||||
@connection = Connection.find_by_client_id(params[:client_id])
|
@connection = Connection.find_by_client_id!(params[:client_id])
|
||||||
@connection.udp_reachable = params[:udp_reachable]
|
@connection.udp_reachable = params[:udp_reachable]
|
||||||
@connection.save
|
@connection.save
|
||||||
respond_with_model(@connection)
|
respond_with_model(@connection)
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ if @search.musicians_text_search?
|
||||||
end
|
end
|
||||||
|
|
||||||
if @search.musicians_filter_search?
|
if @search.musicians_filter_search?
|
||||||
node :city do |user|
|
|
||||||
current_user.try(:location)
|
|
||||||
end
|
|
||||||
|
|
||||||
node :page_count do |foo|
|
node :page_count do |foo|
|
||||||
@search.page_count
|
@search.page_count
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ end
|
||||||
if @user == current_user
|
if @user == current_user
|
||||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :subscribe_email, :auth_twitter, :new_notifications
|
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :subscribe_email, :auth_twitter, :new_notifications
|
||||||
|
|
||||||
|
node :location do |user|
|
||||||
|
geoiplocation = current_user.geoiplocation
|
||||||
|
geoiplocation.info if geoiplocation
|
||||||
|
end
|
||||||
|
|
||||||
elsif current_user
|
elsif current_user
|
||||||
node :is_friend do |uu|
|
node :is_friend do |uu|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!-- Account Summary Dialog -->
|
<!-- Account Summary Dialog -->
|
||||||
<div layout="screen" layout-id="account/audio" class="screen secondary">
|
<div layout="screen" layout-id="account/audio" class="screen secondary" id="account-audio-profile">
|
||||||
<!-- header -->
|
<!-- header -->
|
||||||
<div class="content-head">
|
<div class="content-head">
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,7 @@
|
||||||
%a{href: "#", 'user-id' => "{{data.user_id}}", 'hoveraction' => "musician", class: 'avatar-tiny'}
|
%a{href: "#", 'user-id' => "{{data.user_id}}", 'hoveraction' => "musician", class: 'avatar-tiny'}
|
||||||
%img{src: "{{data.avatar_url}}"}
|
%img{src: "{{data.avatar_url}}"}
|
||||||
|
|
||||||
|
// also used by musicians page
|
||||||
%script{type: 'text/template', id: 'template-account-session-latency'}
|
%script{type: 'text/template', id: 'template-account-session-latency'}
|
||||||
.latency{class: "{{data.latency_style}}", 'data-user-id' => "{{data.id}}", 'data-audio-latency' => "{{data.audio_latency || ''}}", 'data-full-score' => "{{data.full_score || ''}}", 'data-internet-score' => "{{data.internet_score || ''}}"}
|
.latency{class: "{{data.latency_style}}", 'data-user-id' => "{{data.id}}", 'data-audio-latency' => "{{data.audio_latency || ''}}", 'data-full-score' => "{{data.full_score || ''}}", 'data-internet-score' => "{{data.internet_score || ''}}"}
|
||||||
{{data.latency_text}}
|
{{data.latency_text}}
|
||||||
|
|
|
||||||
|
|
@ -113,3 +113,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/template" id="template-help-no-audio-profiles">
|
||||||
|
<div class="help-no-audio-profiles">
|
||||||
|
Click here to configure your audio gear.
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
<%= content_tag(:div, :class => 'content-body-scroller') do -%>
|
<%= content_tag(:div, :class => 'content-body-scroller') do -%>
|
||||||
<%= content_tag(:div, :class => 'content-wrapper musician-wrapper') do -%>
|
<%= content_tag(:div, :class => 'content-wrapper musician-wrapper') do -%>
|
||||||
<%= content_tag(:div, '', :id => 'musician-filter-results', :class => 'filter-results') %>
|
<%= content_tag(:div, '', :id => 'musician-filter-results', :class => 'filter-results') %>
|
||||||
<div class="paginate-wait">Fetching more results...<div class="spinner-small"></div></div>
|
<div class="paginate-wait">Fetching more results...
|
||||||
|
<div class="spinner-small"></div>
|
||||||
|
</div>
|
||||||
<%= content_tag(:div, 'No more results.', :class => 'end-of-list', :id => 'end-of-musician-list') %>
|
<%= content_tag(:div, 'No more results.', :class => 'end-of-list', :id => 'end-of-musician-list') %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
|
@ -27,64 +29,55 @@
|
||||||
<script type="text/template" id="template-find-musician-row">
|
<script type="text/template" id="template-find-musician-row">
|
||||||
<div class="profile-band-list-result musician-list-result" data-musician-id={musician_id}>
|
<div class="profile-band-list-result musician-list-result" data-musician-id={musician_id}>
|
||||||
<div class="f11" data-hint="container">
|
<div class="f11" data-hint="container">
|
||||||
<div class="left" style="width:63px;margin-top:-12px;">
|
<div class="left musician-avatar">
|
||||||
<!-- avatar -->
|
<!-- avatar -->
|
||||||
<div class="avatar-small"><img src="{avatar_url}" /></div>
|
<div class="avatar-small"><img src="{avatar_url}" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right musician-following" style="width: 120px;">
|
<div class="left musician-info"">
|
||||||
<div class="bold">FOLLOWING:</div>
|
|
||||||
<table class="musicians" cellpadding="0" cellspacing="5">{musician_follow_template}</table>
|
|
||||||
</div>
|
|
||||||
<div class="" style="margin-left: 63px; margin-right: 130px;margin-top: 12px;">
|
|
||||||
<div class="first-row" data-hint="top-row">
|
<div class="first-row" data-hint="top-row">
|
||||||
<div class="lcol left">
|
<div class="musician-profile">
|
||||||
<!-- name & location -->
|
<!-- name & location -->
|
||||||
<div class="result-name">{musician_name}</div>
|
<div class="result-name">{musician_name}</div>
|
||||||
<div class="result-location">{musician_location}</div>
|
<div class="result-location">{musician_location}</div>
|
||||||
<div id="result_instruments" class="instruments nowrap mt10">{instruments}</div>
|
<div id="result_instruments" class="instruments nowrap mt10">{instruments}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="whitespace">
|
<div class="musician-stats">
|
||||||
<div class="biography">{biography}</div>
|
|
||||||
</div>
|
|
||||||
<div class="clearleft"></div>
|
|
||||||
</div>
|
|
||||||
<div class="button-row " data-hint="button-row">
|
|
||||||
<div class="lcol stats left">
|
|
||||||
<span class="friend-count">{friend_count} <img src="../assets/content/icon_friend.png" alt="friends" width="14" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
<span class="friend-count">{friend_count} <img src="../assets/content/icon_friend.png" alt="friends" width="14" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
||||||
<span class="follower-count">{follow_count} <img src="../assets/content/icon_followers.png" alt="follows" width="22" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
<span class="follower-count">{follow_count} <img src="../assets/content/icon_followers.png" alt="follows" width="22" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
||||||
<span class="recording-count">{recording_count} <img src="../assets/content/icon_recordings.png" alt="recordings" width="12" height="13" align="absmiddle" style="margin-right:4px;"/></span>
|
<span class="recording-count">{recording_count} <img src="../assets/content/icon_recordings.png" alt="recordings" width="12" height="13" align="absmiddle" style="margin-right:4px;"/></span>
|
||||||
<span class="session-count">{session_count} <img src="../assets/content/icon_session_tiny.png" alt="sessions" width="12" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
<span class="session-count">{session_count} <img src="../assets/content/icon_session_tiny.png" alt="sessions" width="12" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
||||||
<span class="score-count {latency_style}">{musician_one_way_score} <img src="../assets/content/icon_{musician_score_color}_score.png" alt="{musician_score_color_alt} score" width="12" height="12" align="absmiddle" style="margin-right:4px;"/></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="result-list-button-wrapper" data-musician-id={musician_id}>
|
|
||||||
{musician_action_template}
|
|
||||||
</div>
|
|
||||||
<div class="clearall"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<br clear="both"/>
|
||||||
|
</div>
|
||||||
|
<div class="left musician-latency" >
|
||||||
|
<div class="latency-help">Your latency<br/>to {musician_first_name} is: </div>
|
||||||
|
<div class="latency-holder">
|
||||||
|
{latency_badge}
|
||||||
|
</div>
|
||||||
|
<br clear="both"/>
|
||||||
|
</div>
|
||||||
|
<div class="button-row" data-hint="button-row">
|
||||||
|
<div class="biography">{biography}</div>
|
||||||
|
<div class="result-list-button-wrapper" data-musician-id={musician_id}>
|
||||||
|
{musician_action_template}
|
||||||
|
</div>
|
||||||
|
<br clear="both"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="template-musician-action-btns">
|
<script type="text/template" id="template-musician-action-btns">
|
||||||
<a href="{profile_url}" class="button-orange smallbutton">PROFILE</a>
|
<a href="{profile_url}" class="button-orange smallbutton">PROFILE</a>
|
||||||
<% if current_user && current_user.musician? %>
|
<% if current_user && current_user.musician? %>
|
||||||
<a href="#" class="{friend_class} smallbutton search-m-friend">{friend_caption}</a>
|
<a href="#" class="{friend_class} smallbutton search-m-friend">{friend_caption}</a>
|
||||||
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<a href="#" class="{follow_class} smallbutton search-m-follow">{follow_caption}</a>
|
<a href="#" class="{follow_class} smallbutton search-m-follow">{follow_caption}</a>
|
||||||
<a href="#" class="{message_class} smallbutton search-m-message">{message_caption}</a>
|
<a href="#" class="{message_class} smallbutton search-m-message">{message_caption}</a>
|
||||||
<!--<a href="#" class="{button_message} smallbutton search-m-like">MESSAGE</a>-->
|
<!--<a href="#" class="{button_message} smallbutton search-m-like">MESSAGE</a>-->
|
||||||
<div class="clearall"></div>
|
<div class="clearall"></div>
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/template" id="template-musician-follow-info">
|
|
||||||
<tr>
|
|
||||||
<td width="32">
|
|
||||||
<a user-id="{user_id}" hoveraction="musician" href="{profile_url}" class="avatar-tiny"><img src="{avatar_url}" /></a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a user-id="{user_id}" hoveraction="musician" href="{profile_url}"><strong>{musician_name}</strong></a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -49,13 +49,14 @@
|
||||||
<!-- @end show filter -->
|
<!-- @end show filter -->
|
||||||
<% elsif :musician == filter_label %>
|
<% elsif :musician == filter_label %>
|
||||||
<!-- @begin score filter -->
|
<!-- @begin score filter -->
|
||||||
<%= content_tag(:div, 'Latency:', :class => 'filter-element desc') %>
|
<%= content_tag(:div, 'Latency:', :class => 'filter-element desc latency-or-distance') %>
|
||||||
<%= content_tag(:div, :class => 'query-distance-params') do -%>
|
<%= content_tag(:div, :class => 'query-distance-params') do -%>
|
||||||
<%= select_tag("musician_query_score", options_for_select(Search::M_SCORE_OPTS, Search::M_SCORE_DEFAULT), {:class => 'easydropdown'}) %>
|
<%= select_tag("musician_query_score", options_for_select(Search::M_SCORE_OPTS, Search::M_SCORE_DEFAULT), {:class => 'easydropdown'}) %>
|
||||||
|
<%= select_tag("musician_distance", options_for_select(Search::M_DISTANCE_OPTS, Search::M_DISTANCE_DEFAULT), {:class => 'easydropdown'}) %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
<%= content_tag(:div, :class => 'filter-element desc') do -%>
|
<div class="filter-element desc" id="musician-search-city">
|
||||||
to <%= content_tag(:span, current_user ? current_user.current_city(request.remote_ip) : '', :id => "musician-filter-city") %>
|
to <a href="#" id="musician-change-filter-city"><span id="musician-filter-city"></span></a>
|
||||||
<% end -%>
|
</div>
|
||||||
<!-- @end score filter -->
|
<!-- @end score filter -->
|
||||||
<% else %>
|
<% else %>
|
||||||
<!-- @begin distance filter -->
|
<!-- @begin distance filter -->
|
||||||
|
|
@ -75,6 +76,10 @@
|
||||||
<div class="btn-refresh-holder">
|
<div class="btn-refresh-holder">
|
||||||
<a class="button-grey btn-refresh-entries" href="/client#/feed">REFRESH</a>
|
<a class="button-grey btn-refresh-entries" href="/client#/feed">REFRESH</a>
|
||||||
</div>
|
</div>
|
||||||
|
<% elsif :musician == filter_label %>
|
||||||
|
<div class="btn-refresh-holder">
|
||||||
|
<a class="button-grey btn-refresh-entries" href="/client#/musicians">REFRESH</a>
|
||||||
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
<!-- @end web_filter -->
|
<!-- @end web_filter -->
|
||||||
|
|
@ -247,6 +247,9 @@
|
||||||
var testBridgeScreen = new JK.TestBridgeScreen(JK.app);
|
var testBridgeScreen = new JK.TestBridgeScreen(JK.app);
|
||||||
testBridgeScreen.initialize();
|
testBridgeScreen.initialize();
|
||||||
|
|
||||||
|
var changeSearchLocationDialog = new JK.ChangeSearchLocationDialog(JK.app);
|
||||||
|
changeSearchLocationDialog.initialize();
|
||||||
|
|
||||||
// do a client update early check upon initialization
|
// do a client update early check upon initialization
|
||||||
JK.ClientUpdateInstance.check()
|
JK.ClientUpdateInstance.check()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
.right.action-buttons
|
.right.action-buttons
|
||||||
%a.button-grey.btn-close-dialog{href:'#', 'layout-action' => 'close'} CLOSE
|
%a.button-grey.btn-close-dialog{href:'#', 'layout-action' => 'close'} CLOSE
|
||||||
%a.button-grey.btn-cancel-dialog{href:'#', 'layout-action' => 'close'} CANCEL
|
%a.button-grey.btn-cancel-dialog{href:'#', 'layout-action' => 'cancel'} CANCEL
|
||||||
%a.button-orange.btn-accept-friend-request{href:'#'} ACCEPT
|
%a.button-orange.btn-accept-friend-request{href:'#'} ACCEPT
|
||||||
|
|
||||||
%script{type: 'text/template', id: 'template-friend-request-not-friends'}
|
%script{type: 'text/template', id: 'template-friend-request-not-friends'}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
li = 'Input device is not connected'
|
li = 'Input device is not connected'
|
||||||
.buttons
|
.buttons
|
||||||
.left
|
.left
|
||||||
a.button-grey.btnCancel CANCEL
|
a.button-grey.btnCancel layout-action="cancel" CANCEL
|
||||||
a.button-grey.btnConfigureGear GO TO AUDIO GEAR SCREEN
|
a.button-grey.btnConfigureGear GO TO AUDIO GEAR SCREEN
|
||||||
a.button-grey.btnRestartApplication RESTART APPLICATION
|
a.button-grey.btnRestartApplication RESTART APPLICATION
|
||||||
.right
|
.right
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
.dialog.dialog-overlay-sm layout='dialog' layout-id='change-search-location' id='change-search-location-dialog'
|
||||||
|
.content-head
|
||||||
|
h1 change search location
|
||||||
|
.dialog-inner
|
||||||
|
.hint
|
||||||
|
| Specify which location you want to search from.
|
||||||
|
form action='post'
|
||||||
|
.column
|
||||||
|
.field purpose="country"
|
||||||
|
label for="country" Country:
|
||||||
|
select name="country"
|
||||||
|
.field purpose="region"
|
||||||
|
label for="region" State/Province:
|
||||||
|
select name="region" disabled="disabled"
|
||||||
|
.field purpose="city"
|
||||||
|
label for="city" City:
|
||||||
|
select name="city" disabled="disabled"
|
||||||
|
a href="#" class="reset-location" Reset to my current location
|
||||||
|
br clear='all'
|
||||||
|
.buttons
|
||||||
|
.right
|
||||||
|
a.button-grey class='btnCancel' layout-action='cancel' CANCEL
|
||||||
|
a.button-orange class='btnSave' SAVE
|
||||||
|
|
||||||
|
|
@ -13,6 +13,6 @@
|
||||||
br clear='all'
|
br clear='all'
|
||||||
.buttons
|
.buttons
|
||||||
.right
|
.right
|
||||||
a.button-grey class='btnCancel' layout-action='close' CANCEL
|
a.button-grey class='btnCancel' layout-action='cancel' CANCEL
|
||||||
a.button-orange class='btnSave' SAVE
|
a.button-orange class='btnSave' SAVE
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,7 @@
|
||||||
= render 'dialogs/videoDialog'
|
= render 'dialogs/videoDialog'
|
||||||
= render 'dialogs/friendSelectorDialog'
|
= render 'dialogs/friendSelectorDialog'
|
||||||
= render 'dialogs/clientPreferencesDialog'
|
= render 'dialogs/clientPreferencesDialog'
|
||||||
= render 'dialogs/audioProfileInvalidDialog'
|
= render 'dialogs/audioProfileInvalidDialog'
|
||||||
|
= render 'dialogs/gettingStartedDialog'
|
||||||
|
= render 'dialogs/joinTestSessionDialog'
|
||||||
|
= render 'dialogs/changeSearchLocationDialog'
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
%label{for: 'is_public'} Public Recording
|
%label{for: 'is_public'} Public Recording
|
||||||
|
|
||||||
.buttons
|
.buttons
|
||||||
%a.button-grey.cancel-btn CANCEL
|
%a.button-grey.cancel-btn {'layout-action' => 'cancel'} CANCEL
|
||||||
%a.button-orange.delete-btn DELETE
|
%a.button-orange.delete-btn DELETE
|
||||||
%a.button-orange.save-btn UPDATE
|
%a.button-orange.save-btn UPDATE
|
||||||
%br{clear: 'all'}
|
%br{clear: 'all'}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
.dialog.whatsnext-overlay.ftue-overlay.tall layout="dialog" layout-id="getting-started" id="getting-started-dialog"
|
||||||
|
.content-head
|
||||||
|
h1 getting started
|
||||||
|
|
||||||
|
.ftue-inner
|
||||||
|
.title
|
||||||
|
| Welcome to JamKazam! Here are the top things you should do to get the
|
||||||
|
most out of this service. Be sure to get through all of these for the best experience, but you can spread
|
||||||
|
them out over multiple visits!
|
||||||
|
|
||||||
|
.row.full.setup-gear
|
||||||
|
.column
|
||||||
|
h2 SET UP GEAR
|
||||||
|
.blurb
|
||||||
|
span
|
||||||
|
.action-button
|
||||||
|
a.button-orange.setup-gear-btn layout-link="account/audio" SET UP GEAR
|
||||||
|
| Click SET UP GEAR to configure and test your audio gear and network connection.
|
||||||
|
Once you’ve completed this step, we’ll drop you into your first session, and you can explore the session
|
||||||
|
interface.
|
||||||
|
br clear="both"
|
||||||
|
.row
|
||||||
|
.column
|
||||||
|
h2 INVITE YOUR FRIENDS
|
||||||
|
.blurb
|
||||||
|
| Invite others to join JamKazam. You’ll be connected as friends, which makes it easier to get into sessions
|
||||||
|
together. And it will grow our community, which helps us as a young company. Click the icons below to
|
||||||
|
invite!
|
||||||
|
.social-buttons
|
||||||
|
a href="#" class="facebook-invite"
|
||||||
|
= image_tag "content/icon_facebook.png", {:align=>"absmiddle", :height => 24, :width => 24}
|
||||||
|
span Facebook
|
||||||
|
a href="#" class="email-invite"
|
||||||
|
= image_tag "content/icon_gmail.png", {:align=>"absmiddle", :height => 24, :width => 24}
|
||||||
|
span E-mail
|
||||||
|
a href="#" class="google-invite"
|
||||||
|
= image_tag "content/icon_google.png", {:align=>"absmiddle", :height => 26, :width => 26 }
|
||||||
|
span Google+
|
||||||
|
.column
|
||||||
|
h2 CREATE A "REAL" SESSION
|
||||||
|
.blurb
|
||||||
|
| You can create a session to start immediately and hope others join, but this doesn’t work well. It’s better
|
||||||
|
to schedule a session and invite friends or the community to join you. Watch a video to learn how, then
|
||||||
|
schedule your first session!
|
||||||
|
.action-button
|
||||||
|
a.button-orange rel="external" href="https://www.youtube.com/watch?v=EZZuGcDUoWk" WATCH VIDEO
|
||||||
|
br clear="both"
|
||||||
|
.row.find-connect
|
||||||
|
.column
|
||||||
|
h2 FIND SESSIONS TO JOIN
|
||||||
|
.blurb
|
||||||
|
| In addition to creating your own sessions, it’s awesome to join others’ sessions. Watch this tutorial video
|
||||||
|
to learn about how to find and select good sessions to join.
|
||||||
|
.action-button
|
||||||
|
a.button-orange.setup-gear rel="external" href="https://www.youtube.com/watch?v=xWponSJo-GU" WATCH VIDEO
|
||||||
|
|
||||||
|
.column
|
||||||
|
h2 CONNECT WITH MUSICIANS
|
||||||
|
.blurb
|
||||||
|
| To play more music, tap into our growing
|
||||||
|
community to connect with other musicians. Watch this video for tips on how to do this.
|
||||||
|
.action-button
|
||||||
|
a.button-orange rel="external" href="https://www.youtube.com/watch?v=xWponSJo-GU" WATCH VIDEO
|
||||||
|
br clear="both"
|
||||||
|
.row.full.learn-more
|
||||||
|
.column
|
||||||
|
h2 LEARN MORE ABOUT JAMKAZAM
|
||||||
|
.blurb
|
||||||
|
| There is a lot you can do with JamKazam, and more great features available every week. Check the
|
||||||
|
following link for a list of videos and other resources you can use to take advantage of everything that’s
|
||||||
|
available:
|
||||||
|
a rel="external" purpose="youtube-tutorials" href="http://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA" JamKazam Tutorials & Resources
|
||||||
|
br clear="both"
|
||||||
|
.row.dialog-buttons
|
||||||
|
.buttons
|
||||||
|
.show-getting-started
|
||||||
|
input type="checkbox" id="show_getting_started"
|
||||||
|
span Don't show this again
|
||||||
|
a.close-btn href="#" class="button-orange" layout-action="close"
|
||||||
|
| CLOSE
|
||||||
|
br clear="both"
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
.dialog layout='dialog' layout-id='join-test-session' id='join-test-session-dialog'
|
||||||
|
.content-head
|
||||||
|
h1 join test session
|
||||||
|
|
||||||
|
.dialog-inner
|
||||||
|
.title
|
||||||
|
| VERIFY YOUR SETUP WITH A TEST SESSION
|
||||||
|
.hint
|
||||||
|
| You have set up your gear and verified your network, but does it
|
||||||
|
em really
|
||||||
|
| work?
|
||||||
|
br
|
||||||
|
br
|
||||||
|
| The way to find out is by joining a test session.
|
||||||
|
br
|
||||||
|
br
|
||||||
|
| This will familiarize you with how sessions work in JamKazam, and if you are lucky, someone else might even join in.
|
||||||
|
.buttons
|
||||||
|
a.button-grey layout-action="cancel" CANCEL
|
||||||
|
a.button-orange.join-test-session JOIN TEST SESSION
|
||||||
|
br
|
||||||
|
|
@ -7,14 +7,14 @@
|
||||||
%script{type: 'text/template', id: 'template-attempt-launch'}
|
%script{type: 'text/template', id: 'template-attempt-launch'}
|
||||||
%p
|
%p
|
||||||
{{data.messagePrefix}}, you must use the JamKazam application.
|
{{data.messagePrefix}}, you must use the JamKazam application.
|
||||||
.right.buttons
|
.right.launch-buttons
|
||||||
%a.button-grey.btn-cancel{href:'#', 'layout-action' => 'close'} CANCEL
|
%a.button-grey.btn-cancel{href:'#', 'layout-action' => 'close'} CANCEL
|
||||||
%a.button-orange.btn-launch-app{href:'{{data.launchUrl}}'} LAUNCH APP
|
%a.button-orange.btn-launch-app{href:'{{data.launchUrl}}'} LAUNCH APP
|
||||||
|
|
||||||
%script{type: 'text/template', id: 'template-unsupported-launch'}
|
%script{type: 'text/template', id: 'template-unsupported-launch'}
|
||||||
%p
|
%p
|
||||||
{{data.messagePrefix}}, you must use the JamKazam application. Please download and install the application if you have not done so already.
|
{{data.messagePrefix}}, you must use the JamKazam application. Please download and install the application if you have not done so already.
|
||||||
.right.buttons
|
.right.launch-buttons
|
||||||
%a.button-grey.btn-cancel{href:'#', 'layout-action' => 'close'} CANCEL
|
%a.button-grey.btn-cancel{href:'#', 'layout-action' => 'close'} CANCEL
|
||||||
%a.button-orange.btn-go-to-download-page{href:'/downloads'} GO TO APP DOWNLOAD PAGE
|
%a.button-orange.btn-go-to-download-page{href:'/downloads'} GO TO APP DOWNLOAD PAGE
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
If the application is not running, then please
|
If the application is not running, then please
|
||||||
%a.download-application{href: '/downloads'} download
|
%a.download-application{href: '/downloads'} download
|
||||||
and install the application if you have not done so already, and then start it manually rather than using this web launcher.
|
and install the application if you have not done so already, and then start it manually rather than using this web launcher.
|
||||||
.right.buttons
|
.right.launch-buttons
|
||||||
%a.button-grey.btn-done{href:'#', 'layout-action' => 'close'} DONE
|
%a.button-grey.btn-done{href:'#', 'layout-action' => 'close'} DONE
|
||||||
|
|
||||||
%script{type: 'text/template', id: 'template-launch-unsuccessful'}
|
%script{type: 'text/template', id: 'template-launch-unsuccessful'}
|
||||||
|
|
@ -44,6 +44,6 @@
|
||||||
If the application is not running, then please
|
If the application is not running, then please
|
||||||
%a.download-application{href: '/downloads'} download
|
%a.download-application{href: '/downloads'} download
|
||||||
and install the application if you have not done so already, and then start it manually rather than using this web launcher.
|
and install the application if you have not done so already, and then start it manually rather than using this web launcher.
|
||||||
.right.buttons
|
.right.launch-buttons
|
||||||
%a.button-grey.btn-done{href:'#', 'layout-action' => 'close'} CLOSE
|
%a.button-grey.btn-done{href:'#', 'layout-action' => 'close'} CLOSE
|
||||||
%a.button-orange.btn-go-to-download-page{href:'/downloads'} GO TO APP DOWNLOAD PAGE
|
%a.button-orange.btn-go-to-download-page{href:'/downloads'} GO TO APP DOWNLOAD PAGE
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
.clearall
|
.clearall
|
||||||
.buttons
|
.buttons
|
||||||
.left
|
.left
|
||||||
%a.button-grey.btn-cancel{href:'#'} CANCEL
|
%a.button-grey.btn-cancel{href:'#', 'layout-action' => 'cancel'} CANCEL
|
||||||
%a.button-grey.btn-help{rel: 'external', href: 'https://jamkazam.desk.com/customer/portal/articles/1599969-first-time-setup---step-6---test-your-network'} HELP
|
%a.button-grey.btn-help{rel: 'external', href: 'https://jamkazam.desk.com/customer/portal/articles/1599969-first-time-setup---step-6---test-your-network'} HELP
|
||||||
.right
|
.right
|
||||||
%a.button-orange.btn-close{href:'#'} CLOSE
|
%a.button-orange.btn-close{href:'#'} CLOSE
|
||||||
|
|
@ -14,6 +14,9 @@ SampleApp::Application.configure do
|
||||||
# Log error messages when you accidentally call methods on nil
|
# Log error messages when you accidentally call methods on nil
|
||||||
config.whiny_nils = true
|
config.whiny_nils = true
|
||||||
|
|
||||||
|
# useful when debugging a javascript problem...
|
||||||
|
config.assets.compress = false
|
||||||
|
|
||||||
# Show full error reports and disable caching
|
# Show full error reports and disable caching
|
||||||
config.consider_all_requests_local = true
|
config.consider_all_requests_local = true
|
||||||
config.action_controller.perform_caching = false
|
config.action_controller.perform_caching = false
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,52 @@ FactoryGirl.define do
|
||||||
admin true
|
admin true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :austin_user do
|
||||||
|
first_name 'Austin'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Austin'
|
||||||
|
last_jam_locidispid { austin_geoip[:locidispid] }
|
||||||
|
last_jam_addr { austin_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :dallas_user do
|
||||||
|
first_name 'Dallas'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Dallas'
|
||||||
|
last_jam_locidispid { dallas_geoip[:locidispid] }
|
||||||
|
last_jam_addr { dallas_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :houston_user do
|
||||||
|
first_name 'Houston'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'TX'
|
||||||
|
city 'Houston'
|
||||||
|
last_jam_locidispid { houston_geoip[:locidispid] }
|
||||||
|
last_jam_addr { houston_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :miami_user do
|
||||||
|
first_name 'Miami'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'FL'
|
||||||
|
city 'Miami'
|
||||||
|
last_jam_locidispid { miami_geoip[:locidispid] }
|
||||||
|
last_jam_addr { miami_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :seattle_user do
|
||||||
|
first_name 'Seattle'
|
||||||
|
sequence(:last_name) { |n| "#{n}" }
|
||||||
|
state 'WA'
|
||||||
|
city 'Seattle'
|
||||||
|
last_jam_locidispid { seattle_geoip[:locidispid] }
|
||||||
|
last_jam_addr { seattle_ip }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
factory :band_musician do
|
factory :band_musician do
|
||||||
after(:create) do |user|
|
after(:create) do |user|
|
||||||
band = FactoryGirl.create(:band)
|
band = FactoryGirl.create(:band)
|
||||||
|
|
|
||||||
|
|
@ -14,46 +14,15 @@ describe "Gear Wizard", :js => true, :type => :feature, :capybara_feature => tru
|
||||||
it "success path" do
|
it "success path" do
|
||||||
FactoryGirl.create(:latency_tester)
|
FactoryGirl.create(:latency_tester)
|
||||||
fast_signin user, '/client#/account/audio'
|
fast_signin user, '/client#/account/audio'
|
||||||
# step 1 - intro
|
|
||||||
find("div.account-audio a[data-purpose='add-profile']").trigger(:click)
|
find("div.account-audio a[data-purpose='add-profile']").trigger(:click)
|
||||||
find('.btn-next').trigger(:click)
|
walk_gear_wizard
|
||||||
|
|
||||||
# step 2 - select gear
|
|
||||||
find('.ftue-step-title', text: 'Select & Test Audio Gear')
|
|
||||||
should_not have_selector('.resync-status') # when you enter this step,
|
|
||||||
jk_select('Built-in', 'div[layout-wizard-step="1"] select.select-audio-input-device')
|
|
||||||
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
|
||||||
|
|
||||||
# step 3 - configure tracks
|
|
||||||
find('.ftue-step-title', text: 'Configure Tracks')
|
|
||||||
|
|
||||||
# drag one input over to tracks area http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#drag_to-instance_method
|
|
||||||
input = first('.ftue-input')
|
|
||||||
track_slot = first('.track-target')
|
|
||||||
input.drag_to(track_slot)
|
|
||||||
|
|
||||||
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
|
||||||
|
|
||||||
# step 4 - configure voice chat
|
|
||||||
find('.ftue-step-title', text: 'Configure Voice Chat')
|
|
||||||
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
|
||||||
|
|
||||||
# step 5 - configure direct monitoring
|
|
||||||
find('.ftue-step-title', text: 'Turn Off Direct Monitoring')
|
|
||||||
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
|
||||||
|
|
||||||
# step 6 - Test Router & Network
|
|
||||||
find('.ftue-step-title', text: 'Test Router & Network')
|
|
||||||
find('.button-orange.start-network-test').trigger(:click)
|
|
||||||
find('.user-btn', text: 'RUN NETWORK TEST ANYWAY').trigger(:click)
|
|
||||||
find('.button-orange.start-network-test')
|
|
||||||
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
|
||||||
|
|
||||||
# step 7 - Success
|
|
||||||
find('.ftue-step-title', text: 'Success!')
|
|
||||||
find('.btn-close.button-orange').trigger(:click)
|
|
||||||
|
|
||||||
|
# should see prompt afterwards about joining a test session
|
||||||
|
find('h1', text: 'join test session')
|
||||||
|
find('.join-test-session').trigger(:click)
|
||||||
|
|
||||||
|
# and should now be in session
|
||||||
|
find('h2', text: 'my tracks')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe "Home Screen", :js => true, :type => :feature, :capybara_feature => true do
|
||||||
|
|
||||||
|
subject { page }
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
Capybara.javascript_driver = :poltergeist
|
||||||
|
Capybara.current_driver = Capybara.javascript_driver
|
||||||
|
Capybara.default_wait_time = 10
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:user) { FactoryGirl.create(:user, :show_whats_next => true) }
|
||||||
|
|
||||||
|
|
||||||
|
describe "in normal browser" do
|
||||||
|
before(:each) do
|
||||||
|
sign_in_poltergeist user
|
||||||
|
visit "/client"
|
||||||
|
should have_selector('h1', text: 'getting started')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should show launch app dialog if clicked setup gear" do
|
||||||
|
find('#getting-started-dialog .setup-gear-btn').trigger('click')
|
||||||
|
should have_selector('p', text: 'To configure your audio gear, you must use the JamKazam application.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "in native client" do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
sign_in_poltergeist user
|
||||||
|
emulate_client
|
||||||
|
visit "/client"
|
||||||
|
should have_selector('h1', text: 'getting started')
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "new user in the native view should see the getting started dialog" do
|
||||||
|
|
||||||
|
it "should show gear page if clicked setup gear" do
|
||||||
|
find('#getting-started-dialog .setup-gear-btn').trigger('click')
|
||||||
|
should have_selector('h2', text: 'audio profiles:')
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "open invitation dialog for email" do
|
||||||
|
before(:each) do
|
||||||
|
find('#getting-started-dialog .email-invite').trigger(:click)
|
||||||
|
end
|
||||||
|
|
||||||
|
it {should have_selector('label', text: 'Enter email address(es). If multiple addresses, separate with commas.')}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "launches youtube tutorial site" do
|
||||||
|
|
||||||
|
it {
|
||||||
|
find("#getting-started-dialog a[purpose='youtube-tutorials']").trigger(:click)
|
||||||
|
page.driver.window_handles.last
|
||||||
|
page.within_window page.driver.window_handles.last do
|
||||||
|
should have_title('JamKazam - YouTube')
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "close hides the screen" do
|
||||||
|
|
||||||
|
it {
|
||||||
|
find('#getting-started-dialog a[layout-action="close"]').trigger(:click)
|
||||||
|
should have_no_selector('h1', text: 'getting started')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "user can make prompt go away forever" do
|
||||||
|
|
||||||
|
it {
|
||||||
|
find('#getting-started-dialog ins.iCheck-helper').trigger(:click)
|
||||||
|
find('#getting-started-dialog a[layout-action="close"]').trigger(:click)
|
||||||
|
|
||||||
|
# needed because we poke the server with an updateUser call, but their is no indication in the UI that it's done
|
||||||
|
wait_for_ajax
|
||||||
|
emulate_client
|
||||||
|
sleep 1
|
||||||
|
visit "/client"
|
||||||
|
wait_until_curtain_gone
|
||||||
|
should_not have_selector('h1', text: 'getting started')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
@ -6,22 +6,21 @@ describe "Musician Search", :js => true, :type => :feature, :capybara_feature =>
|
||||||
|
|
||||||
let(:austin) { austin_geoip }
|
let(:austin) { austin_geoip }
|
||||||
let(:dallas) { dallas_geoip }
|
let(:dallas) { dallas_geoip }
|
||||||
let(:user) {FactoryGirl.create(:user, last_jam_locidispid: austin_geoip[:locidispid], last_jam_addr: austin_ip)}
|
|
||||||
let(:user2) {FactoryGirl.create(:user, last_jam_locidispid: dallas_geoip[:locidispid], last_jam_addr: dallas_ip)}
|
|
||||||
|
|
||||||
|
let(:austin_user) { FactoryGirl.create(:austin_user) }
|
||||||
|
let(:dallas_user) { FactoryGirl.create(:dallas_user) }
|
||||||
|
let(:miami_user) { FactoryGirl.create(:miami_user) }
|
||||||
|
let(:seattle_user) { FactoryGirl.create(:seattle_user) }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
MaxMindManager.create_phony_database
|
MaxMindManager.create_phony_database
|
||||||
|
User.delete_all
|
||||||
|
austin_user.touch
|
||||||
|
dallas_user.touch
|
||||||
Score.delete_all
|
Score.delete_all
|
||||||
Score.createx(austin_geoip[:locidispid], 'a', 1, dallas_geoip[:locidispid], 'a', 1, 10)
|
Score.createx(austin_geoip[:locidispid], 'a', 1, dallas_geoip[:locidispid], 'a', 1, 10)
|
||||||
|
|
||||||
ActiveRecord::Base.logger.debug '====================================== begin ======================================'
|
fast_signin(austin_user, "/client#/musicians")
|
||||||
sign_in_poltergeist user
|
|
||||||
visit "/client#/musicians"
|
|
||||||
end
|
|
||||||
|
|
||||||
after(:each) do
|
|
||||||
ActiveRecord::Base.logger.debug '====================================== done ======================================'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "shows the musician search page" do
|
it "shows the musician search page" do
|
||||||
|
|
@ -49,13 +48,47 @@ describe "Musician Search", :js => true, :type => :feature, :capybara_feature =>
|
||||||
|
|
||||||
it "shows latency information correctly" do
|
it "shows latency information correctly" do
|
||||||
# this will try to show 5 latency badges. unknown, good, fair, poor, unacceptable. 'me' does not happen on this screen
|
# this will try to show 5 latency badges. unknown, good, fair, poor, unacceptable. 'me' does not happen on this screen
|
||||||
user.last_jam_locidispid = austin[:locidispid]
|
austin_user.last_jam_locidispid = austin[:locidispid]
|
||||||
user.save!
|
austin_user.save!
|
||||||
|
|
||||||
verify_find_musician_score(nil, user, user2)
|
verify_find_musician_score(nil, austin_user, dallas_user)
|
||||||
verify_find_musician_score(3, user, user2)
|
verify_find_musician_score(3, austin_user, dallas_user)
|
||||||
verify_find_musician_score(40, user, user2)
|
verify_find_musician_score(40, austin_user, dallas_user)
|
||||||
verify_find_musician_score(80, user, user2)
|
verify_find_musician_score(80, austin_user, dallas_user)
|
||||||
verify_find_musician_score(110, user, user2)
|
verify_find_musician_score(110, austin_user, dallas_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "shows search by distance" do
|
||||||
|
|
||||||
|
# this test does a distance search with the austin user, then opens up the 'change search location' dialog,
|
||||||
|
# and changes the search distance
|
||||||
|
|
||||||
|
miami_user.touch # no scores, but should still show
|
||||||
|
seattle_user.touch # no scores, but should still show
|
||||||
|
|
||||||
|
wait_for_easydropdown('#musician_order_by')
|
||||||
|
jk_select('Distance', '#musician_order_by')
|
||||||
|
|
||||||
|
find(".musician-list-result[data-musician-id='#{dallas_user.id}']:nth-child(1)") # only dallas is within range
|
||||||
|
|
||||||
|
find('#musician-change-filter-city').trigger(:click)
|
||||||
|
|
||||||
|
find('h1', text: 'change search location') # dialog should be showing
|
||||||
|
|
||||||
|
# wait for it to finish populating
|
||||||
|
wait_for_easydropdown('#change-search-location-dialog select[name="country"]')
|
||||||
|
wait_for_easydropdown('#change-search-location-dialog select[name="region"]')
|
||||||
|
wait_for_easydropdown('#change-search-location-dialog select[name="city"]')
|
||||||
|
|
||||||
|
jk_select('FL', '#change-search-location-dialog select[name="region"]') # this should be 'Florida', but our test data
|
||||||
|
# wait for the city to not be disabled as it reloads
|
||||||
|
expect(page).to_not have_selector('#change-search-location-dialog .field[purpose="city"] .easydropdown-wrapper.disabled')
|
||||||
|
jk_select('Miami', '#change-search-location-dialog select[name="city"]')
|
||||||
|
find('#change-search-location-dialog .btnSave').trigger(:click)
|
||||||
|
find('#musician-filter-city', text: "Miami, FL")
|
||||||
|
|
||||||
|
find(".musician-list-result[data-musician-id='#{miami_user.id}']:nth-child(1)") # only miami is within range
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe "Home Screen", :js => true, :type => :feature, :capybara_feature => true do
|
|
||||||
|
|
||||||
subject { page }
|
|
||||||
|
|
||||||
before(:all) do
|
|
||||||
Capybara.javascript_driver = :poltergeist
|
|
||||||
Capybara.current_driver = Capybara.javascript_driver
|
|
||||||
Capybara.default_wait_time = 10
|
|
||||||
end
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
sign_in_poltergeist user
|
|
||||||
emulate_client
|
|
||||||
visit "/client"
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:user) { FactoryGirl.create(:user, :show_whats_next => true) }
|
|
||||||
|
|
||||||
describe "new user in the native view should see the whats next dialog" do
|
|
||||||
|
|
||||||
it {
|
|
||||||
should have_selector('h1', text: 'what\'s next?')
|
|
||||||
}
|
|
||||||
|
|
||||||
describe "open invitation dialog for email" do
|
|
||||||
before(:each) do
|
|
||||||
find('#whatsnext-dialog .email-invite').trigger(:click)
|
|
||||||
end
|
|
||||||
|
|
||||||
it {should have_selector('label', text: 'Enter email address(es). If multiple addresses, separate with commas.')}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
describe "launches youtube tutorial site" do
|
|
||||||
|
|
||||||
it {
|
|
||||||
find("#whatsnext-dialog a.orange[purpose='youtube-tutorials']").trigger(:click)
|
|
||||||
page.driver.window_handles.last
|
|
||||||
page.within_window page.driver.window_handles.last do
|
|
||||||
should have_title('JamKazam - YouTube')
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
describe "close hides the screen" do
|
|
||||||
|
|
||||||
it {
|
|
||||||
find('#whatsnext-dialog a[layout-action="close"]').trigger(:click)
|
|
||||||
should have_no_selector('h1', text: 'what\'s next?')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "user can make prompt go away forever" do
|
|
||||||
|
|
||||||
it {
|
|
||||||
find('#whatsnext-dialog ins.iCheck-helper').trigger(:click)
|
|
||||||
find('#whatsnext-dialog a[layout-action="close"]').trigger(:click)
|
|
||||||
|
|
||||||
# needed because we poke the server with an updateUser call, but their is no indication in the UI that it's done
|
|
||||||
wait_for_ajax
|
|
||||||
emulate_client
|
|
||||||
sleep 1
|
|
||||||
visit "/client"
|
|
||||||
wait_until_curtain_gone
|
|
||||||
should_not have_selector('h1', text: 'what\'s next?')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<div class="field">
|
||||||
|
<label>Country:</label>
|
||||||
|
<select name='country' class="w80">
|
||||||
|
<option value='{country}' selected="selected">{country}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label>State/Province:</label>
|
||||||
|
<select name='region' class="w80" disabled='disabled'>
|
||||||
|
<option value="{region}" selected="selected">{region}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label>City:</label>
|
||||||
|
<select name='city' class="w80" disabled='disabled'>
|
||||||
|
<option value="{city}" selected="selected">{city}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Teaspoon includes some support files, but you can use anything from your own support path too.
|
||||||
|
// require support/jasmine-jquery-1.7.0
|
||||||
|
// require support/jasmine-jquery-2.0.0
|
||||||
|
// require support/sinon
|
||||||
|
// require support/your-support-file
|
||||||
|
//
|
||||||
|
// PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion.
|
||||||
|
// Use this polyfill to avoid the confusion.
|
||||||
|
//= require support/bind-poly
|
||||||
|
//
|
||||||
|
// Deferring execution
|
||||||
|
// If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call
|
||||||
|
// Teaspoon.execute() after everything has been loaded. Simple example of a timeout:
|
||||||
|
//
|
||||||
|
// Teaspoon.defer = true
|
||||||
|
// setTimeout(Teaspoon.execute, 1000)
|
||||||
|
//
|
||||||
|
// Matching files
|
||||||
|
// By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
|
||||||
|
// spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
|
||||||
|
// configuration in config/initializers/teaspoon.rb
|
||||||
|
//
|
||||||
|
// Manifest
|
||||||
|
// If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
|
||||||
|
// the configuration and use this file as a manifest.
|
||||||
|
//
|
||||||
|
// For more information: http://github.com/modeset/teaspoon
|
||||||
|
//
|
||||||
|
// You can require your own javascript files here. By default this will include everything in application, however you
|
||||||
|
// may get better load performance if you require the specific files that are being used in the spec that tests them.
|
||||||
|
//= require application
|
||||||
|
|
@ -123,4 +123,45 @@ end
|
||||||
|
|
||||||
def close_websocket
|
def close_websocket
|
||||||
page.evaluate_script("window.JK.JamServer.close(true)")
|
page.evaluate_script("window.JK.JamServer.close(true)")
|
||||||
|
end
|
||||||
|
|
||||||
|
# does not launch it; expects that to have just been done
|
||||||
|
def walk_gear_wizard
|
||||||
|
# step 1 - intro
|
||||||
|
find('.btn-next').trigger(:click)
|
||||||
|
|
||||||
|
# step 2 - select gear
|
||||||
|
find('.ftue-step-title', text: 'Select & Test Audio Gear')
|
||||||
|
should_not have_selector('.resync-status') # when you enter this step,
|
||||||
|
jk_select('Built-in', 'div[layout-wizard-step="1"] select.select-audio-input-device')
|
||||||
|
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
||||||
|
|
||||||
|
# step 3 - configure tracks
|
||||||
|
find('.ftue-step-title', text: 'Configure Tracks')
|
||||||
|
|
||||||
|
# drag one input over to tracks area http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Element#drag_to-instance_method
|
||||||
|
input = first('.ftue-input')
|
||||||
|
track_slot = first('.track-target')
|
||||||
|
input.drag_to(track_slot)
|
||||||
|
|
||||||
|
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
||||||
|
|
||||||
|
# step 4 - configure voice chat
|
||||||
|
find('.ftue-step-title', text: 'Configure Voice Chat')
|
||||||
|
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
||||||
|
|
||||||
|
# step 5 - configure direct monitoring
|
||||||
|
find('.ftue-step-title', text: 'Turn Off Direct Monitoring')
|
||||||
|
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
||||||
|
|
||||||
|
# step 6 - Test Router & Network
|
||||||
|
find('.ftue-step-title', text: 'Test Router & Network')
|
||||||
|
find('.button-orange.start-network-test').trigger(:click)
|
||||||
|
find('.user-btn', text: 'RUN NETWORK TEST ANYWAY').trigger(:click)
|
||||||
|
find('.button-orange.start-network-test')
|
||||||
|
find('.btn-next.button-orange:not(.disabled)').trigger(:click)
|
||||||
|
|
||||||
|
# step 7 - Success
|
||||||
|
find('.ftue-step-title', text: 'Success!')
|
||||||
|
find('.btn-close.button-orange').trigger(:click)
|
||||||
end
|
end
|
||||||
|
|
@ -163,29 +163,78 @@ end
|
||||||
def score_location(a_locidispid, b_locidispid, latency)
|
def score_location(a_locidispid, b_locidispid, latency)
|
||||||
Score.createx(a_locidispid, 'anodeid', 1, b_locidispid, 'bnodeid', 1, latency, nil)
|
Score.createx(a_locidispid, 'anodeid', 1, b_locidispid, 'bnodeid', 1, latency, nil)
|
||||||
end
|
end
|
||||||
|
def ip_from_num(num)
|
||||||
|
IPAddr.new(num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
def austin_ip
|
def austin_ip
|
||||||
IPAddr.new(0x0FFFFFFF, Socket::AF_INET).to_s
|
IPAddr.new(austin_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def austin_ip_as_num
|
||||||
|
0x0FFFFFFF
|
||||||
end
|
end
|
||||||
|
|
||||||
def dallas_ip
|
def dallas_ip
|
||||||
IPAddr.new(0x1FFFFFFF, Socket::AF_INET).to_s
|
IPAddr.new(dallas_ip_as_num, Socket::AF_INET).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def dallas_ip_as_num
|
||||||
|
0x1FFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def houston_ip
|
||||||
|
IPAddr.new(houston_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def houston_ip_as_num
|
||||||
|
0x2FFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def miami_ip
|
||||||
|
IPAddr.new(miami_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def miami_ip_as_num
|
||||||
|
0x5FFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_ip
|
||||||
|
IPAddr.new(seattle_ip_as_num, Socket::AF_INET).to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_ip_as_num
|
||||||
|
0xAFFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def create_geoip(locid)
|
||||||
|
geoiplocation = GeoIpLocations.find_by_locid(locid)
|
||||||
|
geoipblock = GeoIpBlocks.find_by_locid(locid)
|
||||||
|
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
||||||
|
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
||||||
|
end
|
||||||
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
def austin_geoip
|
def austin_geoip
|
||||||
geoiplocation = GeoIpLocations.find_by_locid(17192)
|
create_geoip(17192)
|
||||||
geoipblock = GeoIpBlocks.find_by_locid(17192)
|
|
||||||
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
|
||||||
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid) }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
def dallas_geoip
|
def dallas_geoip
|
||||||
geoiplocation = GeoIpLocations.find_by_locid(667)
|
create_geoip(667)
|
||||||
geoipblock = GeoIpBlocks.find_by_locid(667)
|
end
|
||||||
jamisp = JamIsp.find_by_beginip(geoipblock.beginip)
|
|
||||||
{jamisp: jamisp, geoiplocation: geoiplocation, geoipblock: geoipblock, locidispid: Score.compute_locidispid(geoiplocation.locid, jamisp.coid)}
|
# gets related models for an IP in the 1st block from the scores_better_test_data.sql
|
||||||
|
def houston_geoip
|
||||||
|
create_geoip(30350)
|
||||||
|
end
|
||||||
|
|
||||||
|
def miami_geoip
|
||||||
|
create_geoip(23565)
|
||||||
|
end
|
||||||
|
|
||||||
|
def seattle_geoip
|
||||||
|
create_geoip(1539)
|
||||||
end
|
end
|
||||||
|
|
||||||
# attempts to make the creation of a score more straightforward.
|
# attempts to make the creation of a score more straightforward.
|
||||||
|
|
@ -257,8 +306,7 @@ def verify_find_musician_score(score, current_user, target_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
visit '/client#/musicians'
|
visit '/client#/musicians'
|
||||||
hoverable = find(".musician-list-result[data-musician-id='#{target_user.id}'] .score-count#{expected[:latency_badge_selector]} ")
|
hoverable = find(".musician-list-result[data-musician-id='#{target_user.id}'] .latency#{expected[:latency_badge_selector]} ", text: expected[:latency_badge_text])
|
||||||
hoverable.find('img')['src'].include?("icon_#{expected[:color]}_score.png").should be_true
|
|
||||||
|
|
||||||
verify_score_hover(score, current_user, target_user, hoverable)
|
verify_score_hover(score, current_user, target_user, hoverable)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
# Set RAILS_ROOT and load the environment if it's not already loaded.
|
||||||
|
unless defined?(Rails)
|
||||||
|
ENV["RAILS_ROOT"] = File.expand_path("../../", __FILE__)
|
||||||
|
require File.expand_path("../../config/environment", __FILE__)
|
||||||
|
end
|
||||||
|
|
||||||
|
Teaspoon.configure do |config|
|
||||||
|
|
||||||
|
# Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to
|
||||||
|
# `http://localhost:3000/jasmine` to run your tests.
|
||||||
|
#config.mount_at = "/teaspoon"
|
||||||
|
|
||||||
|
# Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can
|
||||||
|
# be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`).
|
||||||
|
# Note: Defaults to `Rails.root` if nil.
|
||||||
|
#config.root = nil
|
||||||
|
|
||||||
|
# Paths that will be appended to the Rails assets paths
|
||||||
|
# Note: Relative to `config.root`.
|
||||||
|
#config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"]
|
||||||
|
|
||||||
|
# Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will
|
||||||
|
# be rendered as fixtures.
|
||||||
|
#config.fixture_paths = ["spec/javascripts/fixtures"]
|
||||||
|
|
||||||
|
# SUITES
|
||||||
|
#
|
||||||
|
# You can modify the default suite configuration and create new suites here. Suites are isolated from one another.
|
||||||
|
#
|
||||||
|
# When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can
|
||||||
|
# omit various directives and the ones defined in the default suite will be used.
|
||||||
|
#
|
||||||
|
# To run a specific suite
|
||||||
|
# - in the browser: http://localhost/teaspoon/[suite_name]
|
||||||
|
# - with the rake task: rake teaspoon suite=[suite_name]
|
||||||
|
# - with the cli: teaspoon --suite=[suite_name]
|
||||||
|
config.suite do |suite|
|
||||||
|
|
||||||
|
# Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for
|
||||||
|
# you -- which you can override with the directives below. This should be specified first, as it can override other
|
||||||
|
# directives.
|
||||||
|
# Note: If no version is specified, the latest is assumed.
|
||||||
|
#
|
||||||
|
# Available: jasmine[1.3.1, 2.0.0], mocha[1.10.0, 1.17.1] qunit[1.12.0, 1.14.0]
|
||||||
|
suite.use_framework :jasmine, "1.3.1"
|
||||||
|
|
||||||
|
# Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These
|
||||||
|
# files need to be within an asset path. You can add asset paths using the `config.asset_paths`.
|
||||||
|
#suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
|
||||||
|
|
||||||
|
# This suites spec helper, which can require additional support files. This file is loaded before any of your test
|
||||||
|
# files are loaded.
|
||||||
|
#suite.helper = "spec_helper"
|
||||||
|
|
||||||
|
# The core Teaspoon javascripts. It's recommended to include only the base files here, as you can require support
|
||||||
|
# libraries from your spec helper.
|
||||||
|
# Note: For CoffeeScript files use `"teaspoon/jasmine"` etc.
|
||||||
|
#
|
||||||
|
# Available: teaspoon-jasmine, teaspoon-mocha, teaspoon-qunit
|
||||||
|
#suite.javascripts = ["jasmine/1.3.1", "teaspoon-jasmine"]
|
||||||
|
|
||||||
|
# You can include your own stylesheets if you want to change how Teaspoon looks.
|
||||||
|
# Note: Spec related CSS can and should be loaded using fixtures.
|
||||||
|
#suite.stylesheets = ["teaspoon"]
|
||||||
|
|
||||||
|
# Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating
|
||||||
|
# a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance.
|
||||||
|
#
|
||||||
|
# Available: boot, boot_require_js
|
||||||
|
#suite.boot_partial = "boot"
|
||||||
|
|
||||||
|
# Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure.
|
||||||
|
#suite.body_partial = "body"
|
||||||
|
|
||||||
|
# Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The
|
||||||
|
# default excludes assets from vendor, gems and support libraries.<br/><br/>
|
||||||
|
#suite.no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
|
||||||
|
|
||||||
|
# Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a
|
||||||
|
# synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name.
|
||||||
|
#suite.hook :fixtures, proc{ }
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also
|
||||||
|
# be run in the default suite -- but can be focused into a more specific suite.
|
||||||
|
#config.suite :targeted do |suite|
|
||||||
|
# suite.matcher = "test/javascripts/targeted/*_test.{js,js.coffee,coffee}"
|
||||||
|
#end
|
||||||
|
|
||||||
|
# CONSOLE RUNNER SPECIFIC
|
||||||
|
#
|
||||||
|
# These configuration directives are applicable only when running via the rake task or command line interface. These
|
||||||
|
# directives can be overridden using the command line interface arguments or with ENV variables when using the rake
|
||||||
|
# task.
|
||||||
|
#
|
||||||
|
# Command Line Interface:
|
||||||
|
# teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js
|
||||||
|
#
|
||||||
|
# Rake:
|
||||||
|
# teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite
|
||||||
|
|
||||||
|
# Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver.
|
||||||
|
#
|
||||||
|
# Available: phantomjs, selenium
|
||||||
|
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
|
||||||
|
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
|
||||||
|
#config.driver = "phantomjs"
|
||||||
|
|
||||||
|
# Specify additional options for the driver.
|
||||||
|
#
|
||||||
|
# PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
|
||||||
|
# Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
|
||||||
|
#config.driver_options = nil
|
||||||
|
|
||||||
|
# Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be
|
||||||
|
# considered a failure. This is to avoid issues that can arise where tests stall.
|
||||||
|
#config.driver_timeout = 180
|
||||||
|
|
||||||
|
# Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used.
|
||||||
|
#config.server = nil
|
||||||
|
|
||||||
|
# Specify a port to run on a specific port, otherwise Teaspoon will use a random available port.
|
||||||
|
#config.server_port = nil
|
||||||
|
|
||||||
|
# Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may
|
||||||
|
# want to lower this if you know it shouldn't take long to start.
|
||||||
|
#config.server_timeout = 20
|
||||||
|
|
||||||
|
# Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have
|
||||||
|
# several suites, but in environments like CI this may not be desirable.
|
||||||
|
#config.fail_fast = true
|
||||||
|
|
||||||
|
# Specify the formatters to use when outputting the results.
|
||||||
|
# Note: Output files can be specified by using `"junit>/path/to/output.xml"`.
|
||||||
|
#
|
||||||
|
# Available: dot, documentation, clean, json, junit, pride, snowday, swayze_or_oprah, tap, tap_y, teamcity
|
||||||
|
#config.formatters = ["dot"]
|
||||||
|
|
||||||
|
# Specify if you want color output from the formatters.
|
||||||
|
#config.color = true
|
||||||
|
|
||||||
|
# Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to
|
||||||
|
# remove them, but in verbose applications this may not be desirable.
|
||||||
|
#config.suppress_log = false
|
||||||
|
|
||||||
|
# COVERAGE REPORTS / THRESHOLD ASSERTIONS
|
||||||
|
#
|
||||||
|
# Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and
|
||||||
|
# display coverage statistics.
|
||||||
|
#
|
||||||
|
# Coverage configurations are similar to suites. You can define several, and use different ones under different
|
||||||
|
# conditions.
|
||||||
|
#
|
||||||
|
# To run with a specific coverage configuration
|
||||||
|
# - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name]
|
||||||
|
# - with the cli: teaspoon --coverage=[coverage_name]
|
||||||
|
|
||||||
|
# Specify that you always want a coverage configuration to be used.
|
||||||
|
#config.use_coverage = nil
|
||||||
|
|
||||||
|
config.coverage do |coverage|
|
||||||
|
|
||||||
|
# Which coverage reports Instanbul should generate. Correlates directly to what Istanbul supports.
|
||||||
|
#
|
||||||
|
# Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity
|
||||||
|
#coverage.reports = ["text-summary", "html"]
|
||||||
|
|
||||||
|
# The path that the coverage should be written to - when there's an artifact to write to disk.
|
||||||
|
# Note: Relative to `config.root`.
|
||||||
|
#coverage.output_dir = "coverage"
|
||||||
|
|
||||||
|
# Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any
|
||||||
|
# aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil.
|
||||||
|
#coverage.statements = nil
|
||||||
|
#coverage.functions = nil
|
||||||
|
#coverage.branches = nil
|
||||||
|
#coverage.lines = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
https://github.com/ariya/phantomjs/issues/10522#issuecomment-39248521
|
||||||
|
|
||||||
|
var isFunction = function(o) {
|
||||||
|
return typeof o == 'function';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var bind,
|
||||||
|
slice = [].slice,
|
||||||
|
proto = Function.prototype,
|
||||||
|
featureMap;
|
||||||
|
|
||||||
|
featureMap = {
|
||||||
|
'function-bind': 'bind'
|
||||||
|
};
|
||||||
|
|
||||||
|
function has(feature) {
|
||||||
|
var prop = featureMap[feature];
|
||||||
|
return isFunction(proto[prop]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for missing features
|
||||||
|
if (!has('function-bind')) {
|
||||||
|
// adapted from Mozilla Developer Network example at
|
||||||
|
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
||||||
|
bind = function bind(obj) {
|
||||||
|
var args = slice.call(arguments, 1),
|
||||||
|
self = this,
|
||||||
|
nop = function() {
|
||||||
|
},
|
||||||
|
bound = function() {
|
||||||
|
return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
|
||||||
|
};
|
||||||
|
nop.prototype = this.prototype || {}; // Firefox cries sometimes if prototype is undefined
|
||||||
|
bound.prototype = new nop();
|
||||||
|
return bound;
|
||||||
|
};
|
||||||
|
proto.bind = bind;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* Simple JavaScript Inheritance for ES 5.1 ( includes polyfill for IE < 9 )
|
||||||
|
* based on http://ejohn.org/blog/simple-javascript-inheritance/
|
||||||
|
* (inspired by base2 and Prototype)
|
||||||
|
* MIT Licensed.
|
||||||
|
*/
|
||||||
|
(function (global) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (!Object.create) {
|
||||||
|
Object.create = (function () {
|
||||||
|
function F() {
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (o) {
|
||||||
|
if (arguments.length != 1) {
|
||||||
|
throw new Error("Object.create implementation only accepts one parameter.");
|
||||||
|
}
|
||||||
|
F.prototype = o;
|
||||||
|
return new F();
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
var fnTest = /xyz/.test(function () {
|
||||||
|
xyz;
|
||||||
|
}) ? /\b_super\b/ : /.*/;
|
||||||
|
|
||||||
|
// The base Class implementation (does nothing)
|
||||||
|
function BaseClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Class that inherits from this class
|
||||||
|
BaseClass.extend = function (props) {
|
||||||
|
var _super = this.prototype;
|
||||||
|
|
||||||
|
// Instantiate a base class (but only create the instance,
|
||||||
|
// don't run the init constructor)
|
||||||
|
var proto = Object.create(_super);
|
||||||
|
|
||||||
|
// Copy the properties over onto the new prototype
|
||||||
|
for (var name in props) {
|
||||||
|
// Check if we're overwriting an existing function
|
||||||
|
proto[name] = typeof props[name] === "function" &&
|
||||||
|
typeof _super[name] === "function" && fnTest.test(props[name]) ?
|
||||||
|
(function (name, fn) {
|
||||||
|
return function () {
|
||||||
|
var tmp = this._super;
|
||||||
|
|
||||||
|
// Add a new ._super() method that is the same method
|
||||||
|
// but on the super-class
|
||||||
|
this._super = _super[name];
|
||||||
|
|
||||||
|
// The method only need to be bound temporarily, so we
|
||||||
|
// remove it when we're done executing
|
||||||
|
var ret = fn.apply(this, arguments);
|
||||||
|
this._super = tmp;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
})(name, props[name]) :
|
||||||
|
props[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The new constructor
|
||||||
|
var newClass = typeof proto.init === "function" ?
|
||||||
|
proto.init : // All construction is actually done in the init method
|
||||||
|
function () {};
|
||||||
|
|
||||||
|
// Populate our constructed prototype object
|
||||||
|
newClass.prototype = proto;
|
||||||
|
|
||||||
|
// Enforce the constructor to be what we expect
|
||||||
|
proto.constructor = newClass;
|
||||||
|
|
||||||
|
// And make this class extendable
|
||||||
|
newClass.extend = BaseClass.extend;
|
||||||
|
|
||||||
|
return newClass;
|
||||||
|
};
|
||||||
|
|
||||||
|
// export
|
||||||
|
global.Class = BaseClass;
|
||||||
|
})(this);
|
||||||
Loading…
Reference in New Issue