Compare commits
15 Commits
develop
...
feature/ja
| Author | SHA1 | Date |
|---|---|---|
|
|
8fc54eae06 | |
|
|
e6ce9d1d02 | |
|
|
537e4d3de4 | |
|
|
63369475a3 | |
|
|
9a73bec85b | |
|
|
9402d55d21 | |
|
|
276c9b1a53 | |
|
|
4c1ca84996 | |
|
|
45a8a6897c | |
|
|
303e186eff | |
|
|
c1e9e02647 | |
|
|
5f014b4139 | |
|
|
ed30cfc921 | |
|
|
76b2710b84 | |
|
|
0bb635cf5d |
|
|
@ -299,4 +299,5 @@ enhance_band_profile.sql
|
|||
alter_band_profile_rate_defaults.sql
|
||||
repair_band_profile.sql
|
||||
jam_track_onboarding_enhancements.sql
|
||||
jam_track_name_drop_unique.sql
|
||||
jam_track_name_drop_unique.sql
|
||||
jam_track_searchability.sql
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN search_tsv tsvector;
|
||||
ALTER TABLE jam_tracks ADD COLUMN artist_tsv tsvector;
|
||||
ALTER TABLE jam_tracks ADD COLUMN name_tsv tsvector;
|
||||
|
||||
CREATE FUNCTION jam_tracks_update_tsv() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
new.search_tsv = to_tsvector('public.jamenglish', COALESCE(NEW.original_artist, '') || ' ' || COALESCE(NEW.name, '') || ' ' || COALESCE(NEW.additional_info, ''));
|
||||
new.artist_tsv = to_tsvector('public.jamenglish', COALESCE(NEW.original_artist, ''));
|
||||
new.name_tsv = to_tsvector('public.jamenglish', COALESCE(NEW.name, ''));
|
||||
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
|
||||
ON jam_tracks FOR EACH ROW EXECUTE PROCEDURE
|
||||
jam_tracks_update_tsv();
|
||||
|
||||
CREATE INDEX jam_tracks_search_tsv_index ON jam_tracks USING gin(search_tsv);
|
||||
CREATE INDEX jam_tracks_artist_tsv_index ON jam_tracks USING gin(artist_tsv);
|
||||
CREATE INDEX jam_tracks_name_tsv_index ON jam_tracks USING gin(name_tsv);
|
||||
|
||||
CREATE INDEX jam_tracks_name_key ON jam_tracks USING btree (name);
|
||||
CREATE INDEX jam_tracks_original_artist_key ON jam_tracks USING btree (original_artist);
|
||||
CREATE INDEX jam_tracks_status_key ON jam_tracks USING btree (status);
|
||||
|
||||
|
||||
UPDATE jam_tracks SET original_artist=original_artist, name=name, additional_info=additional_info;
|
||||
|
|
@ -182,6 +182,10 @@ module JamRuby
|
|||
finish("success", nil)
|
||||
end
|
||||
|
||||
def add_vendor_metadata(metalocation)
|
||||
|
||||
end
|
||||
|
||||
def is_tency_storage?
|
||||
assert_storage_set
|
||||
@storage_format == 'Tency'
|
||||
|
|
|
|||
|
|
@ -215,6 +215,26 @@ module JamRuby
|
|||
JamTrack.where("original_artist=?", artist_name).all
|
||||
end
|
||||
|
||||
# special case of index
|
||||
def autocomplete(options, user)
|
||||
|
||||
if options[:match].blank?
|
||||
return {artists: [], songs: []}
|
||||
end
|
||||
|
||||
options[:limit] = options[:limit] || 5
|
||||
|
||||
options[:artist_search] = options[:match]
|
||||
artists, pager = artist_index(options, user)
|
||||
|
||||
options.delete(:artist_search)
|
||||
options[:song_search] = options[:match]
|
||||
options[:sort_by] = 'jamtrack'
|
||||
songs, pager = index(options, user)
|
||||
|
||||
{artists: artists, songs:songs}
|
||||
end
|
||||
|
||||
def index(options, user)
|
||||
if options[:page]
|
||||
page = options[:page].to_i
|
||||
|
|
@ -252,6 +272,27 @@ module JamRuby
|
|||
query = query.where("jam_track_rights.user_id = ?", user.id)
|
||||
end
|
||||
|
||||
if options[:search]
|
||||
tsquery = Search.create_tsquery(options[:search])
|
||||
if tsquery
|
||||
query = query.where("(search_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
|
||||
end
|
||||
end
|
||||
|
||||
if options[:artist_search]
|
||||
tsquery = Search.create_tsquery(options[:artist_search])
|
||||
if tsquery
|
||||
query = query.where("(artist_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
|
||||
end
|
||||
end
|
||||
|
||||
if options[:song_search]
|
||||
tsquery = Search.create_tsquery(options[:song_search])
|
||||
if tsquery
|
||||
query = query.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
|
||||
end
|
||||
end
|
||||
|
||||
if options[:artist].present?
|
||||
query = query.where("original_artist=?", options[:artist])
|
||||
end
|
||||
|
|
@ -266,7 +307,13 @@ module JamRuby
|
|||
query = query.order('jam_tracks.original_artist')
|
||||
else
|
||||
query = query.group("jam_tracks.id")
|
||||
query = query.order('jam_tracks.original_artist, jam_tracks.name')
|
||||
if options[:sort_by] == 'jamtrack'
|
||||
query = query.order('jam_tracks.name')
|
||||
else
|
||||
query = query.order('jam_tracks.original_artist, jam_tracks.name')
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
query = query.where("jam_tracks.status = ?", 'Production') unless user.admin
|
||||
|
|
@ -279,13 +326,14 @@ module JamRuby
|
|||
query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}' and jam_track_tracks.track_type != 'Master'") unless options[:instrument].blank?
|
||||
query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank?
|
||||
|
||||
count = query.total_entries
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
if count == 0
|
||||
[query, nil, count]
|
||||
elsif query.length < limit
|
||||
[query, nil]
|
||||
[query, nil, count]
|
||||
else
|
||||
[query, start + limit]
|
||||
[query, start + limit, count]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -327,6 +375,14 @@ module JamRuby
|
|||
|
||||
query = query.where("jam_tracks.status = ?", 'Production') unless user.admin
|
||||
|
||||
if options[:artist_search]
|
||||
tsquery = Search.create_tsquery(options[:artist_search])
|
||||
if tsquery
|
||||
query = query.where("(artist_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
unless options[:genre].blank?
|
||||
query = query.joins(:genres)
|
||||
query = query.where('genre_id = ? ', options[:genre])
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ module JamRuby
|
|||
args = args + ":*"
|
||||
args
|
||||
end
|
||||
|
||||
def order_param(params, keys=M_ORDERING_KEYS)
|
||||
ordering = params[:orderby]
|
||||
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
|
||||
|
|
|
|||
|
|
@ -159,8 +159,8 @@ describe JamTrack do
|
|||
|
||||
describe "index" do
|
||||
it "empty query" do
|
||||
query, pager = JamTrack.index({}, user)
|
||||
query.size.should == 0
|
||||
query, pager, count = JamTrack.index({}, user)
|
||||
count.should == 0
|
||||
end
|
||||
|
||||
it "sorts by name" do
|
||||
|
|
@ -190,24 +190,24 @@ describe JamTrack do
|
|||
jam_track1.save!
|
||||
jam_track2.save!
|
||||
|
||||
query, pager = JamTrack.index({genre: 'rock'}, user)
|
||||
query.size.should == 1
|
||||
query, pager, count = JamTrack.index({genre: 'rock'}, user)
|
||||
count.should == 1
|
||||
query[0].should eq(jam_track1)
|
||||
|
||||
query, pager = JamTrack.index({genre: 'asian'}, user)
|
||||
query.size.should == 1
|
||||
query, pager, count = JamTrack.index({genre: 'asian'}, user)
|
||||
count.should == 1
|
||||
query[0].should eq(jam_track2)
|
||||
|
||||
query, pager = JamTrack.index({genre: 'african'}, user)
|
||||
query.size.should == 0
|
||||
query, pager, count = JamTrack.index({genre: 'african'}, user)
|
||||
count.should == 0
|
||||
end
|
||||
|
||||
it "supports showing purchased only" do
|
||||
jam_track1 = FactoryGirl.create(:jam_track_with_tracks, name: 'a')
|
||||
|
||||
# no results yet
|
||||
query, pager = JamTrack.index({show_purchased_only:true}, user)
|
||||
query.size.should == 0
|
||||
query, pager, count = JamTrack.index({show_purchased_only:true}, user)
|
||||
count.should == 0
|
||||
|
||||
# but after the user buys it, it is returned
|
||||
FactoryGirl.create(:jam_track_right, jam_track: jam_track1, user: user)
|
||||
|
|
@ -215,6 +215,25 @@ describe JamTrack do
|
|||
query.size.should == 1
|
||||
query[0].should eq(jam_track1)
|
||||
end
|
||||
|
||||
it "full text search" do
|
||||
jam_track1 = FactoryGirl.create(:jam_track_with_tracks, name: 'Take a Chance On Me', original_artist: 'ABBA')
|
||||
jam_track2 = FactoryGirl.create(:jam_track_with_tracks, name: 'Nothing Chance', original_artist: 'ABBA')
|
||||
|
||||
query, pager = JamTrack.index({search: 'Take'}, user)
|
||||
query.size.should == 1
|
||||
query[0].should eq(jam_track1)
|
||||
|
||||
query, pager = JamTrack.index({search: 'ABB'}, user)
|
||||
query.size.should == 2
|
||||
|
||||
query, pager = JamTrack.index({search: 'Chance'}, user)
|
||||
query.size.should == 2
|
||||
|
||||
query, pager = JamTrack.index({search: 'Chan'}, user)
|
||||
query.size.should == 2
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ gem 'react-rails', '~> 1.0'
|
|||
source 'https://rails-assets.org' do
|
||||
gem 'rails-assets-reflux'
|
||||
gem 'rails-assets-classnames'
|
||||
gem 'rails-assets-react-select'
|
||||
end
|
||||
|
||||
#group :development, :production do
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
var $templateOpenSlots = null;
|
||||
var $templateAccountPendingRsvp = null;
|
||||
var $templateAccountSessionDetail = null;
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
var invitationDialog = null;
|
||||
var inviteMusiciansUtil = null;
|
||||
var friendInput=null;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
}
|
||||
})
|
||||
.fail(function() {
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
window.location = '/client#/jamtrack/search'
|
||||
window.location.reload();
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class CheckoutUtils
|
|||
|
||||
@logger.debug("deleted preserve billing");
|
||||
|
||||
unless $.cookie(@cookie_name)?
|
||||
if $.cookie(@cookie_name)?
|
||||
@logger.error("after deleting the preserve billing cookie, it still exists!")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
$browserJamTrackBtn.click(function() {
|
||||
app.layout.closeDialog('getting-started')
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
window.location = '/client#/jamtrack/search'
|
||||
return false;
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,58 @@
|
|||
var $templateOpenJamTrackRow = null;
|
||||
var $downloadedTrackHelp = null;
|
||||
var $whatAreJamTracks = null;
|
||||
var $searchBtn = null;
|
||||
var sampleRate = null;
|
||||
var sampleRateForFilename = null;
|
||||
var searchQuery = null;
|
||||
var cookieName = 'jamtrack_session_search'
|
||||
|
||||
function search(searchType, searchData) {
|
||||
window.JamTrackSearchInput = searchData;
|
||||
searchQuery = {searchType: searchType, searchData: searchData}
|
||||
$.cookie(cookieName, JSON.stringify(searchQuery))
|
||||
doSearch();
|
||||
}
|
||||
|
||||
function userSearch(e) {
|
||||
e.preventDefault();
|
||||
searchQuery = {searchType: 'user-input', searchData: window.JamTrackSearchInput}
|
||||
$.cookie(cookieName, JSON.stringify(searchQuery))
|
||||
doSearch();
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
emptyList();
|
||||
resetPagination();
|
||||
|
||||
app.user().done(function(user) {
|
||||
|
||||
if (user.purchased_jamtracks_count > perPage) {
|
||||
|
||||
searchQuery = $.cookie(cookieName)
|
||||
if (!searchQuery) {
|
||||
searchQuery = {searchType: 'user-input', searchData: ''}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
searchQuery = JSON.parse(searchQuery)
|
||||
}
|
||||
catch (e) {
|
||||
searchQuery = {searchType: 'user-input', searchData: ''}
|
||||
logger.error("unable to parse search query: " + e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getPurchasedJamTracks(0)
|
||||
.done(function (data, textStatus, jqXHR) {
|
||||
// initialize pagination
|
||||
var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected, 20)
|
||||
$paginatorHolder.append($paginator);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function emptyList() {
|
||||
$tbody.empty();
|
||||
|
|
@ -30,19 +79,13 @@
|
|||
}
|
||||
|
||||
function afterShow() {
|
||||
|
||||
$dialog.data('result', null)
|
||||
emptyList();
|
||||
resetPagination();
|
||||
showing = true;
|
||||
sampleRate = context.jamClient.GetSampleRate()
|
||||
sampleRateForFilename = sampleRate == 48 ? '48' : '44';
|
||||
doSearch();
|
||||
|
||||
getPurchasedJamTracks(0)
|
||||
.done(function(data, textStatus, jqXHR) {
|
||||
// initialize pagination
|
||||
var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected)
|
||||
$paginatorHolder.append($paginator);
|
||||
});
|
||||
|
||||
}
|
||||
function afterHide() {
|
||||
|
|
@ -55,7 +98,21 @@
|
|||
}
|
||||
|
||||
function getPurchasedJamTracks(page) {
|
||||
return rest.getPurchasedJamTracks({page:page + 1, per_page:10})
|
||||
|
||||
var query = {page:page + 1, per_page:10}
|
||||
if (searchQuery && searchQuery.searchData && searchQuery.searchData.length > 0 && searchQuery.searchType && searchQuery.searchType.length > 0) {
|
||||
|
||||
if (searchQuery.searchType == 'user-input') {
|
||||
query.search = searchQuery.searchData
|
||||
}
|
||||
else if(searchQuery.searchType == 'artist-select') {
|
||||
query.artist_search = searchQuery.searchData
|
||||
}
|
||||
else if(searchQuery.searchType == 'song-select') {
|
||||
query.song_search = searchQuery.searchData
|
||||
}
|
||||
}
|
||||
return rest.getPurchasedJamTracks(query)
|
||||
.done(function(purchasedJamTracks) {
|
||||
|
||||
emptyList();
|
||||
|
|
@ -104,6 +161,8 @@
|
|||
|
||||
context.JK.helpBubble($whatAreJamTracks, 'no help yet for this topic', {}, {positions:['bottom'], offsetParent: $dialog})
|
||||
$whatAreJamTracks.on('click', false) // no help yet
|
||||
|
||||
$searchBtn.on('click', userSearch)
|
||||
}
|
||||
|
||||
function initialize(){
|
||||
|
|
@ -121,6 +180,7 @@
|
|||
$templateOpenJamTrackRow = $('#template-jam-track-row')
|
||||
$downloadedTrackHelp = $dialog.find('.downloaded-jamtrack-help')
|
||||
$whatAreJamTracks = $dialog.find('.what-are-jamtracks')
|
||||
$searchBtn = $dialog.find('.search-btn')
|
||||
|
||||
registerStaticEvents();
|
||||
};
|
||||
|
|
@ -128,6 +188,7 @@
|
|||
|
||||
this.initialize = initialize;
|
||||
this.isShowing = function isShowing() { return showing; }
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
|
|||
@logger.debug "downloadCheck"
|
||||
|
||||
retry: () =>
|
||||
@logger.debug "user initiated retry"
|
||||
@path = []
|
||||
@path.push('retry')
|
||||
this.clear()
|
||||
|
|
|
|||
|
|
@ -43,6 +43,23 @@
|
|||
context.JK.dropdown($('select', parentSelector));
|
||||
}
|
||||
|
||||
function render2($select, notSelectedString) {
|
||||
if(!notSelectedString) {
|
||||
notSelectedString = 'Any Genre'
|
||||
}
|
||||
$select.empty();
|
||||
$select.append('<option value="">' + notSelectedString + '</option>');
|
||||
var template = $('#template-genre-option').html();
|
||||
$.each(_genres, function(index, value) {
|
||||
// value will be a dictionary entry from _genres:
|
||||
// { value: xxx, label: yyy }
|
||||
var genreOptionHtml = context.JK.fillTemplate(template, value);
|
||||
$select.append(genreOptionHtml);
|
||||
});
|
||||
context.JK.dropdown($select);
|
||||
}
|
||||
|
||||
|
||||
function getSelectedGenres(parentSelector) {
|
||||
var selectedGenres = [];
|
||||
var selectedVal = $('select', parentSelector).val();
|
||||
|
|
@ -112,6 +129,10 @@
|
|||
render: function() {
|
||||
var _args = arguments;
|
||||
context.JK.GenreSelectorDeferred.done(function(){render.apply(self, _args)})
|
||||
},
|
||||
render2: function() {
|
||||
var _args = arguments;
|
||||
context.JK.GenreSelectorDeferred.done(function(){render2.apply(self, _args)})
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
var logger = context.JK.logger;
|
||||
var rest = new context.JK.Rest();
|
||||
var _instruments = []; // will be list of structs: [ {label:xxx, value:yyy}, {...}, ... ]
|
||||
var _instrumentsSorted = [];
|
||||
var _rsvp = false;
|
||||
var _noICheck = false;
|
||||
if (typeof(_parentSelector)=="undefined") {_parentSelector=null}
|
||||
|
|
@ -35,6 +36,17 @@
|
|||
label: this.description
|
||||
});
|
||||
});
|
||||
|
||||
_instrumentsSorted = _instruments.slice().sort(sortAlpha)
|
||||
}
|
||||
|
||||
function sortAlpha(a, b) {
|
||||
if (a.value == b.value)
|
||||
return 0;
|
||||
if (a.value < b.value)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
function render(parentSelector, userInstruments) {
|
||||
|
|
@ -85,6 +97,23 @@
|
|||
|
||||
}
|
||||
|
||||
function renderDropdown($select, notSelectedString) {
|
||||
if(!notSelectedString) {
|
||||
notSelectedString = 'Any Instrument'
|
||||
}
|
||||
$select.empty();
|
||||
$select.append('<option value="">' + notSelectedString + '</option>');
|
||||
var template = $('#template-instrument-option-simple').html();
|
||||
$.each(_instrumentsSorted, function(index, value) {
|
||||
// value will be a dictionary entry from _genres:
|
||||
// { value: xxx, label: yyy }
|
||||
var instrumentOptionHtml = context.JK.fillTemplate(template, value);
|
||||
$select.append(instrumentOptionHtml);
|
||||
});
|
||||
context.JK.dropdown($select);
|
||||
}
|
||||
|
||||
|
||||
function getSelectedInstruments() {
|
||||
var selectedInstruments = [];
|
||||
var $selectedVal = $('input[type="checkbox"]:checked', _parentSelector);
|
||||
|
|
@ -152,6 +181,10 @@
|
|||
var _args = arguments;
|
||||
context.JK.InstrumentSelectorDeferred.done(function(){render.apply(self, _args)})
|
||||
}
|
||||
this.renderDropdown = function() {
|
||||
var _args = arguments;
|
||||
context.JK.InstrumentSelectorDeferred.done(function(){renderDropdown.apply(self, _args)})
|
||||
}
|
||||
});
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -1576,6 +1576,15 @@
|
|||
});
|
||||
}
|
||||
|
||||
function autocompleteJamTracks(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/jamtracks/autocomplete?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getJamTrackArtists(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
|
|
@ -1649,14 +1658,15 @@
|
|||
type: "POST",
|
||||
url: '/api/shopping_carts/add_jamtrack?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'applications/json'
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getShoppingCarts() {
|
||||
// the need for the time de-duplicator indicates we are doing something wrong on the server
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/shopping_carts',
|
||||
url: '/api/shopping_carts?time=' + new Date().getTime(),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
|
|
@ -1966,6 +1976,7 @@
|
|||
this.getJamTrack = getJamTrack;
|
||||
this.getJamTrackWithArtistInfo = getJamTrackWithArtistInfo;
|
||||
this.getJamTracks = getJamTracks;
|
||||
this.autocompleteJamTracks = autocompleteJamTracks;
|
||||
this.getJamTrackArtists = getJamTrackArtists;
|
||||
this.getPurchasedJamTracks = getPurchasedJamTracks;
|
||||
this.getPaymentHistory = getPaymentHistory;
|
||||
|
|
|
|||
|
|
@ -109,9 +109,7 @@ context.JK.JamTrackPreview = class JamTrackPreview
|
|||
@sound.unload()
|
||||
|
||||
removeNowPlaying: () =>
|
||||
context.JK.JamTrackPreview.nowPlaying.splice(this)
|
||||
if context.JK.JamTrackPreview.nowPlaying.length > 0
|
||||
@logger.warn("multiple jamtrack previews playing")
|
||||
context.JamTrackPreviewActions.stoppedPlaying(this)
|
||||
|
||||
|
||||
onHowlerEnd: () =>
|
||||
|
|
@ -153,10 +151,7 @@ context.JK.JamTrackPreview = class JamTrackPreview
|
|||
|
||||
@logger.debug("play issued for jam track preview")
|
||||
@sound.play()
|
||||
for playingSound in context.JK.JamTrackPreview.nowPlaying
|
||||
playingSound.issueStop()
|
||||
context.JK.JamTrackPreview.nowPlaying = []
|
||||
context.JK.JamTrackPreview.nowPlaying.push(this)
|
||||
context.JamTrackPreviewActions.startedPlaying(this)
|
||||
@playButton.addClass('hidden')
|
||||
@stopButton.removeClass('hidden')
|
||||
|
||||
|
|
@ -182,7 +177,4 @@ context.JK.JamTrackPreview = class JamTrackPreview
|
|||
return false
|
||||
|
||||
|
||||
context.JK.JamTrackPreview.nowPlaying = []
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
else
|
||||
@availability.val('')
|
||||
|
||||
if window.history.replaceState #ie9 proofing
|
||||
if window.history.replaceState #ie9 proofing
|
||||
window.history.replaceState({}, "", "/client#/jamtrackBrowse")
|
||||
|
||||
getParams:() =>
|
||||
|
|
@ -448,6 +448,7 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
this.handleExpanded(jamtrackRecord)
|
||||
|
||||
initialize:() =>
|
||||
|
||||
screenBindings =
|
||||
'beforeShow': this.beforeShow
|
||||
'afterShow': this.afterShow
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ context.JK.JamTrackLanding = class JamTrackLanding
|
|||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
@app.bindScreen('jamtrackLanding', screenBindings)
|
||||
|
||||
#@app.bindScreen('jamtrackLanding', screenBindings)
|
||||
@screen = $('#jamtrackLanding')
|
||||
@noFreeJamTrack = @screen.find('.no-free-jamtrack')
|
||||
@freeJamTrack = @screen.find('.free-jamtrack')
|
||||
|
|
@ -64,14 +65,14 @@ context.JK.JamTrackLanding = class JamTrackLanding
|
|||
|
||||
# client#/jamtrack
|
||||
for artist in artists
|
||||
artistLink = "<a href='client?artist=#{encodeURIComponent(artist.original_artist)}#/jamtrackBrowse' class='artist-link' artist='#{artist.original_artist}'>#{artist.original_artist} (#{artist.song_count})</a>"
|
||||
artistLink = "<a href='client?artist=#{encodeURIComponent(artist.original_artist)}#/jamtrack/search' class='artist-link' artist='#{artist.original_artist}'>#{artist.original_artist} (#{artist.song_count})</a>"
|
||||
@bandList.append("<li>#{artistLink}</li>")
|
||||
|
||||
# We don't want to do a full page load if this is clicked on here:
|
||||
bindArtistLinks:() =>
|
||||
that=this
|
||||
@bandList.on "click", "a.artist-link", (event)->
|
||||
context.location="client#/jamtrackBrowse"
|
||||
context.location="client#/jamtrack/search"
|
||||
if window.history.replaceState # ie9 proofing
|
||||
window.history.replaceState({}, "", this.href)
|
||||
event.preventDefault()
|
||||
|
|
|
|||
|
|
@ -577,6 +577,8 @@
|
|||
|
||||
$(document).triggerHandler(EVENTS.SCREEN_CHANGED, {previousScreen: previousScreen, newScreen: currentScreen})
|
||||
|
||||
context.JamTrackPreviewActions.screenChange()
|
||||
|
||||
screenEvent(currentScreen, 'beforeShow', data);
|
||||
|
||||
// For now -- it seems we want it open always.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
* @param onPageSelected when a new page is selected. receives one argument; the page number.
|
||||
* the function should return a deferred object (whats returned by $.ajax), and that response has to have a 'total-entries' header set
|
||||
*/
|
||||
create:function(totalEntries, perPage, currentPage, onPageSelected) {
|
||||
create:function(totalEntries, perPage, currentPage, onPageSelected, maxPages) {
|
||||
|
||||
if(this.$templatePaginator === null) {
|
||||
this.$templatePaginator = $('#template-paginator')
|
||||
|
|
@ -100,6 +100,13 @@
|
|||
|
||||
var pages = calculatePages(totalEntries, perPage);
|
||||
|
||||
|
||||
if(maxPages) {
|
||||
if((totalEntries / perPage) > maxPages) {
|
||||
pages = calculatePages(maxPages * perPage, perPage);
|
||||
}
|
||||
}
|
||||
|
||||
var options = { pages: pages,
|
||||
currentPage: currentPage };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//= require react-input-autosize
|
||||
//= require react-select
|
||||
//= require_directory ./react-components/helpers
|
||||
//= require_directory ./react-components/actions
|
||||
//= require ./react-components/stores/AppStore
|
||||
|
|
@ -13,4 +15,5 @@
|
|||
//= require_directory ./react-components/stores
|
||||
//= require_directory ./react-components/mixins
|
||||
//= require_directory ./react-components
|
||||
//= require_directory ./react-components/landing
|
||||
|
||||
//= require_directory ./react-components/landing
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
context = window
|
||||
MIX_MODES = context.JK.MIX_MODES
|
||||
|
||||
|
||||
@JamTrackAutoComplete = React.createClass({
|
||||
|
||||
EVENTS: context.JK.EVENTS
|
||||
rest: context.JK.Rest()
|
||||
logger: context.JK.logger
|
||||
|
||||
|
||||
render: () ->
|
||||
|
||||
window.JamTrackSearchInput = '' unless window.JamTrackSearchInput? # can't pass null to react-select
|
||||
|
||||
searchValue = if @state.search == 'SEPARATOR' then '' else window.JamTrackSearchInput
|
||||
|
||||
`<Select
|
||||
placeholder="Search for JamTracks"
|
||||
name="search-field"
|
||||
asyncOptions={this.getOptions}
|
||||
autoload={false}
|
||||
value={searchValue}
|
||||
onChange={this.onSelectChange}
|
||||
onBlur={this.onSelectBlur}
|
||||
onFocus={this.onSelectFocus}
|
||||
className="autocompleter"
|
||||
cacheAsyncResults={false}
|
||||
filterOption={this.filterOption}
|
||||
clearable={false}
|
||||
/>`
|
||||
|
||||
getInitialState: () ->
|
||||
({search: ''})
|
||||
|
||||
filterOption:() ->
|
||||
true
|
||||
|
||||
onSelectChange: (val) ->
|
||||
#@logger.debug("CHANGE #{val}")
|
||||
|
||||
return false unless val?
|
||||
|
||||
if typeof @props.onSearch is 'string'
|
||||
searchFunction = eval(@props.onSearch)
|
||||
else
|
||||
searchFunction = @props.onSearch
|
||||
|
||||
search_type
|
||||
if val.indexOf('ARTIST=') == 0
|
||||
search_type = 'artist-select'
|
||||
artist = val['ARTIST='.length..-1]
|
||||
searchFunction(search_type, artist)
|
||||
else if val.indexOf('SONG=') == 0
|
||||
search_type = 'song-select'
|
||||
song = val['SONG='.length..-1]
|
||||
searchFunction(search_type, song)
|
||||
else
|
||||
@logger.debug("user selected separator")
|
||||
# this is to signal to the component that the separator was selected, and it has code in render to negate the selection
|
||||
setTimeout((() =>
|
||||
@setState({search:val})
|
||||
), 1)
|
||||
|
||||
return false
|
||||
|
||||
|
||||
onSelectFocus: (e) ->
|
||||
e.preventDefault()
|
||||
window.JamTrackSearchInput = ''
|
||||
@setState({search:''})
|
||||
|
||||
onSelectBlur: (e) ->
|
||||
|
||||
#@logger.debug("blur time")
|
||||
|
||||
#@search()
|
||||
|
||||
|
||||
getOptions: (input, callback) =>
|
||||
|
||||
#@logger.debug("getOptions input #{input}", this)
|
||||
|
||||
# sigh. ugly global
|
||||
window.JamTrackSearchInput = input
|
||||
|
||||
if !input? || input.length == 0
|
||||
callback(null, {options: [], complete: false})
|
||||
return
|
||||
|
||||
@rest.autocompleteJamTracks({match:input, limit:5})
|
||||
.done((autocomplete) =>
|
||||
|
||||
options = []
|
||||
for artist in autocomplete.artists
|
||||
options.push { value: "ARTIST=#{artist.original_artist}", label: "Artist: #{artist.original_artist}" }
|
||||
|
||||
if options.length > 0 && autocomplete.songs.length > 0
|
||||
options.push { value: 'SEPARATOR', label: "---------------"}
|
||||
|
||||
for jamtrack in autocomplete.songs
|
||||
options.push { value: "SONG=#{jamtrack.name}", label: "Song: #{jamtrack.name}" }
|
||||
|
||||
callback(null, {options: options, complete: false})
|
||||
)
|
||||
})
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
context = window
|
||||
MIX_MODES = context.JK.MIX_MODES
|
||||
|
||||
|
||||
@JamTrackFilterScreen = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore,"onAppInit")]
|
||||
|
||||
LIMIT: 20
|
||||
instrument_logo_map: context.JK.getInstrumentIconMap24()
|
||||
|
||||
computeWeight: (jam_track_track, instrument) ->
|
||||
weight = switch
|
||||
when jam_track_track.track_type == 'Master' then 0
|
||||
when jam_track_track.instrument?.id == instrument then 1 + jam_track_track.position
|
||||
else 10000 + jam_track_track.position
|
||||
|
||||
render: () ->
|
||||
|
||||
searchText = if @state.first_search then 'SEARCH' else 'SEARCH AGAIN'
|
||||
|
||||
uiJamTracks = []
|
||||
for jamtrack in @state.jamtracks
|
||||
trackRow = context._.clone(jamtrack)
|
||||
trackRow.track_cnt = jamtrack.tracks.length
|
||||
trackRow.tracks = []
|
||||
|
||||
# if an instrument is selected by the user, then re-order any jam tracks with a matching instrument to the top
|
||||
|
||||
instrument = @instrument.val() if @instrument?
|
||||
if instrument?
|
||||
jamtrack.tracks.sort((a, b) =>
|
||||
aWeight = @computeWeight(a, instrument)
|
||||
bWeight = @computeWeight(b, instrument)
|
||||
return aWeight - bWeight
|
||||
)
|
||||
|
||||
for track in jamtrack.tracks
|
||||
trackRow.tracks.push(track)
|
||||
if track.track_type=='Master'
|
||||
track.instrument_desc = "Master"
|
||||
else
|
||||
inst = '../assets/content/icon_instrument_default24.png'
|
||||
if track.instrument?
|
||||
if track.instrument.id in @instrument_logo_map
|
||||
inst = @instrument_logo_map[track.instrument.id].asset
|
||||
track.instrument_desc = track.instrument.description
|
||||
track.instrument_url = inst
|
||||
|
||||
if track.part != ''
|
||||
track.instrument_desc += ' (' + track.part + ')'
|
||||
|
||||
trackRow.free_state = if context.JK.currentUserFreeJamTrack then 'free' else 'non-free'
|
||||
|
||||
trackRow.is_free = trackRow.free_state == 'free'
|
||||
|
||||
uiJamTracks.push trackRow
|
||||
|
||||
|
||||
jamtracks = []
|
||||
|
||||
|
||||
for jamtrack in uiJamTracks
|
||||
|
||||
jamtrackPricesClasses = { "jamtrack-price" : true }
|
||||
jamtrackPricesClasses[jamtrack.free_state] = true
|
||||
jamtrackPricesClasses = classNames(jamtrackPricesClasses)
|
||||
|
||||
tracks = []
|
||||
for track in jamtrack.tracks
|
||||
tracks.push `<div className="jamtrack-track hidden" key={track.id} data-jamtrack-track-id={track.id}>
|
||||
<div className="jamtrack-preview">
|
||||
<JamTrackPreview jamTrack={jamtrack} jamTrackTrack={track} options={{master_shows_duration: true, color:'gray'}} />
|
||||
<div className="clearall" />
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
actionBtn = null
|
||||
if jamtrack.is_free
|
||||
actionBtn = `<a className="jamtrack-add-cart button-orange is_free" href="#" data-jamtrack-id={jamtrack.id}> GET IT FREE!</a>`
|
||||
else if jamtrack.purchased
|
||||
actionBtn = `<a className="jamtrack-add-cart-disabled button-grey button-disabled" href="javascript:void(0)">PURCHASED</a>`
|
||||
else if jamtrack.added_cart
|
||||
actionBtn = `<a className="jamtrack-add-cart-disabled button-grey button-disabled" href="client#/shoppingCart">ALREADY IN CART</a>`
|
||||
else
|
||||
actionBtn = `<a className="jamtrack-add-cart button-orange" href="#" data-jamtrack-id={jamtrack.id}>ADD TO CART</a>`
|
||||
|
||||
availabilityNotice = null
|
||||
if jamtrack.sales_region==context.JK.AVAILABILITY_US
|
||||
availabilityNotice =
|
||||
`<div className="jamtrack-license">
|
||||
This JamTrack available only to US customers.
|
||||
<a className="license-us-why" href="#">why?</a>
|
||||
</div>`
|
||||
|
||||
jamtracks.push `<tr className="jamtrack-record" key={jamtrack.id} data-jamtrack-id={jamtrack.id}>
|
||||
<td className="jamtrack-detail">
|
||||
<div className="jamtrack-name">"{jamtrack.name}"</div>
|
||||
<div className="jamtrack-original-artist">by {jamtrack.original_artist}</div>
|
||||
<br className="clearall"/>
|
||||
<div className="clearall detail-label extra hidden song-writer">Songwriters:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.songwriter}</div>
|
||||
<div className="clearall detail-label extra hidden">Publishers:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.publisher}</div>
|
||||
<div className="clearall detail-label extra hidden">Genres:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.genres.join(', ')}</div>
|
||||
<div className="clearall detail-label extra hidden">Version:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.recording_type}</div>
|
||||
</td>
|
||||
<td className="jamtrack-tracks">
|
||||
<div className="detail-arrow">
|
||||
<div className="jamtrack-detail-btn">
|
||||
show all tracks <a className="details-arrow arrow-down"/>
|
||||
</div>
|
||||
</div>
|
||||
{tracks}
|
||||
</td>
|
||||
<td className="jamtrack-action">
|
||||
<div className="jamtrack-action-container">
|
||||
<div className="jamtrack-actions">
|
||||
<div className={jamtrackPricesClasses}>$ {jamtrack.price}</div>
|
||||
{actionBtn}
|
||||
{availabilityNotice}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>`
|
||||
|
||||
if @state.searching
|
||||
jamtracksHeader = "searching..."
|
||||
else
|
||||
jamtracksHeader = "search results: #{@state.count} jamtracks"
|
||||
|
||||
jamTracksSection =
|
||||
`<div>
|
||||
<h2 className="jamtrack-results-header">{jamtracksHeader} <a className="back-to-jamtracks-home" href="/client#/jamtrack">back to jamtracks home</a></h2>
|
||||
<table className="generaltable jamtrack-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="jamtrack-detail">JAMTRACK</th>
|
||||
<th className="jamtrack-tracks">TRACKS INCLUDED / PREVIEW</th>
|
||||
<th className="jamtrack-shop">SHOP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="jamtrack-content">
|
||||
{jamtracks}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="end-of-jamtrack-list end-of-list">No more JamTracks</div>
|
||||
</div>`
|
||||
|
||||
options = {}
|
||||
|
||||
`<div className="JamTrackFilterScreen">
|
||||
<div className="content-body-scroller">
|
||||
{jamTracksSection}
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
getInitialState: () ->
|
||||
{search: '', type: 'user-input', jamtracks:[], show_all_artists: false, currentPage: 0, next: null, searching: false, count: 0}
|
||||
|
||||
|
||||
clearResults:() ->
|
||||
#@content.empty()
|
||||
#@noMoreJamtracks.hide()
|
||||
@setState({currentPage: 0, next: null, jamtracks:[], type: 'user-input', searching:false})
|
||||
|
||||
|
||||
defaultQuery:(extra) ->
|
||||
query =
|
||||
per_page: @LIMIT
|
||||
page: @state.currentPage + 1
|
||||
if @state.next
|
||||
query.since = @state.next
|
||||
|
||||
instrument = @instrument.val()
|
||||
if instrument?
|
||||
query.instrument = instrument
|
||||
|
||||
genre = @genre.val()
|
||||
if genre?
|
||||
query.genre = genre
|
||||
|
||||
$.extend(query, extra)
|
||||
|
||||
userSearch: (e) ->
|
||||
e.preventDefault()
|
||||
@search()
|
||||
|
||||
setFilterState: (state) ->
|
||||
if state
|
||||
@genre.easyDropDown('enable').removeAttr('disabled')
|
||||
@instrument.easyDropDown('enable').removeAttr('disabled')
|
||||
else
|
||||
@genre.easyDropDown('disable').attr('disabled', 'disabled')
|
||||
@instrument.easyDropDown('disable').attr('disabled', 'disabled')
|
||||
|
||||
|
||||
search: (search_type, input) ->
|
||||
return if @state.searching
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
# disable scroll watching now that we've started a new search
|
||||
$root.find('.content-body-scroller').off('scroll')
|
||||
$root.find('.end-of-jamtrack-list').hide()
|
||||
|
||||
|
||||
# we have to make sure the query starts from page 1, and no 'next' from previous causes a 'since' to show up
|
||||
query = @defaultQuery({page: 1})
|
||||
delete query.since
|
||||
@rest.getJamTracks(query)
|
||||
.done((response) =>
|
||||
@setState({jamtracks: response.jamtracks, next: response.next, searching: false, first_search: false, currentPage: 1, count: response.count})
|
||||
)
|
||||
.fail(() =>
|
||||
@app.notifyServerError jqXHR, 'Search Unavailable'
|
||||
@setState({searching: false, first_search: false})
|
||||
)
|
||||
|
||||
|
||||
@setState({currentPage: 0, next: null, jamtracks:[], searching: true, count: 0})
|
||||
|
||||
componentDidMount: () ->
|
||||
$screen = $('#jamtrackFilter')
|
||||
@genre = $screen.find('#jamtrack_genre')
|
||||
@instrument = $screen.find('#jamtrack_instrument')
|
||||
|
||||
@genre.on 'change', this.userSearch
|
||||
@instrument.on 'change', this.userSearch
|
||||
|
||||
# increase dropdown size
|
||||
context.JK.dropdown(@genre, {cutOff:15})
|
||||
context.JK.dropdown(@instrument, {cutOff:15})
|
||||
|
||||
|
||||
componentDidUpdate: ( ) ->
|
||||
$root = $(this.getDOMNode())
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
|
||||
@setFilterState(!@state.searching)
|
||||
|
||||
for jamTrack in @state.jamtracks
|
||||
jamtrackElement = $root.find("tbody .jamtrack-record[data-jamtrack-id=\"#{jamTrack.id}\"]")
|
||||
jamtrackElement.data('jamTrack', jamTrack)
|
||||
jamtrackElement.data('expanded', true)
|
||||
|
||||
@handleExpanded(jamtrackElement)
|
||||
@registerEvents(jamtrackElement)
|
||||
|
||||
|
||||
if @state.next == null
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
# if we less results than asked for, end searching
|
||||
#$scroller.infinitescroll 'pause'
|
||||
$scroller.off('scroll')
|
||||
if @state.currentPage == 1 and @state.jamtracks.length == 0
|
||||
#@content.append '<td colspan="3" class="no-jamtracks-msg\'>No JamTracks found.</div>'
|
||||
$root.find('.end-of-jamtrack-list').text('No JamTracks found matching your search').show()
|
||||
@logger.debug("JamTrackSearch: empty search")
|
||||
else if @state.currentPage > 0
|
||||
@logger.debug("end of search")
|
||||
$noMoreJamtracks = $root.find('.end-of-jamtrack-list').text('No more JamTracks').show()
|
||||
# there are bugs with infinitescroll not removing the 'loading'.
|
||||
# it's most noticeable at the end of the list, so whack all such entries
|
||||
else
|
||||
@registerInfiniteScroll($scroller)
|
||||
|
||||
|
||||
|
||||
registerInfiniteScroll:($scroller) ->
|
||||
$scroller.off('scroll')
|
||||
$scroller.on('scroll', () =>
|
||||
|
||||
# be sure to not fire off many refreshes when user hits the bottom
|
||||
return if @refreshing
|
||||
|
||||
if $scroller.scrollTop() + $scroller.innerHeight() + 100 >= $scroller[0].scrollHeight
|
||||
$scroller.append('<div class="infinite-scroll-loader-2">... Loading more JamTracks ...</div>')
|
||||
@refreshing = true
|
||||
@logger.debug("refreshing more jamtracks for infinite scroll")
|
||||
@setState({searching:true})
|
||||
@rest.getJamTracks(@defaultQuery())
|
||||
.done((json) =>
|
||||
@setState({jamtracks: @state.jamtracks.concat(json.jamtracks), next: json.next, currentPage: @state.currentPage + 1, count: json.count})
|
||||
)
|
||||
.always(() =>
|
||||
$scroller.find('.infinite-scroll-loader-2').remove()
|
||||
@refreshing = false
|
||||
@setState({searching: false})
|
||||
)
|
||||
)
|
||||
|
||||
playJamtrack:(e) ->
|
||||
e.preventDefault()
|
||||
|
||||
addToCartJamtrack:(e) ->
|
||||
e.preventDefault()
|
||||
$target = $(e.target)
|
||||
params = id: $target.attr('data-jamtrack-id')
|
||||
isFree = $(e.target).is('.is_free')
|
||||
|
||||
@rest.addJamtrackToShoppingCart(params).done((response) =>
|
||||
if(isFree)
|
||||
if context.JK.currentUserId?
|
||||
context.JK.currentUserFreeJamTrack = true # make sure the user sees no more free notices
|
||||
context.location = '/client#/redeemComplete'
|
||||
else
|
||||
# now make a rest call to buy it
|
||||
context.location = '/client#/redeemSignup'
|
||||
|
||||
else
|
||||
context.location = '/client#/shoppingCart'
|
||||
|
||||
).fail(() => @app.ajaxError)
|
||||
|
||||
licenseUSWhy:(e) ->
|
||||
e.preventDefault()
|
||||
@app.layout.showDialog 'jamtrack-availability-dialog'
|
||||
|
||||
registerEvents:($parent) ->
|
||||
$parent.find('.play-button').on 'click', @playJamtrack
|
||||
$parent.find('.jamtrack-add-cart').on 'click', @addToCartJamtrack
|
||||
$parent.find('.license-us-why').on 'click', @licenseUSWhy
|
||||
$parent.find('.jamtrack-detail-btn').on 'click', @toggleExpanded
|
||||
|
||||
toggleExpanded:(e) ->
|
||||
e.preventDefault()
|
||||
jamtrackRecord = $(e.target).parents('.jamtrack-record')
|
||||
@handleExpanded(jamtrackRecord)
|
||||
|
||||
handleExpanded:(trackElement) ->
|
||||
jamTrack = trackElement.data('jamTrack')
|
||||
expanded = trackElement.data('expanded')
|
||||
expand = !expanded
|
||||
trackElement.data('expanded', expand)
|
||||
|
||||
detailArrow = trackElement.find('.jamtrack-detail-btn')
|
||||
|
||||
if expand
|
||||
trackElement.find('.extra').removeClass('hidden')
|
||||
detailArrow.html('hide tracks <a class="details-arrow arrow-up"></a>')
|
||||
for track in jamTrack.tracks
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find('.extra').addClass('hidden')
|
||||
detailArrow.html('show all tracks <a class="details-arrow arrow-down"></a>')
|
||||
count = 0
|
||||
for track in jamTrack.tracks
|
||||
if count < 6
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").addClass('hidden')
|
||||
count++
|
||||
|
||||
|
||||
afterShow: (data) ->
|
||||
@setFilterFromURL()
|
||||
|
||||
beforeShow: () ->
|
||||
|
||||
setFilterFromURL:() ->
|
||||
|
||||
performSearch = false
|
||||
if $.QueryString['genre']?
|
||||
performSearch = true
|
||||
@genre.easyDropDown('select', $.QueryString['genre'], true)
|
||||
if $.QueryString['instrument']?
|
||||
performSearch = true
|
||||
@instrument.easyDropDown('select', $.QueryString['instrument'], true)
|
||||
|
||||
unless performSearch
|
||||
search = context.JamTrackStore.checkRequestedFilter()
|
||||
if search?
|
||||
performSearch = true
|
||||
@genre.easyDropDown('select', search.genre, true)
|
||||
@instrument.easyDropDown('select', search.instrument, true)
|
||||
|
||||
if performSearch
|
||||
@search()
|
||||
if window.history.replaceState #ie9 proofing
|
||||
window.history.replaceState({}, "", "/client#/jamtrack/filter")
|
||||
|
||||
onAppInit: (@app) ->
|
||||
|
||||
window.JamTrackSearchInput = '' # need to be not null; otherwise react-select chokes
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
|
||||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
|
||||
@app.bindScreen('jamtrack/filter', screenBindings)
|
||||
})
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
context = window
|
||||
MIX_MODES = context.JK.MIX_MODES
|
||||
|
||||
|
||||
@JamTrackLandingScreen = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore,"onAppInit")]
|
||||
|
||||
getInitialState: () ->
|
||||
{user: null}
|
||||
|
||||
render: () ->
|
||||
|
||||
howTo = null
|
||||
if @state.user?.free_jamtrack
|
||||
howTo =
|
||||
`<div className="free-jamtrack">
|
||||
<span>
|
||||
For a limited time, get one JamTrack free. Search JamTracks below, add one to your shopping cart, and we'll make it free during the checkout process.
|
||||
</span>
|
||||
</div>`
|
||||
else
|
||||
howTo = `<div className="no-free-jamtrack">
|
||||
<span>
|
||||
To play with your JamTracks, open a JamTrack while in a session in the JamKazam app. Or <a href="/client#/account/jamtracks">visit the JamTracks section of your account.</a>
|
||||
</span>
|
||||
</div>`
|
||||
|
||||
|
||||
`<div className="content-body-scroller">
|
||||
<div className="list-columns">
|
||||
<div className="browse">
|
||||
<h2>my jamtracks</h2>
|
||||
<div className="howto">
|
||||
{howTo}
|
||||
</div>
|
||||
<h2 className="browse-jamtracks">search jamtracks</h2>
|
||||
<div className="search-area">
|
||||
<div className="search-help para"> To search by the name of the original artist, band, or song name, enter your search words below:</div>
|
||||
<div className="search-controls">
|
||||
<JamTrackAutoComplete onSearch={this.search} /><button onClick={this.searchByString} className="search-by-string-btn button-orange ">SEARCH</button>
|
||||
</div>
|
||||
<div className="filter-help para">To search by genre and instrument, make your selections below:</div>
|
||||
<div className="search-controls">
|
||||
<select className="genre-list easydropdown" name="genres">
|
||||
<option value="">Any Genre</option>
|
||||
</select>
|
||||
<select className="instrument-list easydropdown" name="insruments">
|
||||
<option value="">Any Instrument</option>
|
||||
</select>
|
||||
<button className="search-by-filter-btn button-orange" onClick={this.searchByFilter}>SEARCH</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="about">
|
||||
<h2>what are jamtracks?</h2>
|
||||
<div className="what">
|
||||
<div className="details">
|
||||
JamTracks are the best way to play along with your favorite music! Unlike traditional backing tracks, JamTracks are professionally mastered, complete multitrack recordings, with fully isolated tracks for each part of the master mix. Used with the free JamKazam app & Internet service, you can:
|
||||
</div>
|
||||
<ul>
|
||||
<li>Solo just the part you want to play in order to hear and learn it</li>
|
||||
<li>Mute just the part you want to play and play along with the rest</li>
|
||||
<li>Slow down playback to practice without changing the pitch</li>
|
||||
<li>Change the song key by raising or lowering pitch in half steps</li>
|
||||
<li>Make audio recordings and share them via Facebook or URL</li>
|
||||
<li>Make video recordings and share them via YouTube</li>
|
||||
<li>And even go online to play with others live & in sync</li>
|
||||
</ul>
|
||||
<a className="video-thumbnail" href="https://www.youtube.com/watch?v=askHvcCoNfw" rel="external">
|
||||
<img className="play" src="/assets/content/icon_youtube_play.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
componentDidMount: () ->
|
||||
$root = $(@getDOMNode())
|
||||
|
||||
search: (searchType, searchData) ->
|
||||
context.JamTrackActions.requestSearch(searchType, searchData)
|
||||
|
||||
searchByString: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
context.JamTrackActions.requestSearch('user-input', window.JamTrackSearchInput)
|
||||
|
||||
searchByFilter: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
genre = $root.find('select.genre-list').val()
|
||||
instrument = $root.find('select.instrument-list').val()
|
||||
context.JamTrackActions.requestFilter(genre, instrument)
|
||||
|
||||
afterShow: (data) ->
|
||||
|
||||
if context.JK.currentUserId
|
||||
@app.user().done(@onUser)
|
||||
else
|
||||
@onUser({free_jamtrack: gon.global.one_free_jamtrack_per_user})
|
||||
|
||||
beforeShow: () ->
|
||||
@setState({user: null})
|
||||
|
||||
onUser:(user) ->
|
||||
@setState({user: user})
|
||||
|
||||
# Get artist names and build links
|
||||
#@rest.getJamTrackArtists({group_artist: true, per_page:100})
|
||||
#.done(this.buildArtistLinks)
|
||||
#.fail(this.handleFailure)
|
||||
|
||||
# Bind links to action that will open the jam_tracks list view filtered to given artist_name:
|
||||
# artist_name
|
||||
#@bindArtistLinks()
|
||||
|
||||
|
||||
onAppInit: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@noFreeJamTrack = null
|
||||
@freeJamTrack = null
|
||||
@bandList = null
|
||||
@noBandsFound = null
|
||||
|
||||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
|
||||
@app.bindScreen('jamtrack', screenBindings)
|
||||
|
||||
@screen = $('#jamtrackLanding')
|
||||
@noFreeJamTrack = @screen.find('.no-free-jamtrack')
|
||||
@freeJamTrack = @screen.find('.free-jamtrack')
|
||||
@bandList = @screen.find('#band_list')
|
||||
@noBandsFound = @screen.find('#no_bands_found')
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
context.JK.GenreSelectorHelper.render2($root.find('select.genre-list'))
|
||||
|
||||
@instrumentSelector = new context.JK.InstrumentSelector(@app)
|
||||
@instrumentSelector.initialize(false, true)
|
||||
@instrumentSelector.renderDropdown($root.find('select.instrument-list'))
|
||||
})
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
context = window
|
||||
ReactCSSTransitionGroup = React.addons.CSSTransitionGroup
|
||||
|
||||
@JamTrackPreview = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore, "onAppInit")]
|
||||
EVENTS: context.JK.EVENTS
|
||||
logger: context.JK.logger
|
||||
propTypes: { options: React.PropTypes.object }
|
||||
|
||||
getDefaultProps: () ->
|
||||
{ options: {master_shows_duration: false, color: 'gray', add_line_break: false, preload_master: false}}
|
||||
|
||||
getInitialState: () ->
|
||||
{ loaded: false, loading: false, playing: false, no_audio: false }
|
||||
|
||||
render: () ->
|
||||
playButtonClasses = { "play-button": true, disabled: @state.no_audio}
|
||||
playButtonClasses[@props.options.color] = @props.options.color?
|
||||
playButtonClasses = classNames(playButtonClasses)
|
||||
|
||||
stopButtonClasses = { "stop-button": true, disabled: @state.no_audio }
|
||||
stopButtonClasses[@props.options.color] = @props.options.color?
|
||||
stopButtonClasses = classNames(stopButtonClasses)
|
||||
|
||||
partClasses = {part: true}
|
||||
partClasses['adds-line-break'] = true if @props.options.master_adds_line_break
|
||||
partClasses = classNames(partClasses)
|
||||
|
||||
if @state.playing
|
||||
activeButton = `<a className={stopButtonClasses} onClick={this.stop} />`
|
||||
else
|
||||
activeButton = `<a className={playButtonClasses} onClick={this.play} />`
|
||||
|
||||
loaders = []
|
||||
if @state.loading
|
||||
loaders.push `<div key="spinner" className="loading spinner-small"></div>`
|
||||
loaders.push `<div key="text" className="loading-text">preview loading</div>`
|
||||
|
||||
|
||||
`<div className="jam-track-preview" data-track-type={this.props.jamTrackTrack.track_type} data-id={this.props.jamTrackTrack.id}>
|
||||
<div className="actions">
|
||||
{activeButton}
|
||||
</div>
|
||||
<img className="instrument-icon" data-hoveraction="instrument" data-instrument-id={this.state.instrumentId} src={this.state.instrumentSrc} width="24" height="24" />
|
||||
<div className="instrument-name">{this.state.instrumentDescription}</div>
|
||||
<div className="part">{this.state.part}</div>
|
||||
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
|
||||
{loaders}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>`
|
||||
|
||||
|
||||
componentWillMount: () ->
|
||||
instrumentId = null
|
||||
instrumentDescription = '?'
|
||||
if @props.jamTrackTrack.track_type == 'Track'
|
||||
if @props.jamTrackTrack.instrument
|
||||
instrumentId = @props.jamTrackTrack.instrument.id
|
||||
instrumentDescription = @props.jamTrackTrack.instrument.description
|
||||
else
|
||||
instrumentId = 'other'
|
||||
instrumentDescription= 'Master Mix'
|
||||
|
||||
instrumentSrc = context.JK.getInstrumentIcon24(instrumentId)
|
||||
|
||||
part = ''
|
||||
|
||||
if @props.jamTrackTrack.track_type == 'Track'
|
||||
part = "(#{@props.jamTrackTrack.part})" if @props.jamTrackTrack.part? && @props.jamTrackTrack.part != instrumentDescription
|
||||
|
||||
else
|
||||
if @props.options.master_adds_line_break
|
||||
part = '"' + @props.jamTrack.name + '"' + ' by ' + @props.jamTrack.original_artist
|
||||
else
|
||||
if @props.options.master_shows_duration
|
||||
duration = 'entire song'
|
||||
if @props.jamTrack.duration
|
||||
duration = "#{context.JK.prettyPrintSeconds(@props.jamTrack.duration)}"
|
||||
part = duration
|
||||
else
|
||||
part = @props.jamTrack.name + ' by ' + @props.jamTrack.original_artist
|
||||
|
||||
part = "(#{part})" unless part?
|
||||
part = '' unless part?
|
||||
|
||||
urls = null
|
||||
no_audio = null
|
||||
|
||||
if @props.jamTrackTrack.preview_mp3_url?
|
||||
|
||||
urls = [@props.jamTrackTrack.preview_mp3_url]
|
||||
if @props.jamTrackTrack.preview_ogg_url?
|
||||
urls.push(@props.jamTrackTrack.preview_ogg_url)
|
||||
urls = urls
|
||||
|
||||
no_audio = false
|
||||
else
|
||||
no_audio = true
|
||||
|
||||
|
||||
@setState({
|
||||
instrumentId: instrumentId,
|
||||
instrumentDescription: instrumentDescription,
|
||||
instrumentSrc: instrumentSrc,
|
||||
part: part
|
||||
urls: urls,
|
||||
no_audio: no_audio})
|
||||
|
||||
componentDidMount: () ->
|
||||
$root = $(@getDOMNode());
|
||||
|
||||
if @props.options.preload_master && @props.jamTrackTrack.track_type == 'Master' && !@state.no_audio
|
||||
@sound = new Howl({
|
||||
src: @state.urls,
|
||||
autoplay: false,
|
||||
loop: false,
|
||||
volume: 1.0,
|
||||
preload: true,
|
||||
onload: @onHowlerLoad
|
||||
onend: @onHowlerEnd})
|
||||
|
||||
componentWillUnmount: () ->
|
||||
@sound.unload() if @sound?
|
||||
|
||||
removeNowPlaying: () ->
|
||||
context.JamTrackPreviewActions.stoppedPlaying(this)
|
||||
|
||||
onHowlerEnd: () ->
|
||||
@logger.debug("on end")
|
||||
@removeNowPlaying()
|
||||
@setState(playing: false)
|
||||
|
||||
onHowlerLoad: () ->
|
||||
@setState(loaded: true, loading: false)
|
||||
|
||||
play: (e) ->
|
||||
if e?
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
$root.triggerHandler(@EVENTS.PREVIEW_PLAYED)
|
||||
|
||||
$playButton = $root.find('.play-button')
|
||||
if @state.no_audio
|
||||
context.JK.prodBubble($playButton, 'There is no preview available for this track.', {}, {duration:2000})
|
||||
else
|
||||
unless @sound?
|
||||
|
||||
@sound = new Howl({
|
||||
src: @state.urls,
|
||||
autoplay: false,
|
||||
loop: false,
|
||||
volume: 1.0,
|
||||
preload: true,
|
||||
onload: @onHowlerLoad
|
||||
onend: @onHowlerEnd})
|
||||
|
||||
|
||||
@logger.debug("play issued for jam track preview")
|
||||
@sound.play()
|
||||
context.JamTrackPreviewActions.startedPlaying(this)
|
||||
@setState({playing: true, loading: !@state.loaded})
|
||||
|
||||
issueStop: () ->
|
||||
@logger.debug("pause issued for jam track preview")
|
||||
@sound.pause() if @sound? # stop does not actually stop in windows client
|
||||
@setState({playing: false})
|
||||
|
||||
stop: (e) ->
|
||||
if e?
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
|
||||
if @state.no_audio
|
||||
context.JK.helpBubble(@playButton, 'There is no preview available for this track.', {}, {duration:2000})
|
||||
else
|
||||
@issueStop()
|
||||
@removeNowPlaying()
|
||||
|
||||
return false
|
||||
|
||||
})
|
||||
|
|
@ -0,0 +1,529 @@
|
|||
context = window
|
||||
MIX_MODES = context.JK.MIX_MODES
|
||||
|
||||
|
||||
@JamTrackSearchScreen = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore,"onAppInit")]
|
||||
|
||||
LIMIT: 10
|
||||
instrument_logo_map: context.JK.getInstrumentIconMap24()
|
||||
input: null
|
||||
MAX_ARTIST_SHOW: 3
|
||||
|
||||
filterOption:() ->
|
||||
true
|
||||
|
||||
render: () ->
|
||||
|
||||
searchText = if @state.first_search then 'SEARCH' else 'SEARCH AGAIN'
|
||||
|
||||
uiJamTracks = []
|
||||
for jamtrack in @state.jamtracks
|
||||
trackRow = context._.clone(jamtrack)
|
||||
trackRow.track_cnt = jamtrack.tracks.length
|
||||
trackRow.tracks = []
|
||||
|
||||
# if an instrument is selected by the user, then re-order any jam tracks with a matching instrument to the top
|
||||
|
||||
###instrument = @instrument.val()
|
||||
if instrument?
|
||||
jamtrack.tracks.sort((a, b) =>
|
||||
aWeight = @computeWeight(a, instrument)
|
||||
bWeight = @computeWeight(b, instrument)
|
||||
return aWeight - bWeight
|
||||
)
|
||||
###
|
||||
for track in jamtrack.tracks
|
||||
trackRow.tracks.push(track)
|
||||
if track.track_type=='Master'
|
||||
track.instrument_desc = "Master"
|
||||
else
|
||||
inst = '../assets/content/icon_instrument_default24.png'
|
||||
if track.instrument?
|
||||
if track.instrument.id in @instrument_logo_map
|
||||
inst = @instrument_logo_map[track.instrument.id].asset
|
||||
track.instrument_desc = track.instrument.description
|
||||
track.instrument_url = inst
|
||||
|
||||
if track.part != ''
|
||||
track.instrument_desc += ' (' + track.part + ')'
|
||||
|
||||
trackRow.free_state = if @state.is_free then 'free' else 'non-free'
|
||||
|
||||
trackRow.is_free = @state.is_free == 'free'
|
||||
|
||||
uiJamTracks.push trackRow
|
||||
|
||||
artists = []
|
||||
artistsShown = 0
|
||||
for artist in @state.artists
|
||||
|
||||
if @state.show_all_artists || artistsShown < @MAX_ARTIST_SHOW
|
||||
artists.push `<div key={artist.original_artist}><a className="show-artist" onClick={this.artistNavSelected} data-artist={artist.original_artist}>{artist.original_artist}</a></div>`
|
||||
|
||||
artistsShown += 1
|
||||
|
||||
|
||||
artists.push `<div key="no-results" className="no-results">No matching artists</div>` if artists.length == 0
|
||||
|
||||
if !@state.show_all_artists && @state.artists.length > @MAX_ARTIST_SHOW
|
||||
artists.push `<div key="show-hide-artists"><a onClick={this.showAllArtists} className="show-hide-artists">show all <div className="details-arrow arrow-down" /></a></div>`
|
||||
else if @state.show_all_artists
|
||||
artists.push `<div key="show-hide-artists"><a onClick={this.hideExtraArtists} className="show-hide-artists">hide artists <div className="details-arrow arrow-up" /></a></div>`
|
||||
|
||||
jamtracks = []
|
||||
|
||||
|
||||
for jamtrack in uiJamTracks
|
||||
|
||||
jamtrackPricesClasses = { "jamtrack-price" : true }
|
||||
jamtrackPricesClasses[jamtrack.free_state] = true
|
||||
jamtrackPricesClasses = classNames(jamtrackPricesClasses)
|
||||
|
||||
tracks = []
|
||||
for track in jamtrack.tracks
|
||||
tracks.push `<div className="jamtrack-track hidden" key={track.id} data-jamtrack-track-id={track.id}>
|
||||
<div className="jamtrack-preview">
|
||||
<JamTrackPreview jamTrack={jamtrack} jamTrackTrack={track} options={{master_shows_duration: true, color:'gray'}} />
|
||||
<div className="clearall" />
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
actionBtn = null
|
||||
if jamtrack.is_free
|
||||
actionBtn = `<a className="jamtrack-add-cart button-orange is_free" href="#" data-jamtrack-id={jamtrack.id}> GET IT FREE!</a>`
|
||||
else if jamtrack.purchased
|
||||
actionBtn = `<a className="jamtrack-add-cart-disabled button-grey button-disabled" href="javascript:void(0)">PURCHASED</a>`
|
||||
else if jamtrack.added_cart
|
||||
actionBtn = `<a className="jamtrack-add-cart-disabled button-grey button-disabled" href="client#/shoppingCart">ALREADY IN CART</a>`
|
||||
else
|
||||
actionBtn = `<a className="jamtrack-add-cart button-orange" href="#" data-jamtrack-id={jamtrack.id}>ADD TO CART</a>`
|
||||
|
||||
availabilityNotice = null
|
||||
if jamtrack.sales_region==context.JK.AVAILABILITY_US
|
||||
availabilityNotice =
|
||||
`<div className="jamtrack-license">
|
||||
This JamTrack available only to US customers.
|
||||
<a className="license-us-why" href="#">why?</a>
|
||||
</div>`
|
||||
|
||||
jamtracks.push `<tr className="jamtrack-record" key={jamtrack.id} data-jamtrack-id={jamtrack.id}>
|
||||
<td className="jamtrack-detail">
|
||||
<div className="jamtrack-name">"{jamtrack.name}"</div>
|
||||
<div className="jamtrack-original-artist">by {jamtrack.original_artist}</div>
|
||||
<br className="clearall"/>
|
||||
<div className="clearall detail-label extra hidden song-writer">Songwriters:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.songwriter}</div>
|
||||
<div className="clearall detail-label extra hidden">Publishers:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.publisher}</div>
|
||||
<div className="clearall detail-label extra hidden">Genres:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.genres.join(', ')}</div>
|
||||
<div className="clearall detail-label extra hidden">Version:</div>
|
||||
<div className="detail-value extra hidden">{jamtrack.recording_type}</div>
|
||||
</td>
|
||||
<td className="jamtrack-tracks">
|
||||
<div className="detail-arrow">
|
||||
<div className="jamtrack-detail-btn">
|
||||
show all tracks <a className="details-arrow arrow-down"/>
|
||||
</div>
|
||||
</div>
|
||||
{tracks}
|
||||
</td>
|
||||
<td className="jamtrack-action">
|
||||
<div className="jamtrack-action-container">
|
||||
<div className="jamtrack-actions">
|
||||
<div className={jamtrackPricesClasses}>$ {jamtrack.price}</div>
|
||||
{actionBtn}
|
||||
{availabilityNotice}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>`
|
||||
|
||||
#jamtracks.push `<div className="no-results">No matching JamTracks</div>` if jamtracks.length == 0
|
||||
|
||||
searchClasses = classNames({
|
||||
"button-orange" : true,
|
||||
"search-btn" : true,
|
||||
"disabled" : @state.searching
|
||||
})
|
||||
|
||||
artistSection = null
|
||||
jamTracksSection = null
|
||||
|
||||
if @state.type == 'user-input'
|
||||
if @state.searching
|
||||
jamtracksHeader = "searching..."
|
||||
else
|
||||
jamtracksHeader = "search results: #{@state.count} jamtracks"
|
||||
|
||||
|
||||
|
||||
else if @state.type == 'artist-select'
|
||||
jamtracksHeader = "search results: jamtracks for artist \"#{@state.artist}\""
|
||||
else if @state.type == 'song-select'
|
||||
jamtracksHeader = "search results: jamtrack \"#{@state.song}\""
|
||||
else
|
||||
throw "unknown search type #{@state.type}"
|
||||
|
||||
if !@state.first_search
|
||||
|
||||
|
||||
# only show the artists links if the user typed the results
|
||||
if @state.type == 'user-input'
|
||||
artistSection =
|
||||
`<div>
|
||||
<h2>search results: artists</h2>
|
||||
<div className="artist-results">
|
||||
{artists}
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
jamTracksSection =
|
||||
`<div>
|
||||
<h2 className="jamtrack-results-header">{jamtracksHeader} <a className="back-to-jamtracks-home" href="/client#/jamtrack">back to jamtracks home</a></h2>
|
||||
|
||||
<table className="generaltable jamtrack-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="jamtrack-detail">JAMTRACK</th>
|
||||
<th className="jamtrack-tracks">TRACKS INCLUDED / PREVIEW</th>
|
||||
<th className="jamtrack-shop">SHOP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="jamtrack-content">
|
||||
{jamtracks}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="end-of-jamtrack-list end-of-list">No more JamTracks</div>
|
||||
</div>`
|
||||
|
||||
options = {}
|
||||
|
||||
|
||||
searchValue = if @state.search == 'SEPARATOR' then '' else window.JamTrackSearchInput
|
||||
|
||||
`<div className="JamTrackSearchScreen">
|
||||
<div className="controls">
|
||||
<JamTrackAutoComplete onSearch={this.search} />
|
||||
<button className={searchClasses} name="search" onClick={this.userSearch}>{searchText}</button>
|
||||
</div>
|
||||
<div className="content-body-scroller">
|
||||
{artistSection}
|
||||
{jamTracksSection}
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
|
||||
clearResults:() ->
|
||||
@setState({currentPage: 0, next: null, show_all_artists: false, artists:[], jamtracks:[], type: 'user-input', searching:false, artist: null, song:null, is_free: context.JK.currentUserFreeJamTrack, first_search: true})
|
||||
|
||||
|
||||
getInitialState: () ->
|
||||
{search: '', type: 'user-input', artists:[], jamtracks:[], show_all_artists: false, currentPage: 0, next: null, searching: false, first_search: true, count: 0, is_free: context.JK.currentUserFreeJamTrack}
|
||||
|
||||
onSelectChange: (val) ->
|
||||
#@logger.debug("CHANGE #{val}")
|
||||
|
||||
return false unless val?
|
||||
|
||||
search_type
|
||||
if val.indexOf('ARTIST=') == 0
|
||||
search_type = 'artist-select'
|
||||
artist = val['ARTIST='.length..-1]
|
||||
@search(search_type, artist)
|
||||
else if val.indexOf('SONG=') == 0
|
||||
search_type = 'song-select'
|
||||
song = val['SONG='.length..-1]
|
||||
@search(search_type, song)
|
||||
else
|
||||
@logger.debug("user selected separator")
|
||||
# this is to signal to the component that the separator was selected, and it has code in render to negate the selection
|
||||
setTimeout((() =>
|
||||
@setState({search:val})
|
||||
), 1)
|
||||
|
||||
return false
|
||||
|
||||
|
||||
onSelectBlur: (e) ->
|
||||
|
||||
#@logger.debug("blur time")
|
||||
|
||||
#@search()
|
||||
|
||||
showAllArtists: () ->
|
||||
@setState({show_all_artists: true})
|
||||
|
||||
hideExtraArtists: () ->
|
||||
@setState({show_all_artists: false})
|
||||
|
||||
|
||||
defaultQuery:(extra) ->
|
||||
query =
|
||||
per_page: @LIMIT
|
||||
page: @state.currentPage + 1
|
||||
sort_by: 'jamtrack'
|
||||
if @state.next
|
||||
query.since = @state.next
|
||||
$.extend(query, extra)
|
||||
|
||||
|
||||
|
||||
userSearch: (e) ->
|
||||
e.preventDefault()
|
||||
@search('user-input', window.JamTrackSearchInput)
|
||||
|
||||
search: (search_type, input) ->
|
||||
return if @state.searching
|
||||
return unless input?
|
||||
|
||||
window.JamTrackSearchInput = input
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
# disable scroll watching now that we've started a new search
|
||||
#@logger.debug("disabling infinite scroll")
|
||||
$root.find('.content-body-scroller').off('scroll')
|
||||
$root.find('.end-of-jamtrack-list').hide()
|
||||
|
||||
if input?
|
||||
@rest.getJamTrackArtists({artist_search: input, limit:100})
|
||||
.done((response) =>
|
||||
@setState({artists:response.artists})
|
||||
|
||||
# we have to make sure the query starts from page 1, and no 'next' from previous causes a 'since' to show up
|
||||
query = @defaultQuery({page: 1})
|
||||
delete query.since
|
||||
|
||||
@logger.debug("Search type", search_type)
|
||||
if search_type == 'artist-select'
|
||||
query.artist_search = input # works with ilike
|
||||
else if search_type == 'song-select'
|
||||
query.song_search = input # works with ilike
|
||||
else
|
||||
query.search = input # works with tsv
|
||||
@rest.getJamTracks(query)
|
||||
.done((response) =>
|
||||
@setState({jamtracks: response.jamtracks, next: response.next, searching: false, first_search: false, currentPage: 1, count: response.count})
|
||||
)
|
||||
.fail(() =>
|
||||
@app.notifyServerError jqXHR, 'Search Unavailable'
|
||||
@setState({searching: false, first_search: false})
|
||||
)
|
||||
)
|
||||
.fail(() =>
|
||||
@app.notifyServerError jqXHR, 'Search Unavailable'
|
||||
@setState({searching: false, first_search: false})
|
||||
)
|
||||
|
||||
@setState({currentPage: 0, next: null, artists: [], jamtracks:[], searching: true, artist: input, song: input, type: search_type, search:input, count:0})
|
||||
|
||||
getOptions: (input, callback) =>
|
||||
|
||||
#@logger.debug("getOptions input #{input}", this)
|
||||
|
||||
# sigh. ugly global
|
||||
window.JamTrackSearchInput = input
|
||||
|
||||
if !input? || input.length == 0
|
||||
callback(null, {options: [], complete: false})
|
||||
return
|
||||
|
||||
@rest.autocompleteJamTracks({match:input, limit:5})
|
||||
.done((autocomplete) =>
|
||||
|
||||
options = []
|
||||
for artist in autocomplete.artists
|
||||
options.push { value: "ARTIST=#{artist.original_artist}", label: "Artist: #{artist.original_artist}" }
|
||||
|
||||
if options.length > 0 && autocomplete.songs.length > 0
|
||||
options.push { value: 'SEPARATOR', label: "---------------"}
|
||||
|
||||
for jamtrack in autocomplete.songs
|
||||
options.push { value: "SONG=#{jamtrack.name}", label: "Song: #{jamtrack.name}" }
|
||||
|
||||
callback(null, {options: options, complete: false})
|
||||
)
|
||||
|
||||
artistNavSelected: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
@search('artist-select', $(e.target).attr('data-artist'))
|
||||
|
||||
componentDidMount: () ->
|
||||
#@logger.debug("componentDidMount")
|
||||
|
||||
componentDidUpdate: ( ) ->
|
||||
$root = $(this.getDOMNode())
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
|
||||
for jamTrack in @state.jamtracks
|
||||
jamtrackElement = $root.find("tbody .jamtrack-record[data-jamtrack-id=\"#{jamTrack.id}\"]")
|
||||
jamtrackElement.data('jamTrack', jamTrack)
|
||||
jamtrackElement.data('expanded', true)
|
||||
|
||||
@handleExpanded(jamtrackElement)
|
||||
@registerEvents(jamtrackElement)
|
||||
|
||||
|
||||
if @state.next == null
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
# if we less results than asked for, end searching
|
||||
#$scroller.infinitescroll 'pause'
|
||||
#@logger.debug("disabling infinite scroll")
|
||||
$scroller.off('scroll')
|
||||
if @state.currentPage == 1 and @state.jamtracks.length == 0
|
||||
#@content.append '<td colspan="3" class="no-jamtracks-msg\'>No JamTracks found.</div>'
|
||||
$root.find('.end-of-jamtrack-list').text('No JamTracks found matching your search').show()
|
||||
@logger.debug("JamTrackSearch: empty search")
|
||||
else if @state.currentPage > 0
|
||||
@logger.debug("end of search")
|
||||
$noMoreJamtracks = $root.find('.end-of-jamtrack-list').text('No more JamTracks').show()
|
||||
$noMoreJamtracks = $root.find('.end-of-jamtrack-list')
|
||||
$noMoreJamtracks.show()
|
||||
# there are bugs with infinitescroll not removing the 'loading'.
|
||||
# it's most noticeable at the end of the list, so whack all such entries
|
||||
else
|
||||
@registerInfiniteScroll($scroller)
|
||||
|
||||
|
||||
|
||||
registerInfiniteScroll:($scroller) ->
|
||||
@logger.debug("registering infinite scroll")
|
||||
$scroller.off('scroll')
|
||||
$scroller.on('scroll', () =>
|
||||
|
||||
# be sure to not fire off many refreshes when user hits the bottom
|
||||
return if @refreshing
|
||||
|
||||
if $scroller.scrollTop() + $scroller.innerHeight() + 100 >= $scroller[0].scrollHeight
|
||||
$scroller.append('<div class="infinite-scroll-loader-2">... Loading more JamTracks ...</div>')
|
||||
@refreshing = true
|
||||
@setState({searching: true})
|
||||
@logger.debug("refreshing more jamtracks for infinite scroll")
|
||||
@rest.getJamTracks(@defaultQuery({search:@state.search}))
|
||||
.done((json) =>
|
||||
@setState({jamtracks: @state.jamtracks.concat(json.jamtracks), next: json.next, first_search: false, currentPage: @state.currentPage + 1, count: json.count})
|
||||
)
|
||||
.always(() =>
|
||||
$scroller.find('.infinite-scroll-loader-2').remove()
|
||||
@refreshing = false
|
||||
@setState({searching: false})
|
||||
)
|
||||
)
|
||||
|
||||
playJamtrack:(e) ->
|
||||
e.preventDefault()
|
||||
|
||||
addToCartJamtrack:(e) ->
|
||||
e.preventDefault()
|
||||
$target = $(e.target)
|
||||
params = id: $target.attr('data-jamtrack-id')
|
||||
isFree = $(e.target).is('.is_free')
|
||||
|
||||
@rest.addJamtrackToShoppingCart(params).done((response) =>
|
||||
if(isFree)
|
||||
if context.JK.currentUserId?
|
||||
context.JK.currentUserFreeJamTrack = true # make sure the user sees no more free notices
|
||||
context.location = '/client#/redeemComplete'
|
||||
else
|
||||
# now make a rest call to buy it
|
||||
context.location = '/client#/redeemSignup'
|
||||
|
||||
else
|
||||
context.location = '/client#/shoppingCart'
|
||||
|
||||
).fail(() => @app.ajaxError)
|
||||
|
||||
licenseUSWhy:(e) ->
|
||||
e.preventDefault()
|
||||
@app.layout.showDialog 'jamtrack-availability-dialog'
|
||||
|
||||
registerEvents:($parent) ->
|
||||
$parent.find('.play-button').on 'click', @playJamtrack
|
||||
$parent.find('.jamtrack-add-cart').on 'click', @addToCartJamtrack
|
||||
$parent.find('.license-us-why').on 'click', @licenseUSWhy
|
||||
$parent.find('.jamtrack-detail-btn').on 'click', @toggleExpanded
|
||||
|
||||
toggleExpanded:(e) ->
|
||||
e.preventDefault()
|
||||
jamtrackRecord = $(e.target).parents('.jamtrack-record')
|
||||
@handleExpanded(jamtrackRecord)
|
||||
|
||||
handleExpanded:(trackElement) ->
|
||||
jamTrack = trackElement.data('jamTrack')
|
||||
expanded = trackElement.data('expanded')
|
||||
expand = !expanded
|
||||
trackElement.data('expanded', expand)
|
||||
|
||||
detailArrow = trackElement.find('.jamtrack-detail-btn')
|
||||
|
||||
if expand
|
||||
trackElement.find('.extra').removeClass('hidden')
|
||||
detailArrow.html('hide tracks <a class="details-arrow arrow-up"></a>')
|
||||
for track in jamTrack.tracks
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find('.extra').addClass('hidden')
|
||||
detailArrow.html('show all tracks <a class="details-arrow arrow-down"></a>')
|
||||
count = 0
|
||||
for track in jamTrack.tracks
|
||||
if count < 6
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find("[data-jamtrack-track-id='#{track.id}']").addClass('hidden')
|
||||
count++
|
||||
|
||||
|
||||
afterShow: (data) ->
|
||||
|
||||
@setFilterFromURL()
|
||||
|
||||
setFilterFromURL:() ->
|
||||
|
||||
performSearch = false
|
||||
if $.QueryString['artist']?
|
||||
performSearch = true
|
||||
@search('artist-select', $.QueryString['artist'])
|
||||
else if $.QueryString['song']?
|
||||
performSearch = true
|
||||
@search('song-select', $.QueryString['song'])
|
||||
else if $.QueryString['search']?
|
||||
performSearch = true
|
||||
@search('user-input', $.QueryString['search'])
|
||||
else
|
||||
# check if someone has requested a search for us as we transition to this screen
|
||||
search = context.JamTrackStore.checkRequestedSearch()
|
||||
if search?
|
||||
performSearch = true
|
||||
@search(search.searchType, search.searchData)
|
||||
|
||||
if performSearch
|
||||
if window.history.replaceState #ie9 proofing
|
||||
window.history.replaceState({}, "", "/client#/jamtrack/search")
|
||||
|
||||
|
||||
beforeShow: () ->
|
||||
if !@state.first_search
|
||||
@setState({is_free: context.JK.currentUserFreeJamTrack})
|
||||
@search(@state.type, window.JamTrackSearchInput)
|
||||
|
||||
|
||||
|
||||
onAppInit: (@app) ->
|
||||
|
||||
window.JamTrackSearchInput = '' # need to be not null; otherwise react-select chokes
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
|
||||
|
||||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
|
||||
@app.bindScreen('jamtrack/search', screenBindings)
|
||||
})
|
||||
|
|
@ -210,7 +210,6 @@ ChannelGroupIds = context.JK.ChannelGroupIds
|
|||
<img src="/assets/content/icon_close.png" width="18" height="20" />
|
||||
Close JamTrack
|
||||
</a>
|
||||
<div className="download-jamtrack-holder"></div>
|
||||
</div>`
|
||||
|
||||
contents = closeOptions
|
||||
|
|
@ -236,6 +235,9 @@ ChannelGroupIds = context.JK.ChannelGroupIds
|
|||
</a>`
|
||||
|
||||
|
||||
if this.state.downloadJamTrack?
|
||||
mediaTracks.push `<div key="download-jamtrack-holder" className="download-jamtrack-holder"></div>`
|
||||
|
||||
if this.state.mediaSummary.backingTrackOpen
|
||||
|
||||
for backingTrack in @state.backingTracks
|
||||
|
|
|
|||
|
|
@ -3,5 +3,7 @@ context = window
|
|||
@JamTrackActions = Reflux.createActions({
|
||||
open: {}
|
||||
close: {}
|
||||
requestSearch: {}
|
||||
requestFilter: {}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
context = window
|
||||
|
||||
@JamTrackPreviewActions = Reflux.createActions({
|
||||
startedPlaying: {}
|
||||
stoppedPlaying: {}
|
||||
screenChange: {}
|
||||
})
|
||||
|
||||
|
|
@ -606,7 +606,7 @@ MIX_MODES = context.JK.MIX_MODES;
|
|||
|
||||
# sanity check
|
||||
if mixer && mixer.group_id != ChannelGroupIds.PeerAudioInputMusicGroup
|
||||
logger.error("found remote mixer that was not of groupID: PeerAudioInputMusicGroup", mixer)
|
||||
logger.warn("master: found remote mixer that was not of groupID: PeerAudioInputMusicGroup", client_id, track.client_track_id, mixer)
|
||||
|
||||
vuMixer = mixer
|
||||
muteMixer = mixer
|
||||
|
|
@ -618,7 +618,7 @@ MIX_MODES = context.JK.MIX_MODES;
|
|||
oppositeMixer = oppositeMixers[ChannelGroupIds.UserMusicInputGroup][0]
|
||||
|
||||
if !oppositeMixer
|
||||
logger.error("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer )
|
||||
logger.warn("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer )
|
||||
|
||||
when MIX_MODES.PERSONAL
|
||||
mixers = @groupedMixersForClientId(client_id, [ ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL)
|
||||
|
|
@ -632,9 +632,9 @@ MIX_MODES = context.JK.MIX_MODES;
|
|||
# now grab the PeerAudioInputMusicGroup in master mode to satisfy the 'opposite' mixer
|
||||
oppositeMixer = @getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER)
|
||||
if !oppositeMixer
|
||||
logger.debug("unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput", client_id, track.client_track_id)
|
||||
logger.debug("personal: unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput", client_id, track.client_track_id)
|
||||
else if oppositeMixer.group_id != ChannelGroupIds.PeerAudioInputMusicGroup
|
||||
logger.error("found remote mixer that was not of groupID: PeerAudioInputMusicGroup", mixer)
|
||||
logger.error("personaol: found remote mixer that was not of groupID: PeerAudioInputMusicGroup", client_id, track.client_track_id, mixer)
|
||||
|
||||
#vuMixer = oppositeMixer; # for personal mode, use the PeerAudioInputMusicGroup's VUs
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ rest = context.JK.Rest()
|
|||
{processing: false}
|
||||
|
||||
render: () ->
|
||||
bandBrowseUrl = "/client?artist=#{this.props.jam_track.original_artist}#/jamtrackBrowse"
|
||||
bandBrowseUrl = "/client?artist=#{this.props.jam_track.original_artist}#/jamtrack/search"
|
||||
|
||||
`<div className="cta-holder">
|
||||
<div className="checkout">
|
||||
<a href="/client#/jamtrackBrowse" onClick={this.redeem} className="cta-free-jamtrack" alt="ClICK HERE TO PICK YOUR FIRST JAMTRACK FREE!">
|
||||
<a href="/client#/jamtrack/search" onClick={this.redeem} className="cta-free-jamtrack" alt="ClICK HERE TO PICK YOUR FIRST JAMTRACK FREE!">
|
||||
<img src="/assets/web/button_cta_jamtrack_free.png" />
|
||||
</a>
|
||||
<span className="value-indicator">$1.99 value</span>
|
||||
|
|
@ -54,7 +54,7 @@ rest = context.JK.Rest()
|
|||
</div>
|
||||
<br/>
|
||||
<div className="browse-all">
|
||||
<a href="/client#/jamtrackBrowse">or browse all {this.props.all_track_count} backing tracks!</a>
|
||||
<a href="/client#/jamtrack/search">or browse all {this.props.all_track_count} backing tracks!</a>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
logger = context.JK.logger
|
||||
rest = context.JK.Rest()
|
||||
EVENTS = context.JK.EVENTS
|
||||
|
||||
|
||||
JamTrackPreviewActions = @JamTrackPreviewActions
|
||||
|
||||
@JamTrackPreviewStore = Reflux.createStore(
|
||||
{
|
||||
listenables: JamTrackPreviewActions
|
||||
logger: context.JK.logger
|
||||
nowPlaying: []
|
||||
|
||||
init: ->
|
||||
# Register with the app store to get @app
|
||||
this.listenTo(context.AppStore, this.onAppInit)
|
||||
|
||||
onAppInit: (app) ->
|
||||
@app = app
|
||||
|
||||
onStartedPlaying: (preview) ->
|
||||
|
||||
for playingSound in @nowPlaying
|
||||
playingSound.issueStop()
|
||||
@nowPlaying = []
|
||||
@nowPlaying.push(preview)
|
||||
|
||||
onStoppedPlaying: (preview) ->
|
||||
@nowPlaying.splice(preview)
|
||||
if @nowPlaying.length > 0
|
||||
@logger.warn("multiple jamtrack previews playing")
|
||||
|
||||
onScreenChange: () ->
|
||||
for playingSound in @nowPlaying
|
||||
playingSound.issueStop()
|
||||
@nowPlaying = []
|
||||
}
|
||||
)
|
||||
|
|
@ -11,6 +11,8 @@ JamTrackActions = @JamTrackActions
|
|||
{
|
||||
listenables: JamTrackActions
|
||||
jamTrack: null
|
||||
requestedSearch: null
|
||||
requestedFilter: null
|
||||
|
||||
init: ->
|
||||
# Register with the app store to get @app
|
||||
|
|
@ -30,5 +32,26 @@ JamTrackActions = @JamTrackActions
|
|||
onClose: () ->
|
||||
@jamTrack = null
|
||||
this.trigger(@jamTrack)
|
||||
|
||||
onRequestSearch:(searchType, searchData) ->
|
||||
@requestedSearch = {searchType: searchType, searchData: searchData}
|
||||
window.location.href = '/client#/jamtrack/search'
|
||||
|
||||
# needed by the JamTrackSearchScreen
|
||||
checkRequestedSearch:() ->
|
||||
requested = @requestedSearch
|
||||
@requestedSearch = null
|
||||
requested
|
||||
|
||||
onRequestFilter:(genre, instrument) ->
|
||||
@requestedFilter = {genre: genre, instrument:instrument}
|
||||
window.location.href = '/client#/jamtrack/filter'
|
||||
|
||||
# needed by the JamTrackSearchScreen
|
||||
checkRequestedFilter:() ->
|
||||
requested = @requestedFilter
|
||||
@requestedFilter = null
|
||||
requested
|
||||
|
||||
}
|
||||
)
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
if(!checkoutUtils.hasOneFreeItemInShoppingCart(carts)) {
|
||||
// the user has multiple items in their shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemComplete page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
window.location = '/client#/jamtrack/search'
|
||||
}
|
||||
else {
|
||||
// ok, we have one, free item. save it for
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
$backBtn.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
context.location = '/client#/jamtrackBrowse'
|
||||
context.location = '/client#/jamtrack/search'
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@
|
|||
var $signinLink = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
renderLoggedInState();
|
||||
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
renderLoggedInState();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -67,13 +67,13 @@
|
|||
|
||||
if(carts.length == 0) {
|
||||
// nothing is in the user's shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
logger.error("invalid access of redeemJamTrack page; none")
|
||||
window.location = '/client#/jamtrack/search'
|
||||
}
|
||||
else if(carts.length > 1) {
|
||||
// the user has multiple items in their shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
logger.error("invalid access of redeemJamTrack page; multiple")
|
||||
window.location = '/client#/jamtrack/search'
|
||||
}
|
||||
else {
|
||||
var item = carts[0];
|
||||
|
|
@ -86,8 +86,8 @@
|
|||
}
|
||||
else {
|
||||
// the user has a non-free, single item in their basket. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
logger.error("invalid access of redeemJamTrack page, non-free/item")
|
||||
window.location = '/client#/jamtrack/search'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@
|
|||
var instrumentLogoHtml = '';
|
||||
if (instruments !== undefined) {
|
||||
for (var i=0; i < instruments.length; i++) {
|
||||
var inst = '../assets/content/icon_instrument_default24.png';
|
||||
var inst = '/assets/content/icon_instrument_default24.png';
|
||||
if (instruments[i].instrument_id in instrument_logo_map) {
|
||||
inst = instrument_logo_map[instruments[i].instrument_id].asset;
|
||||
instrumentLogoHtml += '<img src="' + inst + '" width="24" height="24" /> ';
|
||||
|
|
|
|||
|
|
@ -1081,8 +1081,11 @@
|
|||
});
|
||||
}
|
||||
|
||||
context.JK.dropdown = function ($select) {
|
||||
context.JK.dropdown = function ($select, options) {
|
||||
|
||||
var opts = options || {}
|
||||
|
||||
opts = $.extend({}, {nativeTouch: !(context.jamClient && context.jamClient.IsNativeClient()) && gon.global.env != "test", cutOff: 7}, opts)
|
||||
$select.each(function (index) {
|
||||
var $item = $(this);
|
||||
|
||||
|
|
@ -1090,7 +1093,7 @@
|
|||
// if this has already been initialized, re-init it so it picks up any new <options>
|
||||
$item.easyDropDown('destroy')
|
||||
}
|
||||
$item.easyDropDown({nativeTouch: !(context.jamClient && context.jamClient.IsNativeClient()) && gon.global.env != "test", cutOff: 7});
|
||||
$item.easyDropDown(opts);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@
|
|||
logger.debug("jam_track", jam_track)
|
||||
|
||||
$jamtrack_band.text(jam_track.original_artist)
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack/search')
|
||||
$jamTracksButton.removeClass('hidden').text("Preview all " + jam_track.band_jam_track_count + " of our " + jam_track.original_artist + " JamTracks")
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack/searche')
|
||||
|
||||
|
||||
context._.each(jam_track.tracks, function (track) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
if(!gon.just_previews) {
|
||||
if (gon.generic) {
|
||||
$genericHeader.removeClass('hidden');
|
||||
$jamTracksButton.attr('href', '/client#/jamtrackBrowse')
|
||||
$jamTracksButton.attr('href', '/client#/jamtrack/search')
|
||||
$jamTracksButton.removeClass('hidden').text("Check out all 100+ JamTracks")
|
||||
|
||||
}
|
||||
|
|
@ -32,9 +32,9 @@
|
|||
$individualizedHeader.removeClass('hidden')
|
||||
$jamtrack_name.text('"' + jam_track.name + '"');
|
||||
$jamtrack_band.text(jam_track.original_artist)
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack/search')
|
||||
$jamTracksButton.removeClass('hidden').text("Preview all " + jam_track.band_jam_track_count + " of our " + jam_track.original_artist + " JamTracks")
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack/search')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
*= require ./feed
|
||||
*= require ./jamtrack
|
||||
*= require ./jamtrack_landing
|
||||
*= require ./jamtrackSearch
|
||||
*= require ./shoppingCart
|
||||
*= require ./checkout
|
||||
*= require ./checkout_signin
|
||||
|
|
@ -85,4 +86,5 @@
|
|||
*= require users/signinCommon
|
||||
*= require landings/partner_agreement_v1
|
||||
*= require_directory ./react-components
|
||||
|
||||
*/
|
||||
|
|
@ -521,6 +521,15 @@ textarea {
|
|||
text-align: center;
|
||||
margin:auto;
|
||||
width:100%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.infinite-scroll-loader-2 {
|
||||
height:14px;
|
||||
text-align: center;
|
||||
margin:auto;
|
||||
@include border_box_sizing;
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
// disable text selection for the in-session panel, ftue, and arbitrary elements marked with .no-selection-range
|
||||
|
|
@ -640,4 +649,53 @@ body.jam .icheckbox_minimal {
|
|||
margin:-46.75% auto 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$ReactSelectVerticalPadding: 3px;
|
||||
|
||||
.Select-value {
|
||||
padding-top: $ReactSelectVerticalPadding !important;
|
||||
padding-bottom: $ReactSelectVerticalPadding !important;
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
top: $ReactSelectVerticalPadding + 5 + 1 !important;
|
||||
}
|
||||
// overrides for react-select
|
||||
.Select-control {
|
||||
background-color: $ColorTextBoxBackground !important;
|
||||
border: 0px solid #868686 !important;
|
||||
border-color: lighten(#868686, 5%) #868686 darken(#868686, 10%) !important;
|
||||
color: #ccc !important;
|
||||
border-radius:0 !important;
|
||||
padding-top: $ReactSelectVerticalPadding !important;
|
||||
padding-bottom: $ReactSelectVerticalPadding !important;
|
||||
font-size:15px !important;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
|
||||
.Select-placeholder {
|
||||
padding-top: $ReactSelectVerticalPadding + 2 !important;
|
||||
padding-bottom: $ReactSelectVerticalPadding + 2 !important;
|
||||
}
|
||||
|
||||
.Select-menu-outer {
|
||||
// Unfortunately, having both border-radius and allows scrolling using overflow defined on the same
|
||||
// element forces the browser to repaint on scroll. However, if these definitions are split into an
|
||||
// outer and an inner element, the browser is able to optimize the scrolling behavior and does not
|
||||
// have to repaint on scroll.
|
||||
|
||||
border-radius: 0 !important;
|
||||
//.border-bottom-radius( @select-input-border-radius );
|
||||
background-color: $ColorTextBoxBackground !important;
|
||||
border: 1px solid #868686 !important;
|
||||
border-top-color: mix($ColorTextBoxBackground, #868686, 50%);
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
|
||||
box-sizing: border-box;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,299 @@
|
|||
@import 'common';
|
||||
|
||||
#jamtrackFilter {
|
||||
.jamtrack-filter.filter-head {
|
||||
|
||||
padding-left:6px;
|
||||
|
||||
.easydropdown.dropdown {
|
||||
width:150px;
|
||||
}
|
||||
|
||||
.filter-element.wrapper:nth-child(2) {
|
||||
.easydropdown-wrapper {
|
||||
margin-left:20px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-element.wrapper:nth-child(3) {
|
||||
margin-left:10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
#jamtrackSearch, #jamtrackFilter {
|
||||
|
||||
div[data-react-class="JamTrackSearchScreen"], .JamTrackSearchScreen, div[data-react-class="JamTrackFilterScreen"], .JamTrackFilterScreen {
|
||||
height:100%;
|
||||
}
|
||||
|
||||
|
||||
.filter-element.desc {
|
||||
margin-left:15px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.jamtrack-header {
|
||||
background-color: #4c4c4c;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
height: 2em;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
a.jamtrack_help {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
margin: 4px 0px 0px 60px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
table.jamtrack-table {
|
||||
table-layout:fixed;
|
||||
}
|
||||
.jamtrack-content {
|
||||
text-align: center;
|
||||
border: 1px solid #222222;
|
||||
padding: 2px
|
||||
}
|
||||
|
||||
.no-jamtracks-msg {
|
||||
margin: 10px 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.jamtrack-record {
|
||||
//border-bottom: 1px solid black;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th.jamtrack-detail {
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
th.jamtrack-tracks {
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
th.jamtrack-action {
|
||||
padding:6px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
td.jamtrack-action {
|
||||
padding:0;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.jamtrack-detail {
|
||||
@include border_box_sizing;
|
||||
width: 25%;
|
||||
padding: 10px 0 0 10px;
|
||||
.detail-label {
|
||||
width: 80px;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-bottom:15px;
|
||||
font-size:11px;
|
||||
}
|
||||
|
||||
.copyright-value {
|
||||
width: 40%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.jamtrack-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.jamtrack-detail-btn {
|
||||
cursor: pointer;
|
||||
margin-top: 29px;
|
||||
margin-right: 5px;
|
||||
padding-top: 5px;
|
||||
vertical-align: bottom;
|
||||
color:#fc0;
|
||||
|
||||
.arrow-down {
|
||||
float:none;
|
||||
margin-left:5px;
|
||||
margin-top:0;
|
||||
margin-right:0;
|
||||
border-top: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
display:inline-block;
|
||||
}
|
||||
.arrow-up {
|
||||
float:none;
|
||||
margin-right:0;
|
||||
margin-left:5px;
|
||||
margin-bottom:2px;
|
||||
border-bottom: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
display:inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-tracks {
|
||||
padding-bottom:30px;
|
||||
position:relative;
|
||||
@include border_box_sizing;
|
||||
width:55%;
|
||||
//padding: 10px 0px;
|
||||
|
||||
.tracks-caption {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.track-instrument {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.instrument-image {
|
||||
float: left;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.instrument-desc {
|
||||
margin-top: 6px;
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.instrument-name {
|
||||
color:white;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.detail-arrow {
|
||||
position:absolute;
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
bottom:14px;
|
||||
left:12px;
|
||||
}
|
||||
|
||||
.jamtrack-name {
|
||||
font-size:16px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.jamtrack-original-artist {
|
||||
font-size:16px;
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
|
||||
.jamtrack-track {
|
||||
float:left;
|
||||
padding:0 0 8px 7px;
|
||||
width: 250px;
|
||||
@include border_box_sizing;
|
||||
|
||||
&.hidden {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
.jam-track-preview {
|
||||
font-size:11px;
|
||||
white-space:nowrap;
|
||||
|
||||
.loading-text {
|
||||
right:-115px;
|
||||
background-color:#262626;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-action {
|
||||
@include border_box_sizing;
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
|
||||
.jamtrack-action-container {
|
||||
display:inline-block;
|
||||
|
||||
}
|
||||
.play-button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.jamtrack-price {
|
||||
margin-top: 5px;
|
||||
font-size: 20px;
|
||||
|
||||
&.free {
|
||||
margin-top:0;
|
||||
display:none;
|
||||
.free-state {
|
||||
font-size: 11px;
|
||||
margin-top: 5px;
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-add-cart, .jamtrack-add-cart-disabled {
|
||||
margin: 8px 0px;
|
||||
}
|
||||
|
||||
.jamtrack-license {
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
font-size: 13px;
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
.end-of-jamtrack-list {
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
|
||||
#jamtrack-license-dialog {
|
||||
.dialog-inner {
|
||||
height: auto;
|
||||
.content-body {
|
||||
max-height: auto;
|
||||
.content-body-scroller {
|
||||
height: 350px;
|
||||
.paragraph {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
border: 1px solid #222;
|
||||
margin: 4px 4px 8px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack_buttons {
|
||||
margin: 8px 4px 12px 4px;
|
||||
}
|
||||
|
|
@ -1,6 +1,53 @@
|
|||
@import 'common';
|
||||
|
||||
#jamtrackLanding {
|
||||
|
||||
div[data-react-class="JamTrackLandingScreen"], .content-body-scroller {
|
||||
height:100%;
|
||||
}
|
||||
.search-by-string-btn {
|
||||
float: right;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.search-by-filter-btn {
|
||||
float:right;
|
||||
margin-top:10px;
|
||||
}
|
||||
.search-help {
|
||||
margin:10px 0 10px 0;
|
||||
line-height:150%;
|
||||
}
|
||||
|
||||
.filter-help {
|
||||
margin:20px 0 10px 0;
|
||||
line-height:150%;
|
||||
}
|
||||
|
||||
.autocompleter {
|
||||
width: calc(100% - 90px);
|
||||
margin-bottom: 20px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
.easydropdown-wrapper{
|
||||
max-width:350px;
|
||||
@include border_box_sizing;
|
||||
&:nth-child(1) {
|
||||
margin-right:10px;
|
||||
width:calc(50% - 10px);
|
||||
|
||||
}
|
||||
&:nth-child(2) {
|
||||
margin-left:10px;
|
||||
width:calc(50% - 10px);
|
||||
}
|
||||
}
|
||||
button {
|
||||
margin-right:0;
|
||||
}
|
||||
}
|
||||
|
||||
//font-family: verdana;
|
||||
.two-column-list-container {
|
||||
-moz-column-count: 2;
|
||||
|
|
@ -20,14 +67,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
li {
|
||||
margin: 1px 4px 1px 4px;
|
||||
font-size:12px;
|
||||
line-height:14px ;
|
||||
}
|
||||
}
|
||||
|
||||
#band_list {
|
||||
margin-top:10px;
|
||||
margin-left:0;
|
||||
|
|
@ -83,7 +122,17 @@
|
|||
> * {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
li {
|
||||
margin: 1px 4px 1px 4px;
|
||||
font-size:12px;
|
||||
line-height:14px ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.browse {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
|
|
@ -93,6 +142,11 @@
|
|||
margin: 4px;
|
||||
}
|
||||
|
||||
.para {
|
||||
color: #cccccc;
|
||||
|
||||
}
|
||||
|
||||
h2.browse-jamtracks {
|
||||
margin-top:30px;
|
||||
}
|
||||
|
|
@ -102,15 +156,19 @@
|
|||
|
||||
}
|
||||
.video-container {
|
||||
width:80%;
|
||||
padding-top:56.25%;
|
||||
width:100%;
|
||||
padding-bottom:53.33%;
|
||||
margin:30px 0 30px 30px;
|
||||
}
|
||||
|
||||
.video-thumbnail {
|
||||
width:80%;
|
||||
padding-top:56.25%;
|
||||
margin:30px 0 30px 30px;
|
||||
width:100%;
|
||||
padding-top:53.33%;
|
||||
margin:25px 0;
|
||||
background:url(//img.youtube.com/vi/askHvcCoNfw/maxresdefault.jpg) no-repeat center;
|
||||
|
||||
img.play {
|
||||
margin:-35.75% auto 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
.JamTrackFilterScreen {
|
||||
|
||||
.content-body-scroller {
|
||||
height:calc(100% - 30px) ! important; // 15px top and bottom padding, and 48px used by .controls
|
||||
padding:15px 30px;
|
||||
}
|
||||
|
||||
.back-to-jamtracks-home {
|
||||
font-weight: normal;
|
||||
margin-right: 2px;
|
||||
margin-top: 6px;
|
||||
font-size:12px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
.JamTrackSearchScreen {
|
||||
|
||||
.content-body-scroller {
|
||||
height:calc(100% - 70px) !important; // 15px top and bottom padding, and 40px used by .controls
|
||||
padding:15px 30px;
|
||||
}
|
||||
|
||||
// react-select overridse
|
||||
.Select-menu-outer {
|
||||
max-height: 400px !important;
|
||||
}
|
||||
.Select-menu {
|
||||
max-height: 400px !important;
|
||||
}
|
||||
|
||||
.controls {
|
||||
background-color: #4c4c4c;
|
||||
min-height: 40px;
|
||||
|
||||
.autocompleter {
|
||||
display: inline-block;
|
||||
min-width: 250px;
|
||||
width: 33%;
|
||||
top: 8px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
margin-left: 15px;
|
||||
margin-top: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.back-to-jamtracks-home {
|
||||
font-weight: normal;
|
||||
margin-right: 2px;
|
||||
margin-top: 6px;
|
||||
font-size:12px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.jamtrack-results-header {
|
||||
margin-top:10px;
|
||||
}
|
||||
.artist-results {
|
||||
div {
|
||||
margin-bottom:5px;
|
||||
}
|
||||
a {
|
||||
|
||||
color:#fc0;
|
||||
}
|
||||
|
||||
a.show-hide-artists {
|
||||
margin-top:10px;
|
||||
font-size:11px;
|
||||
}
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.details-arrow.arrow-down{
|
||||
margin:0;
|
||||
color:#fc0;
|
||||
display:inline-block;
|
||||
float:none;
|
||||
border-top: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
}
|
||||
|
||||
.details-arrow.arrow-up{
|
||||
margin:0;
|
||||
color:#fc0;
|
||||
display:inline-block;
|
||||
float:none;
|
||||
border-bottom: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
# comes from the gem 'rails-assets-react-select'
|
||||
*= require react-select/dist/default.scss
|
||||
*/
|
||||
@import "client/common.css.scss";
|
||||
.Select-control {
|
||||
background-color:$ColorTextBoxBackground;
|
||||
}
|
||||
|
|
@ -1,6 +1,23 @@
|
|||
@import "client/common";
|
||||
|
||||
#open-jam-track-dialog {
|
||||
height:auto;
|
||||
min-height:400px;
|
||||
|
||||
div[data-react-class="JamTrackAutoComplete"] {
|
||||
width: calc(98% - 90px);
|
||||
margin-bottom: 20px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
margin-left: 15px;
|
||||
margin-top: 2px;
|
||||
vertical-align: top;
|
||||
float: right;
|
||||
margin-right: 17px;
|
||||
}
|
||||
|
||||
table.open-jam-tracks {
|
||||
tbody {
|
||||
tr:hover {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
class ApiJamTracksController < ApiController
|
||||
|
||||
# have to be signed in currently to see this screen
|
||||
before_filter :api_signed_in_user, :except => [:index, :show, :show_with_artist_info, :artist_index]
|
||||
before_filter :api_any_user, :only => [:index, :show, :show_with_artist_info, :artist_index]
|
||||
before_filter :api_signed_in_user, :except => [:index, :show, :autocomplete, :show_with_artist_info, :artist_index]
|
||||
before_filter :api_any_user, :only => [:index, :show, :autocomplete, :show_with_artist_info, :artist_index]
|
||||
before_filter :lookup_jam_track_right, :only => [:download,:enqueue, :show_jam_track_right]
|
||||
|
||||
respond_to :json
|
||||
|
|
@ -21,11 +21,19 @@ class ApiJamTracksController < ApiController
|
|||
|
||||
def index
|
||||
data = JamTrack.index(params, any_user)
|
||||
@jam_tracks, @next = data[0], data[1]
|
||||
|
||||
@jam_tracks, @next, @count = data[0], data[1], data[2]
|
||||
|
||||
render "api_jam_tracks/index", :layout => nil
|
||||
end
|
||||
|
||||
def autocomplete
|
||||
autocomplete = JamTrack.autocomplete(params, any_user)
|
||||
|
||||
@artists = autocomplete[:artists]
|
||||
@songs = autocomplete[:songs]
|
||||
render "api_jam_tracks/autocomplete", :layout => nil
|
||||
end
|
||||
|
||||
def artist_index
|
||||
data = JamTrack.artist_index(params, any_user)
|
||||
@artists, @next = data[0], data[1]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ class ApiShoppingCartsController < ApiController
|
|||
|
||||
respond_to :json
|
||||
|
||||
def log
|
||||
@log || Logging.logger[VanillaForumsController ]
|
||||
end
|
||||
|
||||
def index
|
||||
@carts = any_user.shopping_carts
|
||||
end
|
||||
|
|
@ -22,7 +26,7 @@ class ApiShoppingCartsController < ApiController
|
|||
response.status = :unprocessable_entity
|
||||
respond_with @cart
|
||||
else
|
||||
respond_with @cart, responder: ApiResponder, :statue => 201
|
||||
respond_with @cart, responder: ApiResponder, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
child(@artists => :artists) {
|
||||
attributes :original_artist
|
||||
}
|
||||
|
||||
child(@songs => :songs) {
|
||||
attributes :id, :name, :original_artist
|
||||
}
|
||||
|
|
@ -2,6 +2,9 @@ node :next do |page|
|
|||
@next
|
||||
end
|
||||
|
||||
node :count do |page|
|
||||
@count
|
||||
end
|
||||
node :jamtracks do |page|
|
||||
partial "api_jam_tracks/show", object: @jam_tracks
|
||||
end
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
object @user
|
||||
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count,
|
||||
:recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :reuse_card, :purchased_jamtracks_count
|
||||
:recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :reuse_card
|
||||
|
||||
if @user.musician?
|
||||
node :location do @user.location end
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
tr.no-jamtracks-found.hidden
|
||||
td colspan="3"
|
||||
| You don't currently own any JamTracks.
|
||||
a.orange href="/client#/jamtrackBrowse" Browse JamTracks Now
|
||||
a.orange href="/client#/jamtrack/search" Browse JamTracks Now
|
||||
.right
|
||||
a.button-orange href="/client#/jamtrackBrowse" JAMTRACKS
|
||||
a.button-orange href="/client#/jamtrack/search" JAMTRACKS
|
||||
a.button-grey href="javascript:history.go(-1)" BACK
|
||||
|
||||
script#template-account-jamtrack type='text/template'
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ div layout="screen" layout-id="checkoutComplete" id="checkoutCompleteScreen" cla
|
|||
.checkout-complete-wrapper
|
||||
.no-purchases-prompt.hidden
|
||||
| You have not made any purchases recently. Why not go go
|
||||
a href="/client#/jamtrackBrowse" browse our collection of JamTracks
|
||||
a href="/client#/jamtrack/search" browse our collection of JamTracks
|
||||
| ?
|
||||
.thanks-panel
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ div layout="screen" layout-id="checkoutOrder" id="checkoutOrderScreen" class="sc
|
|||
| Please review your order, and if everything looks correct, click the PLACE YOUR ORDER button. Thank you!
|
||||
p.empty-cart-prompt.hidden
|
||||
| You have nothing in your cart. You can go browse for JamTracks
|
||||
a href="/client#/jamtrackBrowse" here
|
||||
a href="/client#/jamtrack/search" here
|
||||
| .
|
||||
p.no-account-info-prompt.hidden
|
||||
| You have no billing info. Please go back to the
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
.homebox-info
|
||||
/! 1 session invitation, 19 public sessions active
|
||||
-if jamtracks
|
||||
.homecard.jamtrack layout-grid-columns=small_tile_size layout-grid-position=column_positions[2] layout-grid-rows="1" layout-link="jamtrackLanding"
|
||||
.homecard.jamtrack layout-grid-columns=small_tile_size layout-grid-position=column_positions[2] layout-grid-rows="1" layout-link="jamtrack"
|
||||
h2 jamtracks
|
||||
.homebox-info
|
||||
/! 5 followers, 3 following
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
.homebox-info
|
||||
-if jamtracks
|
||||
/! 1 session invitation, 19 public sessions active
|
||||
.homecard.jamtrack layout-grid-columns=small_tile_size layout-grid-position=column_positions[2] layout-grid-rows="1" layout-link="jamtrackLanding"
|
||||
.homecard.jamtrack layout-grid-columns=small_tile_size layout-grid-position=column_positions[2] layout-grid-rows="1" layout-link="jamtrack"
|
||||
h2 jamtracks
|
||||
.homebox-info
|
||||
/! 5 followers, 3 following
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
#jamtrackFilter.screen.secondary.no-login-required layout='screen' layout-id='jamtrack/filter'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19)
|
||||
h1 search jamtracks
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
=form_tag('', {:id => 'jamtrack-filter-form', :class => 'inner-content'}) do
|
||||
=render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_JAMTRACK})
|
||||
.filter-body
|
||||
= react_component 'JamTrackFilterScreen', {}
|
||||
|
|
@ -1,37 +1,8 @@
|
|||
#jamtrackLanding.screen.secondary.no-login-required layout='screen' layout-id='jamtrackLanding'
|
||||
#jamtrackLanding.screen.secondary.no-login-required layout='screen' layout-id='jamtrack'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19)
|
||||
h1 jamtracks
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
.content-body-scroller
|
||||
.list-columns
|
||||
.about
|
||||
h2 what are jamtracks?
|
||||
.what
|
||||
.details JamTracks are the best way to play along with your favorite music! Unlike traditional backing tracks, JamTracks are professionally mastered, complete multitrack recordings, with fully isolated tracks for each and every part of the master mix. Used with the free JamKazam app & Internet service, you can:
|
||||
ul
|
||||
li Solo just the part you want to play in order to hear and learn it
|
||||
li Mute just the part you want to play and play along with the rest
|
||||
li Make audio recordings and share them via Facebook or URL
|
||||
li Make video recordings and share them via YouTube
|
||||
li And even go online to play with others in real time -- for example, you can play the electric guitar lead, while someone else plays the bass, and all other parts play from the recorded tracks in your session
|
||||
a.video-thumbnail href="https://www.youtube.com/watch?v=askHvcCoNfw" rel="external"
|
||||
img.play src="/assets/content/icon_youtube_play.png"
|
||||
.browse
|
||||
h2 my jamtracks
|
||||
.howto
|
||||
.no-free-jamtrack.details.hidden
|
||||
span="To play with your JamTracks, open a JamTrack while in a session in the JamKazam app. Or "
|
||||
a href="client#/account/jamtracks" visit the JamTracks Section of your account.
|
||||
.free-jamtrack.orange-fill.details.hidden
|
||||
| For a limited time, get one JamTrack free. Browse JamTracks below, add one to your shopping cart, and we'll make it free during the checkout process.
|
||||
h2.browse-jamtracks browse jamtracks
|
||||
.browse-header
|
||||
| browse by band
|
||||
a href="client#/jamtrackBrowse" or browse all jamtracks
|
||||
.band-browse.two-column-list-container
|
||||
ul#band_list
|
||||
li#no_bands_found.hidden No bands found
|
||||
|
||||
= react_component 'JamTrackLandingScreen', {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
#jamtrackSearch.screen.secondary.no-login-required layout='screen' layout-id='jamtrack/search'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19)
|
||||
h1 search jamtracks
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
= react_component 'JamTrackSearchScreen', {}
|
||||
|
|
@ -11,7 +11,7 @@ div layout="screen" layout-id="redeemComplete" id="redeemCompleteScreen" class="
|
|||
.checkout-complete-wrapper
|
||||
.no-purchases-prompt.hidden
|
||||
| You have not made any purchases recently. Why not go go
|
||||
a href="/client#/jamtrackBrowse" browse our collection of JamTracks
|
||||
a href="/client#/jamtrack/search" browse our collection of JamTracks
|
||||
| ?
|
||||
.thanks-panel
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ div layout="screen" layout-id="redeemSignup" id="redeemSignupScreen" class="scre
|
|||
p.carry-on-prompt
|
||||
| You can go back to browsing.
|
||||
.actions
|
||||
a.btnNext.button-orange href="/client#/jamtrackBrowse" BROWSE JAMTRACKS
|
||||
a.btnNext.button-orange href="/client#/jamtrack/search" BROWSE JAMTRACKS
|
||||
.not-signed-in.prompt
|
||||
| To get your free
|
||||
span.jamtrack-name
|
||||
|
|
|
|||
|
|
@ -519,4 +519,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</script>
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
#session-screen-old.screen.secondary[layout="screen" layout-id="session_old" layout-arg="id"]
|
||||
.content-head
|
||||
.content-icon
|
||||
= image_tag "shared/icon_session.png", {:height => 19, :width => 19}
|
||||
h1
|
||||
| session
|
||||
.content-body
|
||||
#session-controls
|
||||
a#session-resync.button-grey.resync.left
|
||||
= image_tag "content/icon_resync.png", {:align => "texttop", :height => 12, :width => 12}
|
||||
| RESYNC
|
||||
a#session-settings-button.button-grey.left[layout-link="session-settings"]
|
||||
= image_tag "content/icon_settings_sm.png", {:align => "texttop", :height => 12, :width => 12}
|
||||
| SETTINGS
|
||||
a.button-grey.left[layout-link="share-dialog"]
|
||||
= image_tag "content/icon_share.png", {:align => "texttop", :height => 12, :width => 12}
|
||||
| SHARE
|
||||
|
||||
- if (Rails.application.config.video_available && Rails.application.config.video_available!="none")
|
||||
a#session-webcam.button-grey-toggle.video.left
|
||||
= image_tag "content/icon_cam.png", {:align => "texttop", :height => 12, :width => 12}
|
||||
| VIDEO
|
||||
.block
|
||||
.label
|
||||
| VOLUME:
|
||||
#volume.fader.lohi[mixer-id=""]
|
||||
.block.monitor-mode-holder
|
||||
.label
|
||||
| MIX:
|
||||
select.monitor-mode.easydropdown
|
||||
option.label[value="personal"]
|
||||
| Personal
|
||||
option[value="master"]
|
||||
| Master
|
||||
a#session-leave.button-grey.right.leave[href="/client#/home"]
|
||||
| X LEAVE
|
||||
#tracks
|
||||
.content-scroller
|
||||
.content-wrapper
|
||||
.session-mytracks
|
||||
h2
|
||||
| my tracks
|
||||
#track-settings.session-add[style="display:block;" layout-link="configure-tracks"]
|
||||
= image_tag "content/icon_settings_lg.png", {:width => 18, :height => 18}
|
||||
span
|
||||
| Settings
|
||||
.session-tracks-scroller
|
||||
#session-mytracks-notracks
|
||||
p.notice
|
||||
| You have not set up any inputs for your instrument or vocals.
|
||||
| If you want to hear yourself play through the JamKazam app,
|
||||
| and let the app mix your live playing with JamTracks, or with other musicians in online sessions,
|
||||
a.open-ftue-no-tracks href='#' click here now.
|
||||
#session-mytracks-container
|
||||
#voice-chat.voicechat[style="display:none;" mixer-id=""]
|
||||
.voicechat-label
|
||||
| CHAT
|
||||
.voicechat-gain
|
||||
.voicechat-mute.enabled[control="mute" mixer-id=""]
|
||||
.session-fluidtracks
|
||||
.session-livetracks
|
||||
h2
|
||||
| live tracks
|
||||
.session-add[layout-link="select-invites"]
|
||||
a#session-invite-musicians[href="#"]
|
||||
= image_tag "content/icon_add.png", {:width => 19, :height => 19, :align => "texttop"}
|
||||
| Invite Musicians
|
||||
.session-tracks-scroller
|
||||
#session-livetracks-container
|
||||
.when-empty.livetracks
|
||||
| No other musicians
|
||||
br
|
||||
| are in your session
|
||||
br[clear="all"]
|
||||
#recording-start-stop.recording
|
||||
a
|
||||
= image_tag "content/recordbutton-off.png", {:width => 20, :height => 20, :align => "absmiddle"}
|
||||
|
|
||||
span#recording-status
|
||||
| Make Recording
|
||||
.session-recordings
|
||||
h2
|
||||
| other audio
|
||||
.session-recording-name-wrapper
|
||||
.session-recording-name.left
|
||||
| (No audio loaded)
|
||||
.session-add.right
|
||||
a#close-playback-recording[href="#"]
|
||||
= image_tag "content/icon_close.png", {:width => 18, :height => 20, :align => "texttop"}
|
||||
| Close
|
||||
.session-tracks-scroller
|
||||
#session-recordedtracks-container
|
||||
.when-empty.recordings
|
||||
span.open-media-file-header
|
||||
= image_tag "content/icon_folder.png", {width:22, height:20}
|
||||
| Open:
|
||||
ul.open-media-file-options
|
||||
li
|
||||
a#open-a-recording[href="#"]
|
||||
| Recording
|
||||
- if Rails.application.config.jam_tracks_available || (current_user && current_user.admin)
|
||||
li.open-a-jamtrack
|
||||
a#open-a-jamtrack[href="#"]
|
||||
| JamTrack
|
||||
- if Rails.application.config.backing_tracks_available
|
||||
li
|
||||
a#open-a-backingtrack[href="#"]
|
||||
| Audio File
|
||||
.when-empty.use-metronome-header
|
||||
- if Rails.application.config.metronome_available
|
||||
= image_tag "content/icon_metronome.png", {width:22, height:20}
|
||||
a#open-a-metronome[href="#"]
|
||||
| Use Metronome
|
||||
br[clear="all"]
|
||||
.play-controls-holder
|
||||
= render "play_controls"
|
||||
.webcam-container.hidden
|
||||
/ Webcam is actually in another window.
|
||||
= render 'webcam'
|
||||
= render "configureTrack"
|
||||
= render "addTrack"
|
||||
= render "addNewGear"
|
||||
= render "error"
|
||||
= render "sessionSettings"
|
||||
script#template-session-track[type="text/template"]
|
||||
.session-track.track client-id="{clientId}" track-id="{trackId}"
|
||||
.track-vu-left.mixer-id="{vuMixerId}_vul"
|
||||
.track-vu-right.mixer-id="{vuMixerId}_vur"
|
||||
.track-label[title="{name}"]
|
||||
span.name-text="{name}"
|
||||
#div-track-close.track-close.op30 track-id="{trackId}"
|
||||
=image_tag("content/icon_closetrack.png", {width: 12, height: 12})
|
||||
div class="{avatarClass}"
|
||||
img src="{avatar}"
|
||||
.track-instrument class="{preMasteredClass}"
|
||||
img height="45" src="{instrumentIcon}" width="45"
|
||||
.track-gain mixer-id="{mixerId}"
|
||||
.track-icon-mute class="{muteClass}" control="mute" mixer-id="{muteMixerId}"
|
||||
.track-icon-loop.hidden control="loop"
|
||||
input#loop-button type="checkbox" value="loop" Loop
|
||||
.track-connection.grey mixer-id="{mixerId}_connection"
|
||||
CONNECTION
|
||||
.disabled-track-overlay
|
||||
.metronome-selects.hidden
|
||||
select.metronome-select.metro-sound title="Metronome Sound"
|
||||
option.label value="Beep" Knock
|
||||
option.label value="Click" Tap
|
||||
option.label value="Snare" Snare
|
||||
option.label value="Kick" Kick
|
||||
br
|
||||
select.metronome-select.metro-tempo title="Metronome Tempo"
|
||||
- metronome_tempos.each do |t|
|
||||
option.label value=t
|
||||
=t
|
||||
|
||||
script#template-option type="text/template"
|
||||
option value="{value}" title="{label}" selected="{selected}"
|
||||
="{label}"
|
||||
|
||||
script#template-genre-option type="text/template"
|
||||
option value="{value}"
|
||||
="{label}"
|
||||
|
||||
script#template-pending-metronome type="text/template"
|
||||
.pending-metronome
|
||||
.spinner-large
|
||||
p Your metronome is synchronizing.
|
||||
|
|
@ -6,3 +6,56 @@
|
|||
| session
|
||||
.content-body
|
||||
= react_component 'SessionScreen', {}
|
||||
|
||||
= render "configureTrack"
|
||||
= render "addTrack"
|
||||
= render "addNewGear"
|
||||
= render "error"
|
||||
= render "sessionSettings"
|
||||
script#template-session-track[type="text/template"]
|
||||
.session-track.track client-id="{clientId}" track-id="{trackId}"
|
||||
.track-vu-left.mixer-id="{vuMixerId}_vul"
|
||||
.track-vu-right.mixer-id="{vuMixerId}_vur"
|
||||
.track-label[title="{name}"]
|
||||
span.name-text="{name}"
|
||||
#div-track-close.track-close.op30 track-id="{trackId}"
|
||||
=image_tag("content/icon_closetrack.png", {width: 12, height: 12})
|
||||
div class="{avatarClass}"
|
||||
img src="{avatar}"
|
||||
.track-instrument class="{preMasteredClass}"
|
||||
img height="45" src="{instrumentIcon}" width="45"
|
||||
.track-gain mixer-id="{mixerId}"
|
||||
.track-icon-mute class="{muteClass}" control="mute" mixer-id="{muteMixerId}"
|
||||
.track-icon-loop.hidden control="loop"
|
||||
input#loop-button type="checkbox" value="loop" Loop
|
||||
.track-connection.grey mixer-id="{mixerId}_connection"
|
||||
CONNECTION
|
||||
.disabled-track-overlay
|
||||
.metronome-selects.hidden
|
||||
select.metronome-select.metro-sound title="Metronome Sound"
|
||||
option.label value="Beep" Knock
|
||||
option.label value="Click" Tap
|
||||
option.label value="Snare" Snare
|
||||
option.label value="Kick" Kick
|
||||
br
|
||||
select.metronome-select.metro-tempo title="Metronome Tempo"
|
||||
- metronome_tempos.each do |t|
|
||||
option.label value=t
|
||||
=t
|
||||
|
||||
script#template-option type="text/template"
|
||||
option value="{value}" title="{label}" selected="{selected}"
|
||||
="{label}"
|
||||
|
||||
script#template-genre-option type="text/template"
|
||||
option value="{value}"
|
||||
="{label}"
|
||||
|
||||
script#template-instrument-option-simple type="text/template"
|
||||
option value="{value}"
|
||||
="{label}"
|
||||
|
||||
script#template-pending-metronome type="text/template"
|
||||
.pending-metronome
|
||||
.spinner-large
|
||||
p Your metronome is synchronizing.
|
||||
|
|
|
|||
|
|
@ -56,6 +56,6 @@
|
|||
.clearall
|
||||
.right.actions
|
||||
%a.button-grey{href: "#"} HELP
|
||||
%a.button-orange{href: "/client#/jamtrackBrowse"} CONTINUE SHOPPING
|
||||
%a.button-orange{href: "/client#/jamtrack/search"} CONTINUE SHOPPING
|
||||
%a.button-orange.proceed-checkout{href: "#"} PROCEED TO CHECKOUT
|
||||
.clearall
|
||||
|
|
@ -22,8 +22,9 @@
|
|||
/ =select_tag("#{filter_label}_genre", |
|
||||
/ options_for_select([['Any', '']].concat(JamRuby::Genre.all.collect { |ii| [ii.description, ii.id] })), {:class => 'easydropdown'}) |
|
||||
-if :jamtrack==filter_label
|
||||
=content_tag(:div, 'Filter JamTracks:', :class => 'filter-element desc')
|
||||
=select_tag("#{filter_label}_artist", options_for_select([['Any Band', '']].concat(JamTrack.all_artists.collect { |ii| [ii, ii] })), {:class => 'easydropdown'})
|
||||
=content_tag(:div, 'Filter JamTracks By:', :class => 'filter-element desc')
|
||||
=select_tag("#{filter_label}_genre",
|
||||
options_for_select([['Any Genre', '']].concat(JamRuby::Genre.order(:description).collect { |ii| [ii.description, ii.id] })), {:class => 'easydropdown'})
|
||||
=content_tag(:div, :class => 'filter-element wrapper') do
|
||||
-if :musician==filter_label || :jamtrack==filter_label
|
||||
/ =content_tag(:div, 'Instrument:', :class => 'filter-element desc instrument-selector')
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
<%= render "sidebar" %>
|
||||
<%= render "scheduledSession" %>
|
||||
<%= render "findSession" %>
|
||||
<%= render "session" %>
|
||||
<%= render "session2" %>
|
||||
<%= render "profile" %>
|
||||
<%= render "bandProfile" %>
|
||||
|
|
@ -39,7 +38,8 @@
|
|||
<%= render "band_setup_photo" %>
|
||||
<%= render "users/feed_music_session_ajax" %>
|
||||
<%= render "users/feed_recording_ajax" %>
|
||||
<%= render "jamtrack_browse" %>
|
||||
<%= render "jamtrack_search" %>
|
||||
<%= render "jamtrack_filter" %>
|
||||
<%= render "jamtrack_landing" %>
|
||||
<%= render "shopping_cart" %>
|
||||
<%= render "checkout_signin" %>
|
||||
|
|
@ -167,6 +167,7 @@
|
|||
localRecordingsDialog.initialize();
|
||||
|
||||
var openJamTrackDialog = new JK.OpenJamTrackDialog(JK.app);
|
||||
JK.OpenJamTrackDialogInstance = openJamTrackDialog;
|
||||
openJamTrackDialog.initialize();
|
||||
|
||||
var openBackingTrackDialog = new JK.OpenBackingTrackDialog(JK.app);
|
||||
|
|
@ -284,11 +285,11 @@
|
|||
// }
|
||||
// findSessionScreen.initialize(sessionLatency);
|
||||
|
||||
var jamtrackScreen = new JK.JamTrackScreen(JK.app);
|
||||
jamtrackScreen.initialize();
|
||||
//var jamtrackScreen = new JK.JamTrackScreen(JK.app);
|
||||
//jamtrackScreen.initialize();
|
||||
|
||||
var jamtrackLanding = new JK.JamTrackLanding(JK.app);
|
||||
jamtrackLanding.initialize();
|
||||
//var jamtrackLanding = new JK.JamTrackLanding(JK.app);
|
||||
//jamtrackLanding.initialize();
|
||||
|
||||
var shoppingCartScreen = new JK.ShoppingCartScreen(JK.app);
|
||||
shoppingCartScreen.initialize();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
| to access most functionality on this page.
|
||||
p
|
||||
| However, you can browse for
|
||||
a class="go-to-jamtracks" href='/client#/jamtrackBrowse' JamTracks
|
||||
a class="go-to-jamtracks" href='/client#/jamtrack/search' JamTracks
|
||||
| without logging in.
|
||||
br
|
||||
.clearall
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
.dialog-inner
|
||||
|
||||
= react_component 'JamTrackAutoComplete', {:onSearch => 'window.JK.OpenJamTrackDialogInstance.search'}
|
||||
button.search-btn.button-orange SEARCH
|
||||
.recording-wrapper
|
||||
table.open-jam-tracks cellspacing="0" cellpadding="0" border="0"
|
||||
thead
|
||||
|
|
@ -28,7 +30,7 @@
|
|||
.help-links
|
||||
a.what-are-jamtracks href='#'
|
||||
| What are JamTracks?
|
||||
a href='/client#/jamtrackBrowse' rel="external"
|
||||
a href='/client#/jamtrack/search' rel="external"
|
||||
| Shop for JamTracks
|
||||
.right
|
||||
a href="#" class="button-grey" layout-action="cancel"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
p Click the GET A JAMTRACK FREE button below. Browse to find the one you want, click the Add to cart, and we'll apply a credit during checkout to make the first one free! We're confident you'll be back for more.
|
||||
|
||||
.cta-big-button
|
||||
a.white-bordered-button href="/client#/jamtrackBrowse" GET A JAMTRACK FREE!
|
||||
a.white-bordered-button href="/client#/jamtrack/search" GET A JAMTRACK FREE!
|
||||
.column
|
||||
h1 Why are JamTracks Better than Backing Tracks?
|
||||
p
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
<% if @show_cta_free_jamtrack %>
|
||||
<div class="cta-free-jamtrack">
|
||||
<%= link_to image_tag("web/free-jamtrack-cta.png", :alt => "ClICK HERE TO PICK YOUR FIRST JAMTRACK FREE!"), "/client#/jamtrackBrowse", class: "cta-free-jamtrack" %>
|
||||
<%= link_to image_tag("web/free-jamtrack-cta.png", :alt => "ClICK HERE TO PICK YOUR FIRST JAMTRACK FREE!"), "/client#/jamtrack/search", class: "cta-free-jamtrack" %>
|
||||
<span class="value-indicator">$1.99 value</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
.video-container
|
||||
iframe src="//www.youtube.com/embed/askHvcCoNfw" frameborder="0" allowfullscreen="allowfullscreen"
|
||||
|
||||
a.go-jamtrack-shopping href="/client#/jamtrackBrowse" rel="external"
|
||||
a.go-jamtrack-shopping href="/client#/jamtrack/search" rel="external"
|
||||
| Shop for free
|
||||
br
|
||||
| JamTrack now!
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
strong JamTracks
|
||||
| are the best way to play with your favorite music. Unlike traditional backing tracks, JamTracks are complete multitrack recordings, with fully isolated tracks for each part.
|
||||
|
||||
= link_to image_tag("web/button_cta_jamtrack.png", width: 234, height:57), '/client#/jamtrackBrowse', class: 'cta-button jamtracks'
|
||||
= link_to image_tag("web/button_cta_jamtrack.png", width: 234, height:57), '/client#/jamtrack/search', class: 'cta-button jamtracks'
|
||||
br clear="all"
|
||||
.extra-links
|
||||
.learn-more
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ SampleApp::Application.routes.draw do
|
|||
match '/affiliate/links/:id', to: 'affiliates#links', via: :get, as: 'affilate_links'
|
||||
|
||||
# redirect /jamtracks to jamtracks browse page
|
||||
get '/jamtracks', to: redirect('/client#/jamtrackBrowse')
|
||||
get '/jamtracks', to: redirect('/client#/jamtrack/search')
|
||||
|
||||
# product pages
|
||||
match '/products/jamblaster', to: 'landings#product_jamblaster', via: :get, as: 'product_jamblaster'
|
||||
|
|
@ -233,6 +233,7 @@ SampleApp::Application.routes.draw do
|
|||
match '/backing_tracks' => 'api_backing_tracks#index', :via => :get, :as => 'api_backing_tracks_list'
|
||||
|
||||
# Jamtracks
|
||||
match '/jamtracks/autocomplete' => 'api_jam_tracks#autocomplete', :via => :get, :as => 'api_jam_tracks_autocomplete'
|
||||
match '/jamtracks/purchased' => 'api_jam_tracks#purchased', :via => :get, :as => 'api_jam_tracks_purchased'
|
||||
match '/jamtracks/artists' => 'api_jam_tracks#artist_index', :via => :get, :as => 'api_jam_tracks_list_artists'
|
||||
match '/jamtracks/:plan_code' => 'api_jam_tracks#show', :via => :get, :as => 'api_jam_tracks_show'
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ namespace :jam_tracks do
|
|||
JamTrackImporter.synchronize_all(skip_audio_upload:false)
|
||||
end
|
||||
|
||||
task tency_dups: :environment do |task, args|
|
||||
|
||||
end
|
||||
task onboarding_exceptions: :environment do |task, args|
|
||||
JamTrackImporter.onboarding_exceptions
|
||||
end
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ describe ApiRecordingsController do
|
|||
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
@jam_track = FactoryGirl.create(:jam_track)
|
||||
@jam_track.reload
|
||||
|
||||
# make sure the jam track is opened
|
||||
@music_session.jam_track = @jam_track
|
||||
|
|
|
|||
|
|
@ -701,8 +701,8 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
|
||||
describe "Complete Checkout Flow" do
|
||||
it "for anonymous user" do
|
||||
visit "/client#/jamtrackBrowse"
|
||||
find('h1', text: 'jamtracks')
|
||||
visit "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search"
|
||||
find('h1', text: 'search jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jamtrack_acdc_backinblack.id}\"]", text: 'GET IT FREE!').trigger(:click)
|
||||
|
|
@ -756,7 +756,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
|
||||
# now, go back to checkout flow again, and make sure we are told there are no free jam tracks
|
||||
|
||||
visit "/client#/jamtrackBrowse"
|
||||
visit "/client?song=#{jamtrack_pearljam_evenflow.name}#/jamtrack/search"
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jamtrack_pearljam_evenflow.id}\"]", text: 'ADD TO CART').trigger(:click)
|
||||
find('h1', text: 'shopping cart')
|
||||
|
|
@ -833,9 +833,9 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
affiliate_params = partner.affiliate_query_params
|
||||
|
||||
visit '/landing/jamtracks/acdc-backinblack?' + affiliate_params
|
||||
find('.browse-all a').trigger(:click)
|
||||
find('.browse-band a').trigger(:click)
|
||||
|
||||
find('h1', text: 'jamtracks')
|
||||
find('h1', text: 'search jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jamtrack_acdc_backinblack.id}\"]", text: 'GET IT FREE!').trigger(:click)
|
||||
|
|
@ -877,7 +877,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
|
||||
# now, go back to checkout flow again, and make sure we are told there are no free jam tracks
|
||||
|
||||
visit "/client#/jamtrackBrowse"
|
||||
visit "/client?song=#{jamtrack_pearljam_evenflow.name}#/jamtrack/search"
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jamtrack_pearljam_evenflow.id}\"]", text: 'ADD TO CART').trigger(:click)
|
||||
find('h1', text: 'shopping cart')
|
||||
|
|
@ -947,7 +947,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
|
||||
it "for existing user with a freebie available (already logged in)" do
|
||||
|
||||
fast_signin(user, "/client#/jamtrackBrowse")
|
||||
fast_signin(user, "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search")
|
||||
find('h1', text: 'jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
|
|
@ -967,7 +967,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
user.has_redeemable_jamtrack = false
|
||||
user.save!
|
||||
|
||||
fast_signin(user, "/client#/jamtrackBrowse")
|
||||
fast_signin(user, "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search")
|
||||
find('h1', text: 'jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
|
|
@ -1025,7 +1025,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
user.save!
|
||||
|
||||
# the point of this is to also prove that the free jamtrack does not carry over to the existing user, once they log in
|
||||
visit "/client#/jamtrackBrowse"
|
||||
visit "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search"
|
||||
find('h1', text: 'jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
|
|
@ -1087,7 +1087,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
set_cookie('redeemed_jamtrack', 'true')
|
||||
|
||||
# the point of this is to also prove that the free jamtrack does not carry over to the existing user, once they log in
|
||||
visit "/client#/jamtrackBrowse"
|
||||
visit "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search"
|
||||
find('h1', text: 'jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
|
|
@ -1152,7 +1152,7 @@ describe "Checkout", :js => true, :type => :feature, :capybara_feature => true d
|
|||
set_cookie('redeemed_jamtrack', 'true')
|
||||
|
||||
# the point of this is to also prove that the free jamtrack does not carry over to the existing user, once they log in
|
||||
visit "/client#/jamtrackBrowse"
|
||||
visit "/client?song=#{jamtrack_acdc_backinblack.name}#/jamtrack/search"
|
||||
find('h1', text: 'jamtracks')
|
||||
#find('a', text: 'What is a JamTrack?')
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ describe "Individual JamTrack", :js => true, :type => :feature, :capybara_featur
|
|||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('.browse-band a')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrackBrowse")
|
||||
find('.browse-all a')['href'].should eq("/client#/jamtrackBrowse")
|
||||
find('a.cta-free-jamtrack')['href'].should eq("/client#/jamtrackBrowse")
|
||||
find('.browse-band a')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrack/search")
|
||||
find('.browse-all a')['href'].should eq("/client#/jamtrack/search")
|
||||
find('a.cta-free-jamtrack')['href'].should eq("/client#/jamtrack/search")
|
||||
find('a.cta-free-jamtrack').trigger(:click)
|
||||
find('h1', text: 'check out')
|
||||
find('h3', text: 'OR SIGN UP USING YOUR EMAIL')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "JamTrack Search", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
let(:user) { FactoryGirl.create(:user, has_redeemable_jamtrack: true) }
|
||||
let(:jt_us) { FactoryGirl.create(:jam_track, :name=>'jt_us', sales_region: 'United States', make_track: true, original_artist: "foobar") }
|
||||
let(:jt_ww) { FactoryGirl.create(:jam_track, :name=>'jt_ww', sales_region: 'Worldwide', make_track: true, original_artist: "barfoo") }
|
||||
let(:jt_rock) { FactoryGirl.create(:jam_track, :name=>'jt_rock', genres: [JamRuby::Genre.find('rock')], make_track: true, original_artist: "badfood") }
|
||||
let(:jt_blues) { FactoryGirl.create(:jam_track, :name=>'jt_blues', genres: [JamRuby::Genre.find('blues')], make_track: true, original_artist: "foodbart") }
|
||||
|
||||
before(:all) do
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.current_driver = Capybara.javascript_driver
|
||||
Capybara.default_wait_time = 30 # these tests are SLOOOOOW
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrackRight.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
|
||||
stub_const("APP_CONFIG", web_config)
|
||||
|
||||
end
|
||||
|
||||
it "search repeatedly" do
|
||||
|
||||
fast_signin user, "/client#/jamtrack/search"
|
||||
find('h1', text: 'search jamtracks')
|
||||
|
||||
find('#jamtrackSearch .Select-control').trigger(:mousedown)
|
||||
|
||||
# wait for the 'Type to search' prompt to show
|
||||
find('#jamtrackSearch .Select-noresults')
|
||||
|
||||
send_key_sequence('#jamtrackSearch .Select-control', 'abc')
|
||||
|
||||
jt_us.touch
|
||||
|
||||
find('.Select-input').trigger(:blur)
|
||||
find('#jamtrackSearch .search-btn').trigger(:click)
|
||||
|
||||
find('#jamtrackSearch .Select-control').trigger(:mousedown)
|
||||
send_key_sequence('#jamtrackSearch .Select-control', 'foo')
|
||||
|
||||
#screenshot_and_open_image
|
||||
|
||||
find('.jamtrack-record[data-jamtrack-id="' + jt_us.id + '"]')
|
||||
find('.show-artist', text: jt_us.original_artist).trigger(:click)
|
||||
|
||||
find('h2.jamtrack-results-header', text: "search results: jamtracks for artist \"#{jt_us.original_artist}\"")
|
||||
find('.jamtrack-record[data-jamtrack-id="' + jt_us.id + '"]')
|
||||
|
||||
|
||||
# TODO: do a second search. Unfortunately, i Can't figure out how to simulate events to cause the search bar to reset
|
||||
#jt_blues.touch
|
||||
#find('.Select-input').trigger(:blur)
|
||||
#find('#jamtrackSearch .Select-control').trigger(:mousedown)
|
||||
#send_key_sequence('#jamtrackSearch .Select-control', 'foo')
|
||||
|
||||
#find('.jamtrack-record[data-jamtrack-id="' + jt_blues.id + '"]')
|
||||
#screenshot_and_open_image
|
||||
|
||||
#jt_ww.touch
|
||||
#jt_rock.touch
|
||||
#jt_blues.touch
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -5,8 +5,8 @@ describe "JamTrack Landing", :js => true, :type => :feature, :capybara_feature =
|
|||
let(:user) { FactoryGirl.create(:user, has_redeemable_jamtrack: true) }
|
||||
let(:jt_us) { FactoryGirl.create(:jam_track, :name=>'jt_us', sales_region: 'United States', make_track: true, original_artist: "foobar") }
|
||||
let(:jt_ww) { FactoryGirl.create(:jam_track, :name=>'jt_ww', sales_region: 'Worldwide', make_track: true, original_artist: "barfoo") }
|
||||
let(:jt_rock) { FactoryGirl.create(:jam_track, :name=>'jt_rock', genre: JamRuby::Genre.find('rock'), make_track: true, original_artist: "badfood") }
|
||||
let(:jt_blues) { FactoryGirl.create(:jam_track, :name=>'jt_blues', genre: JamRuby::Genre.find('blues'), make_track: true, original_artist: "foodbart") }
|
||||
let(:jt_rock) { FactoryGirl.create(:jam_track, :name=>'jt_rock', genres: [JamRuby::Genre.find('avante-garde')], make_track: true, original_artist: "badfood") }
|
||||
let(:jt_blues) { FactoryGirl.create(:jam_track, :name=>'jt_blues', genres: [JamRuby::Genre.find('blues')], make_track: true, original_artist: "foodbart") }
|
||||
|
||||
before(:all) do
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
|
|
@ -27,10 +27,12 @@ describe "JamTrack Landing", :js => true, :type => :feature, :capybara_feature =
|
|||
end
|
||||
|
||||
it "not logged in" do
|
||||
jt_us.touch
|
||||
jt_ww.touch
|
||||
jt_rock.touch
|
||||
jt_rock.reload
|
||||
jt_blues.touch
|
||||
jt_blues.reload
|
||||
|
||||
visit '/client#/jamtrackLanding'
|
||||
visit '/client#/jamtrack'
|
||||
|
||||
find('h2', text: 'what are jamtracks?')
|
||||
if web_config.one_free_jamtrack_per_user
|
||||
|
|
@ -39,20 +41,24 @@ describe "JamTrack Landing", :js => true, :type => :feature, :capybara_feature =
|
|||
find('.no-free-jamtrack')
|
||||
end
|
||||
|
||||
find("a[artist='#{jt_us.original_artist}']", text: 'foobar (1)')
|
||||
find("a[artist='#{jt_ww.original_artist}']", text: 'barfoo (1)')
|
||||
# and go ahead and try out some searches
|
||||
jk_select(jt_rock.genres[0].description, '#jamtrackLanding .genre-list')
|
||||
jk_select(jt_rock.jam_track_tracks[0].instrument.description, '#jamtrackLanding .instrument-list')
|
||||
find('.search-by-filter-btn').trigger(:click)
|
||||
# should have transitioned to the filter screen
|
||||
find('.JamTrackFilterScreen')
|
||||
# and the search should have been kicked off and already showing our track
|
||||
find('.jamtrack-record[data-jamtrack-id="' + jt_rock.id + '"]')
|
||||
end
|
||||
|
||||
it "logged in and has redeemable track" do
|
||||
jt_us.touch
|
||||
jt_ww.touch
|
||||
|
||||
fast_signin(user, '/client#/jamtrackLanding')
|
||||
fast_signin(user, '/client#/jamtrack')
|
||||
|
||||
find('h2', text: 'what are jamtracks?')
|
||||
find('.free-jamtrack')
|
||||
find("a[artist='#{jt_us.original_artist}']", text: 'foobar (1)')
|
||||
find("a[artist='#{jt_ww.original_artist}']", text: 'barfoo (1)')
|
||||
end
|
||||
|
||||
it "logged in and does not have redeemable track" do
|
||||
|
|
@ -61,11 +67,9 @@ describe "JamTrack Landing", :js => true, :type => :feature, :capybara_feature =
|
|||
user.has_redeemable_jamtrack = false
|
||||
user.save!
|
||||
|
||||
fast_signin(user, '/client#/jamtrackLanding')
|
||||
fast_signin(user, '/client#/jamtrack')
|
||||
|
||||
find('h2', text: 'what are jamtracks?')
|
||||
find('.no-free-jamtrack')
|
||||
find("a[artist='#{jt_us.original_artist}']", text: 'foobar (1)')
|
||||
find("a[artist='#{jt_ww.original_artist}']", text: 'barfoo (1)')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature
|
|||
before(:all) do
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.current_driver = Capybara.javascript_driver
|
||||
Capybara.default_wait_time = 30 # these tests are SLOOOOOW
|
||||
Capybara.default_wait_time = 10 # these tests are SLOOOOOW
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature
|
|||
end
|
||||
|
||||
def find_jamtrack jamtrack, options = {}
|
||||
jamtrack_record = find(".jamtrack-record[jamtrack-id=\"#{jamtrack.id}\"]")
|
||||
jamtrack_record = find(".jamtrack-record[data-jamtrack-id=\"#{jamtrack.id}\"]")
|
||||
#jamtrack_record.find('.detail-value', text: jamtrack.name)
|
||||
#jamtrack_record.find('.detail-value', text: jamtrack.recording_type)
|
||||
#jamtrack_record.find('.detail-value', text: jamtrack.original_artist)
|
||||
|
|
@ -58,68 +58,24 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature
|
|||
end
|
||||
|
||||
def not_find_jamtrack jamtrack
|
||||
should_not have_selector(".jamtrack-record[jamtrack-id=\"#{jamtrack.id}\"]")
|
||||
end
|
||||
|
||||
describe "Shopping" do
|
||||
|
||||
before(:each) do
|
||||
visit "/client#/jamtrackBrowse"
|
||||
find('h1', text: 'jamtracks')
|
||||
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_artist')
|
||||
end
|
||||
|
||||
it "shows all JamTracks" do
|
||||
find_jamtrack jt_us
|
||||
find_jamtrack jt_ww
|
||||
find_jamtrack jt_rock
|
||||
end
|
||||
|
||||
=begin
|
||||
# removed for now
|
||||
it "filters with availability" do
|
||||
jk_select('Worldwide', '#jamtrack-find-form #jamtrack_artist')
|
||||
find_jamtrack jt_ww
|
||||
not_find_jamtrack jt_us
|
||||
not_find_jamtrack jt_rock
|
||||
end
|
||||
=end
|
||||
|
||||
it "filters with artist" do
|
||||
jk_select("foobar", '#jamtrack-find-form #jamtrack_artist')
|
||||
find_jamtrack jt_us
|
||||
not_find_jamtrack jt_blues
|
||||
not_find_jamtrack jt_rock
|
||||
not_find_jamtrack jt_ww
|
||||
end
|
||||
|
||||
it "filters with instrument" do
|
||||
jk_select('Electric Guitar', '#jamtrack-find-form #jamtrack_instrument')
|
||||
find_jamtrack jt_us
|
||||
find_jamtrack jt_ww
|
||||
find_jamtrack jt_rock
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it "sets artist filter" do
|
||||
pending "The item is clearly present, so not currently sure why capybar can't find it"
|
||||
visit "/client?artist=foobar#/jamtrackBrowse"
|
||||
art = find('#jamtrack_artist')
|
||||
puts "art: #{art}"
|
||||
should_not have_selector(".jamtrack-record[data-jamtrack-id=\"#{jamtrack.id}\"]")
|
||||
end
|
||||
|
||||
describe "Shopping Carts" do
|
||||
|
||||
before(:each) do
|
||||
visit "/client#/jamtrackBrowse"
|
||||
find('h1', text: 'jamtracks')
|
||||
visit "/client#/jamtrack/search"
|
||||
find('h1', text: 'jamtracks')
|
||||
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_artist')
|
||||
find('#jamtrackSearch .Select-control').trigger(:mousedown)
|
||||
# wait for the 'Type to search' prompt to show
|
||||
find('#jamtrackSearch .Select-noresults')
|
||||
send_key_sequence('#jamtrackSearch .Select-control', jt_us.name)
|
||||
find('#jamtrackSearch .search-btn').trigger(:click)
|
||||
end
|
||||
|
||||
it "adds/deletes JamTrack to/from Cart" do
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click)
|
||||
|
||||
find('h1', text: 'shopping cart')
|
||||
|
|
@ -127,19 +83,22 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature
|
|||
find('.cart-item-price', text: "$ #{jt_us.price}")
|
||||
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_artist')
|
||||
find('button.disabled.search-btn')
|
||||
|
||||
|
||||
find_jamtrack jt_us, {added_cart: true}
|
||||
|
||||
find('a.header-shopping-cart').trigger(:click)
|
||||
find("a.remove-cart").trigger(:click)
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
jk_select('Any', '#jamtrack-find-form #jamtrack_artist')
|
||||
find('button.disabled.search-btn')
|
||||
|
||||
find_jamtrack jt_us
|
||||
|
||||
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click)
|
||||
find('.shopping-sub-total', text: "Subtotal:$ #{jt_us.price}")
|
||||
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
|
||||
find('button.disabled.search-btn')
|
||||
|
||||
find_jamtrack jt_ww
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ bputs "before load poltergeist"
|
|||
require 'capybara/poltergeist'
|
||||
bputs "before register capybara"
|
||||
Capybara.register_driver :poltergeist do |app|
|
||||
driver = Capybara::Poltergeist::Driver.new(app, { debug: false, phantomjs_logger: File.open('log/phantomjs.out', 'w'), phantomjs_options: ['--ignore-ssl-errors=yes'] })
|
||||
driver = Capybara::Poltergeist::Driver.new(app, { debug: false, phantomjs_logger: File.open('log/phantomjs.out', 'w'), phantomjs_options: ['--ignore-ssl-errors=yes', '--load-images=no'] })
|
||||
end
|
||||
Capybara.javascript_driver = :poltergeist
|
||||
Capybara.default_wait_time = 10
|
||||
|
|
|
|||
|
|
@ -739,9 +739,23 @@ end
|
|||
def send_key(selector, keycode = 13)
|
||||
keypress_script = "var e = $.Event('keyup', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
|
||||
page.driver.execute_script(keypress_script)
|
||||
end
|
||||
|
||||
def send_key_sequence(selector, text)
|
||||
text.each_char do |char|
|
||||
keycode = char.ord - 32
|
||||
keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
|
||||
page.driver.execute_script(keypress_script)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def send_keydown(selector, keycode = 13)
|
||||
keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
|
||||
page.driver.execute_script(keypress_script)
|
||||
end
|
||||
|
||||
|
||||
def special_characters
|
||||
["?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}"]
|
||||
end
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,73 @@
|
|||
function topPosition(domElt) {
|
||||
if (!domElt) {
|
||||
return 0;
|
||||
}
|
||||
return domElt.offsetTop + topPosition(domElt.offsetParent);
|
||||
}
|
||||
|
||||
(function () {
|
||||
if (React.addons && React.addons.InfiniteScroll) {
|
||||
return React.addons.InfiniteScroll;
|
||||
}
|
||||
React.addons = React.addons || {};
|
||||
var InfiniteScroll = React.addons.InfiniteScroll = React.createClass({
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
pageStart: 0,
|
||||
hasMore: false,
|
||||
loadMore: function () {},
|
||||
threshold: 250,
|
||||
scrollNode: null
|
||||
};
|
||||
},
|
||||
componentDidMount: function () {
|
||||
this.pageLoaded = this.props.pageStart;
|
||||
this.attachScrollListener();
|
||||
},
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return !_.isEqual(this.props.children, nextProps.children);
|
||||
},
|
||||
componentDidUpdate: function () {
|
||||
this.attachScrollListener();
|
||||
},
|
||||
render: function () {
|
||||
var props = this.props;
|
||||
return React.DOM.tbody(null, props.children, props.hasMore && (props.loader || InfiniteScroll._defaultLoader));
|
||||
},
|
||||
scrollListener: function () {
|
||||
var el = this.props.scrollNode ? $(this.getDOMNode()).closest(this.props.scrollNode).get(0) : this.getDOMNode();
|
||||
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
|
||||
console.log("scrollTop", scrollTop)
|
||||
if (topPosition(el) + el.offsetHeight - scrollTop - window.innerHeight < Number(this.props.threshold)) {
|
||||
this.detachScrollListener();
|
||||
// call loadMore after detachScrollListener to allow
|
||||
// for non-async loadMore functions
|
||||
this.props.loadMore(this.pageLoaded += 1);
|
||||
}
|
||||
},
|
||||
attachScrollListener: function () {
|
||||
if (!this.props.hasMore) {
|
||||
return;
|
||||
}
|
||||
console.log("attachScrollListener")
|
||||
window.addEventListener('scroll', this.scrollListener);
|
||||
window.addEventListener('resize', this.scrollListener);
|
||||
|
||||
setTimeout(
|
||||
this.scrollListener,
|
||||
1
|
||||
);
|
||||
},
|
||||
detachScrollListener: function () {
|
||||
window.removeEventListener('scroll', this.scrollListener);
|
||||
window.removeEventListener('resize', this.scrollListener);
|
||||
},
|
||||
componentWillUnmount: function () {
|
||||
this.detachScrollListener();
|
||||
}
|
||||
});
|
||||
InfiniteScroll.setDefaultLoader = function (loader) {
|
||||
InfiniteScroll._defaultLoader = loader;
|
||||
};
|
||||
return InfiniteScroll;
|
||||
})();
|
||||
Loading…
Reference in New Issue