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 uiJamTracks.push trackRow artists = [] artistsShown = 0 for artist in @state.artists if @state.show_all_artists || artistsShown < @MAX_ARTIST_SHOW artists.push `
{artist.original_artist}
` artistsShown += 1 artists.push `
No matching artists
` if artists.length == 0 if !@state.show_all_artists && @state.artists.length > @MAX_ARTIST_SHOW artists.push `
show all
` else if @state.show_all_artists artists.push `
hide artists
` 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 `
` actionBtn = null if jamtrack.is_free actionBtn = ` GET IT FREE!` else if jamtrack.purchased actionBtn = `PURCHASED` else if jamtrack.added_cart actionBtn = `ALREADY IN CART` else actionBtn = `ADD TO CART` availabilityNotice = null if jamtrack.sales_region==context.JK.AVAILABILITY_US availabilityNotice = `
This JamTrack available only to US customers.      why?
` jamtracks.push `
"{jamtrack.name}"
by {jamtrack.original_artist}

Songwriters:
{jamtrack.songwriter}
Publishers:
{jamtrack.publisher}
Genres:
{jamtrack.genres.join(', ')}
Version:
{jamtrack.recording_type}
show all tracks
{tracks}
$ {jamtrack.price}
{actionBtn} {availabilityNotice}
` #jamtracks.push `
No matching JamTracks
` 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 = `

search results: artists

{artists}
` jamTracksSection = `

{jamtracksHeader} back to jamtracks home

{jamtracks}
JAMTRACK TRACKS INCLUDED / PREVIEW SHOP
No more JamTracks
` options = {} searchValue = if @state.search == 'SEPARATOR' then '' else window.JamTrackSearchInput `
{artistSection} {jamTracksSection}
` 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() artistSearch = {limit:100} if search_type == 'artist-select' # the user wants to see just artists matching thes exact name artistSearch.artist = input else # the user wants to see anything sort of matching input artistSearch.artist_search = input if input? @rest.getJamTrackArtists(artistSearch) .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 = input # works like exact match else if search_type == 'song-select' query.song = input # works as exact match 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}\"]") alreadyRegistered = jamtrackElement.data('registered') unless alreadyRegistered jamtrackElement.data('jamTrack', jamTrack) jamtrackElement.data('registered', true) 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 $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) -> @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('
... Loading more JamTracks ...
') @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 ') 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 ') 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: () -> @setState({is_free: context.JK.currentUserFreeJamTrack}) if !@state.first_search @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) })