diff --git a/ruby/lib/jam_ruby/models/feed.rb b/ruby/lib/jam_ruby/models/feed.rb index 43f31c430..64f002a1d 100644 --- a/ruby/lib/jam_ruby/models/feed.rb +++ b/ruby/lib/jam_ruby/models/feed.rb @@ -123,19 +123,31 @@ module JamRuby - - if query.length == 0 - [query, nil] - elsif query.length < limit - [query, nil] - else - if sort == 'date' - [query, query.last.id] + if params[:hash] + if query.length == 0 + { query:query, next: nil} + elsif query.length < limit + { query:query, next: nil} else - [query, start + limit] + if sort == 'date' + { query:query, next: query.last.id} + else + { query:query, next: start + limit} + end + end + else + if query.length == 0 + [query, nil] + elsif query.length < limit + [query, nil] + else + if sort == 'date' + [query, query.last.id] + else + [query, start + limit] + end end end - end end end diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb index 65ab57968..570734180 100644 --- a/ruby/lib/jam_ruby/models/recording.rb +++ b/ruby/lib/jam_ruby/models/recording.rb @@ -345,7 +345,8 @@ module JamRuby # meant to be used as a way to 'pluck' a claimed_recording appropriate for user. def candidate_claimed_recording - claimed_recordings.where(is_public: true).first + #claimed_recordings.where(is_public: true).first + claimed_recordings.first end private diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index fb73151ac..4de3b0f4c 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -103,17 +103,17 @@ module JamRuby DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] - F_SORT_RECENT = ['Most Recent', :recent] - F_SORT_OLDEST = ['Ending Soonest', :ending_soon] - F_SORT_LENGTH = ['Session Length', :session_length] + F_SORT_RECENT = ['Most Recent', :date] + F_SORT_OLDEST = ['Most Liked', :likes] + F_SORT_LENGTH = ['Most Played', :plays] F_SORT_OPTS = [F_SORT_RECENT, F_SORT_LENGTH, F_SORT_OLDEST] - SHOW_BOTH = ['Both', :both] - SHOW_SESSIONS = ['Sessions', :sessions] - SHOW_RECORDINGS = ['Recordings', :recordings] + SHOW_BOTH = ['Sessions & Recordings', :all] + SHOW_SESSIONS = ['Sessions', :music_session_history] + SHOW_RECORDINGS = ['Recordings', :recording] SHOW_OPTS = [SHOW_BOTH, SHOW_SESSIONS, SHOW_RECORDINGS] - DATE_OPTS = [['Today', 0], ['This week', 7], ['Past 2 weeks', 14], ['This month', 30], ['Past year', 365], ['All', -1]] + DATE_OPTS = [['Today', 'today'], ['This Week', 'week'], ['This Month', 'month'], ['All Time', 'all']] def self.order_param(params, keys=M_ORDERING_KEYS) ordering = params[:orderby] diff --git a/web/Gemfile b/web/Gemfile index 0748f7187..6ea68e5fb 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -19,6 +19,7 @@ else gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}" ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true" end +gem 'oj' gem 'builder' gem 'rails', '~>3.2.11' gem 'jquery-rails', '2.0.2' diff --git a/web/app/assets/javascripts/AAC_underscore-min.js b/web/app/assets/javascripts/AAC_underscore-min.js deleted file mode 100644 index c1d9d3aed..000000000 --- a/web/app/assets/javascripts/AAC_underscore-min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file diff --git a/web/app/assets/javascripts/application.js b/web/app/assets/javascripts/application.js index e96b3b6fe..49fbdb9e7 100644 --- a/web/app/assets/javascripts/application.js +++ b/web/app/assets/javascripts/application.js @@ -26,6 +26,8 @@ //= require jquery.easydropdown //= require jquery.scrollTo //= require jquery.infinitescroll +//= require jquery.hoverIntent +//= require jquery.dotdotdot //= require globals //= require AAB_message_factory //= require AAC_underscore diff --git a/web/app/assets/javascripts/feed.js b/web/app/assets/javascripts/feed.js index 8baa2b36f..77a073e95 100644 --- a/web/app/assets/javascripts/feed.js +++ b/web/app/assets/javascripts/feed.js @@ -6,15 +6,366 @@ var logger = context.JK.logger; var rest = context.JK.Rest(); + var currentQuery = null; + var currentPage = 0; + var LIMIT = 20; + var $screen = null; + var $next = null; + var $scroller = null; + var $content = null; + var $noMoreFeeds = null; + var $refresh = null; + var $sortFeedBy = null; + var $includeDate = null; + var $includeType = null; + var next = null; + + function defaultQuery() { + var query = { limit:LIMIT, page:currentPage}; + + if(next) { + query.since = next; + } + + return query; + } + + function buildQuery() { + currentQuery = defaultQuery(); + + // specify search criteria based on form + currentQuery.sort = $sortFeedBy.val(); + currentQuery.time_range = $includeDate.val(); + currentQuery.type = $includeType.val(); + + return currentQuery; + } function beforeShow(data) { } function afterShow(data) { - + refresh(); } + function clearResults() { + currentPage = 0; + $content.empty(); // TODO: do we need to delete audio elements? + $noMoreFeeds.hide(); + next = null; + } + + function handleFeedResponse(response) { + next = response.next; + + renderFeeds(response); + + if(response.next == null) { + // if we less results than asked for, end searching + $scroller.infinitescroll('pause'); + logger.debug("end of feeds") + + if(currentPage > 0) { + $noMoreFeeds.show(); + // there are bugs with infinitescroll not removing the 'loading'. + // it's most noticeable at the end of the list, so whack all such entries + $('.infinite-scroll-loader').remove(); + } + } + else { + currentPage++; + buildQuery(); + registerInfiniteScroll(); + } + } + + function refresh() { + + clearResults(); + + currentQuery = buildQuery(); + rest.getFeeds(currentQuery) + .done(function(response) { + handleFeedResponse(response); + }) + .fail(function(jqXHR) { + app.notifyServerError(jqXHR, 'Feed Unavailable') + }) + } + + function registerInfiniteScroll() { + + $scroller.infinitescroll({ + behavior: 'local', + navSelector: '#feedScreen .btn-next-pager', + nextSelector: '#feedScreen .btn-next-pager', + binder: $scroller, + dataType: 'json', + appendCallback: false, + prefill: false, + bufferPx:100, + loading: { + msg: $('
Loading ...
'), + img: '/assets/shared/spinner.gif' + }, + path: function(page) { + return '/api/feeds?' + $.param(buildQuery()); + } + },function(json, opts) { + handleFeedResponse(json); + }); + $scroller.infinitescroll('resume'); + } + + + function toggleSessionDetails() { + var $detailsLink = $(this); + var $feedItem = $detailsLink.closest('.feed-entry'); + var $musicians = $feedItem.find('.musician-detail'); + var $description = $feedItem.find('.description'); + var toggledOpen = $detailsLink.data('toggledOpen'); + + if(toggledOpen) { + $feedItem.css('height', $feedItem.height() + 'px') + $feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() { + $feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height')); + + $musicians.hide(); + $description.css('height', $description.data('original-height')); + $description.dotdotdot(); + }); + } + else { + $description.trigger('destroy.dot'); + $description.data('original-height', $description.css('height')).css('height', 'auto'); + $musicians.show(); + $feedItem.animate({'max-height': '1000px'}); + } + + toggledOpen = !toggledOpen; + $detailsLink.data('toggledOpen', toggledOpen); + return false; + } + + function startSessionPlay($feedItem) { + var img = $('.play-icon', $feedItem); + var $controls = $feedItem.find('.session-controls'); + img.attr('src', '/assets/content/icon_pausebutton.png'); + $controls.trigger('play.listenBroadcast'); + $feedItem.data('playing', true); + } + + function stopSessionPlay($feedItem) { + var img = $('.play-icon', $feedItem); + var $controls = $feedItem.find('.session-controls'); + img.attr('src', '/assets/content/icon_playbutton.png'); + $controls.trigger('pause.listenBroadcast'); + $feedItem.data('playing', false); + } + + function toggleSessionPlay() { + var $playLink = $(this); + var $feedItem = $playLink.closest('.feed-entry'); + + var $status = $feedItem.find('.session-status') + var playing = $feedItem.data('playing'); + + if(playing) { + $status.text('SESSION IN PROGRESS'); + stopSessionPlay($feedItem); + } + else { + startSessionPlay($feedItem); + } + return false; + } + + function stateChangeSession(e, data) { + var $controls = data.element; + var $feedItem = $controls.closest('.feed-entry'); + var $status = $feedItem.find('.session-status'); + + if(data.displayText) $status.text(data.displayText); + + if(data.isEnd) stopSessionPlay(); + + if(data.isSessionOver) { + $controls.removeClass('inprogress').addClass('ended') + } + } + + function startRecordingPlay($feedItem) { + var img = $('.play-icon', $feedItem); + var $controls = $feedItem.find('.recording-controls'); + img.attr('src', '/assets/content/icon_pausebutton.png'); + $controls.trigger('play.listenRecording'); + $feedItem.data('playing', true); + } + + function stopRecordingPlay($feedItem) { + var img = $('.play-icon', $feedItem); + var $controls = $feedItem.find('.recording-controls'); + img.attr('src', '/assets/content/icon_playbutton.png'); + $controls.trigger('pause.listenRecording'); + $feedItem.data('playing', false); + } + + function toggleRecordingPlay() { + + var $playLink = $(this); + var $feedItem = $playLink.closest('.feed-entry'); + var playing = $feedItem.data('playing'); + + if(playing) { + stopRecordingPlay($feedItem); + } + else { + startRecordingPlay($feedItem); + } + return false; + } + + + function stateChangeRecording(e, data) { + var $controls = data.element; + var $feedItem = $controls.closest('.feed-entry'); + + var $sliderBar = $('.recording-position', $feedItem); + var $statusBar = $('.recording-status', $feedItem); + var $currentTime = $('.recording-current', $feedItem); + var $status = $('.status-text', $feedItem); + var $playButton = $('.play-button', $feedItem); + + if(data.isEnd) stopRecordingPlay($feedItem); + if(data.isError) { + $sliderBar.hide(); + $playButton.hide(); + $currentTime.hide(); + $statusBar.show(); + $status.text(data.displayText); + } + } + + function toggleRecordingDetails() { + var $detailsLink = $(this); + var $feedItem = $detailsLink.closest('.feed-entry'); + var $musicians = $feedItem.find('.musician-detail'); + var $description = $feedItem.find('.description'); + var $name = $feedItem.find('.name'); + var toggledOpen = $detailsLink.data('toggledOpen'); + + if(toggledOpen) { + $feedItem.css('height', $feedItem.height() + 'px') + $feedItem.animate({'height': $feedItem.data('original-max-height')}).promise().done(function() { + $feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height')); + + $musicians.hide(); + $description.css('height', $description.data('original-height')); + $description.dotdotdot(); + $name.css('height', $name.data('original-height')); + $name.dotdotdot(); + }); + } + else { + $description.trigger('destroy.dot'); + $description.data('original-height', $description.css('height')).css('height', 'auto'); + $name.trigger('destroy.dot'); + $name.data('original-height', $name.css('height')).css('height', 'auto'); + $musicians.show(); + $feedItem.animate({'max-height': '1000px'}); + } + + toggledOpen = !toggledOpen; + $detailsLink.data('toggledOpen', toggledOpen); + + return false; + } + + + function renderFeeds(feeds) { + + $.each(feeds.entries, function(i, feed) { + if(feed.type == 'music_session_history') { + var options = { + feed_item: feed, + status_class: feed['is_over?'] ? 'ended' : 'inprogress', + mount_class: feed['has_mount?'] ? 'has-mount' : 'no-mount' + } + var $feedItem = $(context._.template($('#template-feed-music-session').html(), options, {variable: 'data'})); + var $controls = $feedItem.find('.session-controls'); + + // do everything we can before we attach the item to the page + $('.timeago', $feedItem).timeago(); + context.JK.prettyPrintElements($('.duration', $feedItem).show()); + context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem)); + $('.details', $feedItem).click(toggleSessionDetails); + $('.details-arrow', $feedItem).click(toggleSessionDetails); + $('.play-button', $feedItem).click(toggleSessionPlay); + + // put the feed item on the page + renderFeed($feedItem); + + // these routines need the item to have height to work (must be after renderFeed) + $controls.listenBroadcast(); + $controls.bind('statechange.listenBroadcast', stateChangeSession); + $('.dotdotdot', $feedItem).dotdotdot(); + $feedItem.data('original-max-height', $feedItem.css('height')); + context.JK.bindHoverEvents($feedItem); + } + else if(feed.type == 'recording') { + if(feed.claimed_recordings.length == 0) { + logger.error("a recording in the feed should always have one claimed_recording") + return; + } + var options = { + feed_item: feed, + candidate_claimed_recording: feed.claimed_recordings[0], + mix_class: feed['has_mix?'] ? 'has-mix' : 'no-mix', + } + + var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'})); + var $controls = $feedItem.find('.recording-controls'); + + $('.timeago', $feedItem).timeago(); + context.JK.prettyPrintElements($('.duration', $feedItem)); + context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem)); + $('.details', $feedItem).click(toggleRecordingDetails); + $('.details-arrow', $feedItem).click(toggleRecordingDetails); + $('.play-button', $feedItem).click(toggleRecordingPlay); + + // put the feed item on the page + renderFeed($feedItem); + + // these routines need the item to have height to work (must be after renderFeed) + $controls.listenRecording({recordingId: feed.id, claimedRecordingId: options.candidate_claimed_recording.id, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'}); + $controls.bind('statechange.listenRecording', stateChangeRecording); + $('.dotdotdot', $feedItem).dotdotdot(); + $feedItem.data('original-max-height', $feedItem.css('height')); + context.JK.bindHoverEvents($feedItem); + } + else { + logger.warn("skipping feed type: " + feed.type); + } + }) + } + + function renderFeed(feed) { + $content.append(feed); + } + + function search() { + logger.debug("Searching for feeds..."); + refresh(); + return false; + } + + function events() { + $refresh.on("click", search); + $sortFeedBy.on('change', search); + $includeDate.on('change', search); + $includeType.on('change', search); + } function initialize() { var screenBindings = { @@ -23,6 +374,21 @@ }; app.bindScreen('feed', screenBindings); + $screen = $('[layout-id="feed"]'); + $scroller = $screen.find('.content-body-scroller'); + $content = $screen.find('.feed-content'); + $noMoreFeeds = $('#end-of-feeds-list'); + $refresh = $screen.find('#btn-refresh-feed'); + $sortFeedBy = $screen.find('#feed_order_by'); + $includeDate = $screen.find('#feed_date'); + $includeType = $screen.find('#feed_show'); + + // set default search criteria + $sortFeedBy.val('date') + $includeDate.val('month') + $includeType.val('all') + + events(); } this.initialize = initialize; diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index e76fee93e..c0e028ead 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -618,6 +618,18 @@ }); } + function getFeeds(options) { + if(!options) { options = {}; } + return $.ajax({ + type: 'GET', + dataType: "json", + url: "/api/feeds?" + $.param(options), + processData:false + }) + } + + + function sendFriendRequest(app, userId, callback) { var url = "/api/users/" + context.JK.currentUserId + "/friend_requests"; $.ajax({ @@ -929,6 +941,7 @@ this.getClientDownloads = getClientDownloads; this.createEmailInvitations = createEmailInvitations; this.postFeedback = postFeedback; + this.getFeeds = getFeeds; this.serverHealthCheck = serverHealthCheck; this.sendFriendRequest = sendFriendRequest; this.acceptFriendRequest = acceptFriendRequest; diff --git a/web/app/assets/javascripts/jquery.listenRecording.js b/web/app/assets/javascripts/jquery.listenRecording.js index d508b9707..6bd55e648 100644 --- a/web/app/assets/javascripts/jquery.listenRecording.js +++ b/web/app/assets/javascripts/jquery.listenRecording.js @@ -347,6 +347,7 @@ $parent.triggerHandler('statechange.listenRecording', { + element: $parent, state: playState, displayText: displayText, isEnd: isEnd, diff --git a/web/app/assets/javascripts/jquery.listenbroadcast.js b/web/app/assets/javascripts/jquery.listenbroadcast.js index 9576f886d..fbbc090c7 100644 --- a/web/app/assets/javascripts/jquery.listenbroadcast.js +++ b/web/app/assets/javascripts/jquery.listenbroadcast.js @@ -389,6 +389,7 @@ $parent.triggerHandler('statechange.listenBroadcast', { + element: $parent, state: playState, displayText: displayText, isEnd: isEnd, diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 1c358145d..92443499a 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -151,7 +151,7 @@ $element.bt(text, options); } - context.JK.bindHoverEvents = function ($parent) { + context.JK.bindHoverEvents = function ($parent) { if($parent) { $parent = $('body'); diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css index c403ed71f..f5ec5c95b 100644 --- a/web/app/assets/stylesheets/client/client.css +++ b/web/app/assets/stylesheets/client/client.css @@ -43,12 +43,16 @@ *= require ./leaveSessionWarning *= require ./terms *= require ./createSession + *= require ./feed *= require ./genreSelector *= require ./sessionList *= require ./searchResults *= require ./banner *= require ./clientUpdate *= require ./musician + *= require web/audioWidgets + *= require web/recordings + #= require web/sessions *= require jquery.Jcrop *= require icheck/minimal/minimal */ \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/content.css.scss b/web/app/assets/stylesheets/client/content.css.scss index 8431e7e2d..108892b37 100644 --- a/web/app/assets/stylesheets/client/content.css.scss +++ b/web/app/assets/stylesheets/client/content.css.scss @@ -95,6 +95,10 @@ .filter-head { position: absolute; padding:11px 0; + + .btn-refresh-entries { + margin-top:7px; + } } .filter-body { height:100%; diff --git a/web/app/assets/stylesheets/client/feed.css.scss b/web/app/assets/stylesheets/client/feed.css.scss new file mode 100644 index 000000000..4dbd60d4f --- /dev/null +++ b/web/app/assets/stylesheets/client/feed.css.scss @@ -0,0 +1,5 @@ +#feedScreen { + .recording-current { + position:absolute; // solves a problem with duration wrapping--only in firefox + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/findSession.css.scss b/web/app/assets/stylesheets/client/findSession.css.scss index 5c4e47c0c..3cc12cd8a 100644 --- a/web/app/assets/stylesheets/client/findSession.css.scss +++ b/web/app/assets/stylesheets/client/findSession.css.scss @@ -48,14 +48,6 @@ height:20px; } - #end-of-session-list { - display:none; - overflow: visibility; - margin:40px auto 10px; - width:100%; - height:20px; - text-align:center; - } .btn-next { display:none; diff --git a/web/app/assets/stylesheets/client/jamkazam.css.scss b/web/app/assets/stylesheets/client/jamkazam.css.scss index 4dfd51558..8c992dc30 100644 --- a/web/app/assets/stylesheets/client/jamkazam.css.scss +++ b/web/app/assets/stylesheets/client/jamkazam.css.scss @@ -525,3 +525,17 @@ hr { height: 1px; margin: 10px 0; } + +// infinitescroll required element +.btn-next-pager { + display:none; +} + +.end-of-list { + display:none; + overflow: visibility; + margin:40px auto 10px; + width:100%; + height:20px; + text-align:center; +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/web/audioWidgets.css.scss b/web/app/assets/stylesheets/web/audioWidgets.css.scss index 6faf75ac5..ce9b3c251 100644 --- a/web/app/assets/stylesheets/web/audioWidgets.css.scss +++ b/web/app/assets/stylesheets/web/audioWidgets.css.scss @@ -112,6 +112,7 @@ .feed-entry { .session-controls, .recording-controls { + display:inline-block; &.ended { background-color: #471f18; diff --git a/web/app/controllers/api_feeds_controller.rb b/web/app/controllers/api_feeds_controller.rb index db17218b1..693fbe73e 100644 --- a/web/app/controllers/api_feeds_controller.rb +++ b/web/app/controllers/api_feeds_controller.rb @@ -3,15 +3,19 @@ class ApiFeedsController < ApiController respond_to :json def index - @feeds, @next = Feed.index(current_user, + data = Feed.index(current_user, start: params[:since], limit: params[:limit], sort: params[:sort], time_range: params[:time_range], type: params[:type], user: params[:user], - band: params[:band]) + band: params[:band], + hash: true) + + @feeds = data[:query] + @next = data[:next] render "api_feeds/index", :layout => nil end end \ No newline at end of file diff --git a/web/app/helpers/feeds_helper.rb b/web/app/helpers/feeds_helper.rb index 4aa802046..22e68b01f 100644 --- a/web/app/helpers/feeds_helper.rb +++ b/web/app/helpers/feeds_helper.rb @@ -7,14 +7,18 @@ module FeedsHelper image_tag resolve_avatarables(music_session_history.band, music_session_history.user) end - def session_duration(music_session_history, options={}) + def session_duration_value(music_session_history) if music_session_history.session_removed_at.nil? - duration(Time.now - music_session_history.created_at, options) + Time.now - music_session_history.created_at else - duration(music_session_history.session_removed_at - music_session_history.created_at, options) + music_session_history.session_removed_at - music_session_history.created_at end end + def session_duration(music_session_history, options={}) + duration(session_duration_value(music_session_history), options) + end + def session_text(music_session_history) if music_session_history.is_over? 'SESSION ENDED' diff --git a/web/app/views/api_feeds/show.rabl b/web/app/views/api_feeds/show.rabl index 10bb90294..5094da586 100644 --- a/web/app/views/api_feeds/show.rabl +++ b/web/app/views/api_feeds/show.rabl @@ -7,8 +7,22 @@ glue :music_session_history do 'music_session_history' end - attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count, :fan_access + attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count, :fan_access, :is_over?, :has_mount? + node do |history| + { + helpers: { + avatar: asset_path(resolve_avatarables(history.band, history.user)), + artist_name: session_artist_name(history), + utc_created_at: history.created_at.getutc.iso8601, + description: session_description(history), + status: session_text(history), + duration: session_duration_value(history), + duration_secs: history.created_at.to_i, + genre: session_genre(history) + } + } + end child(:user => :creator) { attributes :id, :first_name, :last_name, :photo_url @@ -17,17 +31,25 @@ glue :music_session_history do child(:unique_user_histories => :participants) { attributes :first_name, :last_name, :photo_url - node :id do |history| - history.user_id + node :id do |user| + user.user_id end + node do |user| + { + helpers: { + avatar: asset_path(resolve_avatarables(user)) + } + } + end + # total_duration comes back from the database as a string - node :duration do |history| - history.total_duration.nil? ? 0 : history.total_duration.to_i + node :duration do |user| + user.total_duration.nil? ? 0 : user.total_duration.to_i end - node :instruments do |history| - history.total_instruments.nil? ? [] : history.total_instruments.split('|').uniq + node :instruments do |user| + user.total_instruments.nil? ? [] : user.total_instruments.split('|').uniq end } @@ -52,7 +74,20 @@ glue :recording do 'recording' end - attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count + attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix? + + node do |recording| + { + helpers: { + avatar: asset_path(resolve_avatarables(recording.band, recording.owner)), + artist_name: recording_artist_name(recording), + utc_created_at: recording.created_at.getutc.iso8601, + name: recording_name(recording), + description: recording_description(recording), + genre: recording_genre(recording) + } + } + end child(:owner => :owner) { attributes :id, :name, :location, :photo_url @@ -70,6 +105,23 @@ glue :recording do } } + child(:grouped_tracks => :grouped_tracks) { + + :instrument_ids + + child(:musician => :musician) { + attributes :id, :first_name, :last_name, :city, :state, :country, :location, :photo_url + + node do |user| + { + helpers: { + avatar: asset_path(resolve_avatarables(user)) + } + } + end + } + } + child(:comments => :comments) { attributes :comment, :created_at @@ -80,7 +132,7 @@ glue :recording do child(:claimed_recordings => :claimed_recordings) { - attributes :id, :name, :description, :is_public, :genre_id + attributes :id, :name, :description, :is_public, :genre_id, :has_mix? child(:user => :creator) { attributes :id, :first_name, :last_name, :photo_url diff --git a/web/app/views/clients/_feed.html.haml b/web/app/views/clients/_feed.html.haml index 002770ef3..c48c1b17d 100644 --- a/web/app/views/clients/_feed.html.haml +++ b/web/app/views/clients/_feed.html.haml @@ -1,4 +1,4 @@ -%div{ layout: 'screen', :'layout-id' => 'feed', :class => 'screen secondary'} +%div{ layout: 'screen', :'layout-id' => 'feed', id: 'feedScreen', :class => 'screen secondary'} .content .content-head .content-icon= image_tag("content/icon_feed.png", {:height => 19, :width => 19}) @@ -9,5 +9,7 @@ = render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_FEED}) .filter-body .content-body-scroller - %p This feature not yet implemented - .content-wrapper + .profile-wrapper + .feed-content + %a{href: "/api/feeds?page=1", class: "btn-next-pager"}= 'Next' + %div{id: 'end-of-feeds-list', class: 'end-of-list'}= 'No more feed entries' diff --git a/web/app/views/clients/_findSession.html.erb b/web/app/views/clients/_findSession.html.erb index c3d48139c..42cabf7d6 100644 --- a/web/app/views/clients/_findSession.html.erb +++ b/web/app/views/clients/_findSession.html.erb @@ -53,7 +53,7 @@ There are currently no public sessions. -
+
No more sessions.
diff --git a/web/app/views/clients/_web_filter.html.erb b/web/app/views/clients/_web_filter.html.erb index 9b0345848..5c8d362e7 100644 --- a/web/app/views/clients/_web_filter.html.erb +++ b/web/app/views/clients/_web_filter.html.erb @@ -60,5 +60,11 @@ <% end %> <% end -%> + + <% if :feed == filter_label %> +
+ REFRESH +
+ <% end %> <% end -%> \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 21e359063..db84f9608 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -25,6 +25,8 @@ <%= render "bandProfile" %> <%= render "band_setup" %> <%= render "band_setup_photo" %> +<%= render "users/feed_music_session_ajax" %> +<%= render "users/feed_recording_ajax" %> <%= render "feed" %> <%= render "bands" %> <%= render "musicians" %> @@ -268,6 +270,8 @@ var clientUpdate = new JK.ClientUpdate(JK.app) clientUpdate.initialize().check() + JK.TickDuration('.feed-entry.music-session-history-entry .inprogress .tick-duration'); + JK.JamServer.connect(); // singleton here defined in JamServer.js // this ensures that there is always a CurrentSessionModel, even if it's for a non-active session JK.CurrentSessionModel = new JK.SessionModel(JK.app, JK.JamServer, window.jamClient); diff --git a/web/app/views/users/_feed_music_session_ajax.html.haml b/web/app/views/users/_feed_music_session_ajax.html.haml index 590bc829a..bbdbb514c 100644 --- a/web/app/views/users/_feed_music_session_ajax.html.haml +++ b/web/app/views/users/_feed_music_session_ajax.html.haml @@ -1,48 +1,49 @@ -%script {type: 'text/javascript'} - .feed-entry.music-session-history-entry{'data-music-session' => feed_item.id} +%script{type: 'text/template', id: 'template-feed-music-session'} + .feed-entry.music-session-history-entry{'data-music-session' => '{{data.feed_item.id}}' } / avatar .avatar-small.ib - = session_avatar(feed_item) + %img{ src: '{{data.feed_item.helpers.avatar}}' } / type and artist .left.ml20.w15 - .title{hoveraction: 'session', :'session-id' => feed_item.id } SESSION + .title{hoveraction: 'session', :'session-id' => '{{data.feed_item.id}}' } SESSION .artist - = session_artist_name(feed_item) - = timeago(feed_item.created_at, class: 'small created_at') + = '{{data.feed_item.helpers.artist_name}}' + %time.small.created_at.timeago{datetime: '{{data.feed_item.helpers.utc_created_at}}'}= '{{data.feed_item.created_at}}' / name and description .left.ml20.w30 .description.dotdotdot - = session_description(feed_item) + = '{{data.feed_item.helpers.description}}' / timeline and controls .right.w40 / recording play controls - .session-controls{ class: "#{(feed_item.is_over? ? 'ended' : 'inprogress')} #{feed_item.has_mount? ? 'has-mount' : 'no-mount'}", 'data-music-session' => feed_item.id, 'fan-access' => feed_item.fan_access.to_s} + .session-controls{class:'{{data.status_class}} {{data.mount_class}}', :'data-music-session' => '{{data.feed_item.id}}', 'fan-access' => '{{data.feed_item.fan_access}}'} / session status %a.left.play-button{href:'#'} = image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon' - - if feed_item.has_mount? - %audio{preload: 'none'} - %source{src: feed_item.music_session.mount.url, type: feed_item.music_session.mount.resolve_string(:mime_type)} + = "{% if(data.feed_item['has_mount?']) { %}" + %audio{preload: 'none'} + %source{src: '{{data.feed_item.music_session.mount.url}}', type: '{{data.feed_item.music_session.mime_type}}'} + = '{% } %}' %span.session-status - = session_text(feed_item) + = '{{data.feed_item.helpers.status}}' / current playback time - = session_duration(feed_item, class: 'session-duration tick-duration recording-current', 'data-created-at' => feed_item.created_at.to_i) + %time{class: 'session-duration tick-duration recording-current duration', 'data-created-at' => '{{data.feed_item.helpers.duration_secs}}', 'duration' => '{{data.feed_item.helpers.duration}}'} + = '{{data.feed_item.helpers.duration}}' / end recording play controls / genre and social - .left.small - = session_genre(feed_item) + .left.small= '{{data.feed_item.helpers.genre}}' .right.small.feed-details %span.play-count %span.plays - = feed_item.play_count + = '{{data.feed_item.play_count}}' = image_tag 'content/icon_arrow.png', :height => "12", :width => "7" %span.comment-count %span.comments - = feed_item.comment_count + = '{{data.feed_item.comment_count}}' = image_tag 'content/icon_comment.png', :height => "12", :width => "13" %span.like-count %span.likes - = feed_item.like_count + = '{{data.feed_item.comment_count}}' = image_tag 'content/icon_like.png', :height => "12", :width => "12" %a.details{:href => "#"} Details %a.details-arrow.arrow-down-orange{:href => "#"} @@ -51,22 +52,24 @@ / sub-table of musicians %table.musicians{:cellpadding => "0", :cellspacing => "5"} %tbody - - feed_item.unique_user_histories.each do |user| - %tr - %td{:width => "24"} - %a.avatar-tiny{:href => "#"} - = render_avatarable(user) - %td - %a{:href => "#"} - = "#{user.first_name} #{user.last_name}" - %td - .nowrap - - if user.total_instruments - - user.total_instruments.split('|').uniq.each do |instrument_id| - %img.instrument-icon{'instrument-id' =>instrument_id, height:24, width:24} - - else - %img.instrument-icon{'instrument-id' =>'default', height:24, width:24} - + = '{% _.each(data.feed_item.participants, function(user) { %}' + %tr + %td{:width => "24"} + %a.avatar-tiny{:href => "#"} + %img{src: '{{user.helpers.avatar}}'} + %td + %a{:href => "#"} + = '{{user.first_name}} {{user.last_name}}' + %td + .nowrap + = '{% if(user.total_instruments) { %}' + = '{% _.each(_.uniq(user.total_instruments), function(instrument_id) { %}' + %img.instrument-icon{'instrument-id' =>'{{instrument_id}}', height:24, width:24} + = '{% }) %}' + = '{% } else { %}' + %img.instrument-icon{'instrument-id' =>'default', height:24, width:24} + = '{% } %}' + = '{% }) %}' %br{:clear => "all"}/ %br/ \ No newline at end of file diff --git a/web/app/views/users/_feed_recording_ajax.html.haml b/web/app/views/users/_feed_recording_ajax.html.haml new file mode 100644 index 000000000..974734d35 --- /dev/null +++ b/web/app/views/users/_feed_recording_ajax.html.haml @@ -0,0 +1,95 @@ +%script{type: 'text/template', id: 'template-feed-recording'} + .feed-entry.recording-entry{:'data-claimed-recording-id' => '{{data.candidate_claimed_recording.id}}' } + / avatar + .avatar-small.ib + %img{ src: '{{data.feed_item.helpers.avatar}}' } + / type and artist + .left.ml20.w15 + .title{hoveraction: 'recording', :'recording-id' => '{{data.candidate_claimed_recording.id}}' } RECORDING + .artist + = '{{data.feed_item.helpers.artist_name}}' + %time.small.created_at.timeago{datetime: '{{data.feed_item.helpers.utc_created_at}}'} + = '{{data.feed_item.created_at}}' + / name and description + .left.ml20.w30 + .name.dotdotdot + = '{{data.feed_item.helpers.name}}' + .description.dotdotdot + = '{{data.feed_item.helpers.description}}' + / timeline and controls + .right.w40 + / recording play controls + .recording-controls{ class: '{{data.mix_class}}'} + / play button + %a.left.play-button{:href => "#"} + = image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon' + = "{% if(data.feed_item['has_mix?']) { %}" + %audio{preload: 'none'} + %source{src: '{{data.candidate_claimed_recording.mix.mp3_url}}', type:'audio/mpeg'} + %source{src: '{{data.candidate_claimed_recording.mix.ogg_url}}', type:'audio/ogg'} + = "{% } %}" + .recording-status + %span.status-text STILL MIXING + .recording-duration + %time{class: 'tick-duration duration', duration: '{{data.feed_item.duration}}'} + = '{{data.feed_item.duration}}' + / playback position + .recording-position + / start time + .recording-time 0:00 + / playback background & slider + .recording-playback + .recording-slider + = image_tag 'content/slider_playcontrols.png', width:5, height:16 + / end time + .recording-time.recording-duration + %time{class: 'tick-duration duration', duration: '{{data.feed_item.duration}}'} + = '{{data.feed_item.duration}}' + / end playback position + / current playback time + .recording-current + 0:00 + / end recording play controls + / genre and social + .left.small= '{{data.feed_item.helpers.genre}}' + .right.small.feed-details + %span.play-count + %span.plays + = '{{data.feed_item.play_count}}' + = image_tag 'content/icon_arrow.png', :height => "12", :width => "7" + %span.comment-count + %span.comments + = '{{data.feed_item.comment_count}}' + = image_tag 'content/icon_comment.png', :height => "12", :width => "13" + %span.like-count + %span.likes + = '{{data.feed_item.like_count}}' + = image_tag 'content/icon_like.png', :height => "12", :width => "12" + %a.details{:href => "#"} Details + %a.details-arrow.arrow-down-orange{:href => "#"} + %br/ + .musician-detail.hidden + / sub-table of musicians + %table.musicians{:cellpadding => "0", :cellspacing => "5"} + %tbody + = '{% _.each(data.feed_item.grouped_tracks, function(track) { %}' + %tr + %td{:width => "24"} + %a.avatar-tiny{:href => "#"} + %img{src: '{{track.musician.helpers.avatar}}'} + %td + %a{:href => "#"} + = '{{track.musician.first_name}} {{track.musician.last_name}}' + %td + .nowrap + = '{% if(track.instrument_ids) { %}' + = '{% _.each(_.uniq(track.instrument_ids), function(instrument_id) { %}' + %img.instrument-icon{'instrument-id' =>'{{instrument_id}}', height:24, width:24} + = '{% }) %}' + = '{% } else { %}' + %img.instrument-icon{'instrument-id' =>'default', height:24, width:24} + = '{% } %}' + = '{% }) %}' + + %br{:clear => "all"}/ + %br/ diff --git a/web/config/routes.rb b/web/config/routes.rb index a090f7869..64d0dc9f7 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -60,7 +60,7 @@ SampleApp::Application.routes.draw do match '/gmail_contacts', to: 'gmail#gmail_contacts' - match '/events/:slug', to: 'events#show', :via => :get + match '/events/:slug', to: 'events#show', :via => :get, :as => 'event' # temporarily allow for debugging--only allows admini n match '/listen_in', to: 'spikes#listen_in'