diff --git a/dss/pipelinesettings.py b/dss/pipelinesettings.py index 0df31aa..bebd7e2 100644 --- a/dss/pipelinesettings.py +++ b/dss/pipelinesettings.py @@ -12,23 +12,26 @@ PIPELINE_JS = { }, 'backbone': { 'source_filenames': ( - 'js/lib/jquery.js', 'js/lib/underscore.js', 'js/lib/underscore.templatehelpers.js', 'js/lib/backbone.js', + 'js/lib/backbone.syphon.js', 'js/lib/backbone.associations.js', 'js/lib/backbone.marionette.js', ) }, 'lib': { 'source_filenames': ( + 'js/lib/ace/uncompressed/jquery.js', 'js/lib/ace/uncompressed/jquery-ui.js', - 'js/lib/backbone.associations.js', - 'js/lib/backbone.syphon.js', 'js/lib/ace/uncompressed/bootstrap.js', 'js/lib/moment.js', 'js/lib/ajaxfileupload.js', 'js/lib/ace/uncompressed/ace.js', + 'js/lib/ace/uncompressed/ace-elements.js', + 'js/lib/ace/uncompressed/select2.js', + 'js/lib/ace/uncompressed/fuelux/fuelux.wizard.js', + 'js/lib/ace/ace/elements.wizard.js', 'js/lib/typeahead.js', 'js/lib/ace/uncompressed/bootstrap-wysiwyg.js', @@ -40,6 +43,7 @@ PIPELINE_JS = { 'js/lib/sm/soundmanager2.js', + 'js/lib/jasny.fileinput.js', 'js/lib/jquery.fileupload.js', 'js/lib/jquery.fileupload-process.js', 'js/lib/jquery.fileupload-audio.js', @@ -61,4 +65,4 @@ PIPELINE_JS = { ), 'output_filename': 'js/site.js', } -} \ No newline at end of file +} diff --git a/spa/ajax.py b/spa/ajax.py index c97c03e..2cc5e82 100755 --- a/spa/ajax.py +++ b/spa/ajax.py @@ -11,7 +11,7 @@ from django.http import HttpResponse, HttpResponseNotFound from annoying.decorators import render_to from django.shortcuts import render_to_response from django.utils import simplejson -from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views.decorators.http import require_POST from jfu.http import upload_receive, UploadResponse @@ -234,6 +234,7 @@ def upload_avatar_image(request): @require_POST @login_required +@csrf_protect def upload(request): # The assumption here is that jQuery File Upload # has been configured to send files one at a time. @@ -242,16 +243,22 @@ def upload(request): try: uid = request.POST['upload-hash'] in_file = request.FILES['file'] if request.FILES else None - fileName, extension = os.path.splitext(in_file.name) + file_name, extension = os.path.splitext(in_file.name) file_storage = FileSystemStorage(location=os.path.join(settings.CACHE_ROOT, "mixes")) cache_file = file_storage.save("%s%s" % (uid, extension), ContentFile(in_file.read())) + response = '' - create_waveform_task.delay(in_file=os.path.join(file_storage.base_location, cache_file), uid=uid) + try: + create_waveform_task.delay(in_file=os.path.join(file_storage.base_location, cache_file), uid=uid) + except: + logger.debug("Unable to connect to celery") + response = 'Unable to connect to waveform generation task, there may be a delay in getting your mix online' file_dict = { - 'size': in_file.size, - 'uid': uid + 'response': response, + 'size': in_file.size, + 'uid': uid } return UploadResponse(request, file_dict) diff --git a/spa/api/v1/MixResource.py b/spa/api/v1/MixResource.py index dda9158..9c52734 100755 --- a/spa/api/v1/MixResource.py +++ b/spa/api/v1/MixResource.py @@ -53,14 +53,15 @@ class MixResource(BackboneCompatibleResource): (self._meta.resource_name, trailing_slash()), self.wrap_view('get_search'), name="api_get_search"), - url(r"^(?P%s)/(?P[\d]+)/$" % - self._meta.resource_name, self.wrap_view('dispatch_detail'), + url(r"^(?P%s)/(?P[\d]+)%s$" % + (self._meta.resource_name, trailing_slash()), + self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), url(r"^(?P%s)/random/$" % self._meta.resource_name, self.wrap_view('dispatch_random'), name="api_dispatch_random"), - url(r"^(?P%s)/(?P[\w\d-]+)/$" % - self._meta.resource_name, + url(r"^(?P%s)/(?P[\w\d-]+)%s$" % + (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), url(r"^(?P%s)/(?P\w[\w/-]*)/comments%s$" % (self._meta.resource_name, trailing_slash()), diff --git a/spa/api/v1/UserResource.py b/spa/api/v1/UserResource.py index fcb9704..993fcd2 100755 --- a/spa/api/v1/UserResource.py +++ b/spa/api/v1/UserResource.py @@ -78,13 +78,12 @@ class UserResource(BackboneCompatibleResource): ret = super(UserResource, self).obj_update(bundle, skip_errors, **kwargs) - """ - bundle.obj.update_follower(bundle.request.user, - bundle.data['favourited']) - """ + try: + update_geo_info_task.delay(ip_address=bundle.request.META['REMOTE_ADDR'], + profile_id=bundle.request.user.get_profile().id) + except: + pass - update_geo_info_task.delay(ip_address=bundle.request.META['REMOTE_ADDR'], - profile_id=bundle.request.user.get_profile().id) return ret def dehydrate_description(self, bundle): @@ -122,6 +121,7 @@ class UserResource(BackboneCompatibleResource): bundle.data['date_joined'] = bundle.obj.user.date_joined bundle.data['last_login'] = bundle.obj.user.last_login bundle.data['mix_count'] = bundle.obj.mix_count + bundle.data['thumbnail'] = bundle.obj.get_small_profile_image() return bundle diff --git a/spa/models/userprofile.py b/spa/models/userprofile.py index cf0ba02..b0228c3 100755 --- a/spa/models/userprofile.py +++ b/spa/models/userprofile.py @@ -139,10 +139,6 @@ class UserProfile(_BaseModel): except IOError, ex: self.logger.warn("Error getting medium profile image: %s", ex.message) - def get_small_profile_image_2(self): - ret = self.get_small_profile_image() - return ret - def get_small_profile_image(self): try: if self.avatar_type == 'custom': diff --git a/spa/templates.py b/spa/templates.py index 293fc08..e354e4a 100755 --- a/spa/templates.py +++ b/spa/templates.py @@ -46,6 +46,8 @@ def get_javascript(request, template_name): 'CURRENT_USER_ID': request.user.get_profile().id if not request.user.is_anonymous() else -1, 'CURRENT_USER_NAME': request.user.get_profile().get_nice_name() if not request.user.is_anonymous() else -1, 'CURRENT_USER_URL': request.user.get_profile().get_profile_url() if not request.user.is_anonymous() else -1, + 'CURRENT_USER_SLUG': request.user.get_profile().slug if not request.user.is_anonymous() else -1, + 'CURRENT_USER_CANHOMEPAGE': request.user.has_perm('spa.mix_add_homepage') or request.user.user.is_staff() if not request.user.is_anonymous() else False, 'AVATAR_IMAGE': request.user.get_profile().get_small_profile_image() if not request.user.is_anonymous() else "" }) return render_to_response( diff --git a/static/js/app/lib/audioController.coffee b/static/js/app/lib/audioController.coffee index 6267436..d6b1307 100755 --- a/static/js/app/lib/audioController.coffee +++ b/static/js/app/lib/audioController.coffee @@ -47,7 +47,6 @@ error: => utils.showWarning "Ooops", "Error playing mix. If you have a flash blocker, please disable it for this site. Otherwise, do please try again." return - com.podnoms.storage.setItem "now_playing", @id return isPlayingId: (id) -> diff --git a/static/js/app/lib/audioController.js b/static/js/app/lib/audioController.js index b5085c1..b2523b4 100755 --- a/static/js/app/lib/audioController.js +++ b/static/js/app/lib/audioController.js @@ -65,7 +65,6 @@ utils.showWarning("Ooops", "Error playing mix. If you have a flash blocker, please disable it for this site. Otherwise, do please try again."); } }); - com.podnoms.storage.setItem("now_playing", _this.id); }); }; diff --git a/static/js/app/lib/editableView.coffee b/static/js/app/lib/editableView.coffee index 97d28f9..da508d7 100755 --- a/static/js/app/lib/editableView.coffee +++ b/static/js/app/lib/editableView.coffee @@ -164,4 +164,3 @@ define ['app.lib/dssView', 'utils', 'ace-editable', 'typeahead'], deferred.promise() - EditableView \ No newline at end of file diff --git a/static/js/app/lib/editableView.js b/static/js/app/lib/editableView.js index 8cf6c66..7236996 100755 --- a/static/js/app/lib/editableView.js +++ b/static/js/app/lib/editableView.js @@ -6,7 +6,7 @@ define(['app.lib/dssView', 'utils', 'ace-editable', 'typeahead'], function(DssView, utils) { var EditableView; - EditableView = (function(_super) { + return EditableView = (function(_super) { __extends(EditableView, _super); @@ -201,7 +201,6 @@ return EditableView; })(DssView); - return EditableView; }); }).call(this); diff --git a/static/js/dss/app.coffee b/static/js/dss/app.coffee index b8a45fa..1de5ab3 100644 --- a/static/js/dss/app.coffee +++ b/static/js/dss/app.coffee @@ -15,6 +15,7 @@ App.addInitializer -> @headerRegion.show(new App.HeaderApp.Views.Header()) + @sidebarRegion.show(new App.SidebarApp.Views.SidebarView()) App.addInitializer -> $(document).on("click", "a[href]:not([data-bypass])", (evt) -> @@ -60,7 +61,7 @@ @listenTo @vent, "user:follow", (model)-> console.log "App(vent): user:follow" - user = new UserItem({id: com.podnoms.settings.currentUser }) + user = new App.UserApp.Models.UserItem({id: com.podnoms.settings.currentUser }) target = com.podnoms.settings.urlRoot + "user/" + model.get("id") + "/" user.fetch( success: => diff --git a/static/js/dss/apps/activity/models/a_activityItem.coffee b/static/js/dss/apps/activity/models/a_activityItem.coffee new file mode 100644 index 0000000..abe82a9 --- /dev/null +++ b/static/js/dss/apps/activity/models/a_activityItem.coffee @@ -0,0 +1,8 @@ +@Dss.module "ActivityApp.Models", (Models, App, Backbone) -> + class Models.ActivityItem extends Backbone.Model + urlRoot: com.podnoms.settings.urlRoot + "activity/" + + parse: (model) -> + model.human_date = moment(model.date).fromNow() + model + diff --git a/static/js/dss/apps/activity/models/activityCollection.coffee b/static/js/dss/apps/activity/models/activityCollection.coffee new file mode 100644 index 0000000..7f336f8 --- /dev/null +++ b/static/js/dss/apps/activity/models/activityCollection.coffee @@ -0,0 +1,19 @@ +@Dss.module "ActivityApp.Models", (Models, App, Backbone) -> + class Models.ActivityCollection extends Backbone.Collection + model: Models.ActivityItem + url:com.podnoms.settings.urlRoot + "activity/" + + initialize: -> + @listenTo App.vent, "model:activity:new", (url) => + console.log("ActivityCollection: activity:new") + item = new Models.ActivityItem() + item.fetch + url: url, + success: (response) => + console.log("ActivityCollection: item fetched") + console.log(response) + @add response + + comparator: (item)-> + -item.id + diff --git a/static/js/dss/apps/activity/views/activityItemView.coffee b/static/js/dss/apps/activity/views/activityItemView.coffee new file mode 100644 index 0000000..01098da --- /dev/null +++ b/static/js/dss/apps/activity/views/activityItemView.coffee @@ -0,0 +1,8 @@ +@Dss.module "ActivityApp.Views", (Views, App, Backbone, Marionette, $) -> + class Views.ActivityItemView extends Marionette.ItemView + template: "activityitemview" + tagName: "div" + + onRender: (itemView) -> + $(itemView.el).addClass('animated flash') + true diff --git a/static/js/dss/apps/activity/views/activityListView.coffee b/static/js/dss/apps/activity/views/activityListView.coffee new file mode 100644 index 0000000..293a681 --- /dev/null +++ b/static/js/dss/apps/activity/views/activityListView.coffee @@ -0,0 +1,21 @@ +@Dss.module "ActivityApp.Views", (Views, App, Backbone, Marionette) -> + class Views.ActivityListView extends Marionette.CompositeView + template: "activitylistview" + tagName: "div" + className: "widget-box" + itemView: Views.ActivityItemView + itemViewContainer: "#activity-container" + + initialize: -> + @collection = new App.ActivityApp.Models.ActivityCollection + @collection.fetch() + + #kinda primordial (but working) support for sorted collection view + #based on https://github.com/marionettejs/backbone.marionette/wiki/Adding-support-for-sorted-collections + appendHtml: (collectionView, itemView, index) -> + childrenContainer = (if collectionView.itemViewContainer then collectionView.$(collectionView.itemViewContainer) else collectionView.$el) + children = childrenContainer.children() + if children.size() <= index + childrenContainer.append itemView.el + else + childrenContainer.children().eq(index).before itemView.el diff --git a/static/js/dss/apps/header/views/headerView.coffee b/static/js/dss/apps/header/views/headerView.coffee index bfbefc9..d87db22 100644 --- a/static/js/dss/apps/header/views/headerView.coffee +++ b/static/js/dss/apps/header/views/headerView.coffee @@ -25,7 +25,7 @@ onShow: -> @searchRegion.show(new App.SearchApp.Views.SearchView()) if com.podnoms.settings.currentUser != -1 - @notificationsRegion.show(new NotificationsListView()) + @notificationsRegion.show(new App.NotificationApp.Views.NotificationsListView()) showRandom: -> console.log("headerView: showRandom") diff --git a/static/js/dss/apps/mix/views/mixEditView.coffee b/static/js/dss/apps/mix/views/mixEditView.coffee new file mode 100644 index 0000000..5aad1d8 --- /dev/null +++ b/static/js/dss/apps/mix/views/mixEditView.coffee @@ -0,0 +1,185 @@ +@Dss.module "MixApp.Views", (Views, App, Backbone, Marionette, $) -> + class Views.MixEditView extends App.Lib.EditableView + @func = null + + template: "mixeditview" + events: + "click #login": "login" + + ui: + image: "#mix-image" + progress: "#mix-upload-progress" + uploadError: '#mix-upload-error' + + initialize: -> + @guid = utils.generateGuid() + @uploadState = -1 + @detailsEntered = false + @patch = false + Dropzone.autoDiscover = false + + onDomRefresh: -> + $('#mix-upload-wizard', @el).ace_wizard().on("change", (e, info) => + if info.step is 1 and @uploadState is 0 + console.log "MixEditView: No mix uploaded" + @ui.uploadError.text("Please add a mix") + @ui.uploadError.fadeIn() + false + else if @uploadState > 0 + true + else + $('#step1').addClass("alert-danger") + false + ).on("finished", (e) => + console.log("Finished") + @saveChanges() + ) + + onRender: -> + console.log("MixEditView: onRender") + $('.progress', @el).hide() + @sendImage = false + + if not @model.id + $('input[name="upload-hash"]', @el).val(@guid) + else + $('#header-step1', @el).remove() + $('#step1', @el).remove() + + $('#header-step2', @el).addClass("active") + $('#step2', @el).addClass("active") + + $('.progress', @el).hide() + + @patch = true + @uploadState = 2 + + + $("#mix-upload-form", @el).dropzone + addRemoveLinks: true + + dictDefaultMessage: " Drop files to upload \t\t\t\t(or click)
\t\t\t\t" + + maxFilesize: 512 + + sending: (file, xhr, formData) => + $('.progress', @el).show() + xhr.setRequestHeader "X-CSRFToken", utils.getCookie("csrftoken") + @uploadState = 1 + + uploadprogress: (e, progress, bytesSent) => + $('.progress', @el).show() + percentage = Math.round(progress) + @ui.progress.css("width", percentage + "%").parent().attr "data-percent", percentage + "%" + + complete: (file)=> + if file.status != "error" + @uploadState = 2 + @checkRedirect() + + $("#genres", @el).select2 + placeholder: "Start typing and choose from list or create your own." + minimumInputLength: 1 + multiple: true + ajax: # instead of writing the function to execute the request we use Select2's convenient helper + url: "/ajax/lookup/genre/" + dataType: "json" + data: (term, page) -> + q: term + + results: (data, page) -> # parse the results into the format expected by Select2. + # since we are using custom formatting functions we do not need to alter remote JSON data + results: data + formatResult: (genre) -> + genre.description + + formatSelection: (genre) -> + "
" + genre.description + "
" + + initSelection: (element, callback) => + console.log("MixEditView: genres:initSelection") + result = [] + genres = @model.get("genres") + unless genres is `undefined` + genres.each (data) -> + result.push + id: data.get("id") + description: data.get("description") + callback result + + """ + createSearchChoice: (term, data) -> + if $(data).filter(-> + @description.localeCompare(term) is 0 + ).length is 0 + id: term + text: term + """ + $('#mix-image-fileinput', @el).on "change", (evt) => + file = evt.target.files[0] + if file + @sendImage = true + + true + true + + saveChanges: => + console.log("MixEditView: saveChanges") + @model.set Backbone.Syphon.serialize($("#mix-details-form", @el)[0]) + flair = Backbone.Syphon.serialize $("#mix-flair-form", @el)[0], + exclude: ["...", ""] + + @model.set flair + + @model.set "upload-hash", @guid + @model.set "upload-extension", $("#upload-extension", @el).val() + + @model.set("genres", new App.GenresApp.Models.GenreCollection()) + $.each $("#genres", @el).select2("data"), (i, item) => + ### + if @model.get("genres") is undefined + @model.set("genres", new GenreCollection()) + ### + @model.get("genres").add({id: item.id, description: item.text}); + + @model.unset "mix_image" unless @sendImage + @model.unset "comments" + + @_saveChanges + patch: @patch + success: => + if @sendImage + $.ajaxFileUpload + url: "/ajax/upload_mix_image/" + @model.get("id") + "/" + secureuri: false + fileElementId: "input[name='...']" + success: (data, status) => + unless typeof (data.error) is "undefined" + unless data.error is "" + alert data.error + else + alert data.msg + else + $("#mix-upload-wizard", @el).hide() + @detailsEntered = true + @checkRedirect() + + error: (data, status, e) -> + utils.showError e + else + $("#mix-upload-wizard", @el).hide() + @detailsEntered = true + @checkRedirect() + true + error: (model, response) -> + utils.showError "Error", "Something went wrong
Nerd stuff is: " + response + + false + + checkRedirect: -> + if @detailsEntered and @uploadState is 2 + Backbone.history.navigate "/mix/" + @model.get("slug"), + trigger: true + + login: -> + App.vent.trigger('app:login') diff --git a/static/js/dss/apps/mix/views/mixItemView.coffee b/static/js/dss/apps/mix/views/mixItemView.coffee index 86e17ce..5c26969 100644 --- a/static/js/dss/apps/mix/views/mixItemView.coffee +++ b/static/js/dss/apps/mix/views/mixItemView.coffee @@ -47,14 +47,12 @@ #the el has not been added to the DOM at this stage, so we'll check for the bounds #and if zero, rely on the composite view to call into this in it's onDomRefresh - """ if App.audioController.isPlayingId @model.id console.log "Re-wrapping player" App.audioController.setupPlayerEl $(@el) @ui.playButton.toggleClass("play", false).toggleClass("pause", false).toggleClass("resume", false) @mixState = App.audioController.getMixState() @_setupStateUI() - """ #$(@el).on("resize", App.audioController.setupPlayerEl($(@el))); return @@ -101,7 +99,6 @@ mixFavourite: -> console.log("MixItemView: favouriteMix") - app = require('app') App.vent.trigger("mix:favourite", @model) true diff --git a/static/js/dss/apps/notifications/models/a_notificationItem.coffee b/static/js/dss/apps/notifications/models/a_notificationItem.coffee new file mode 100644 index 0000000..d6d0fc4 --- /dev/null +++ b/static/js/dss/apps/notifications/models/a_notificationItem.coffee @@ -0,0 +1,9 @@ +@Dss.module "NotificationApp.Models", (Models, App, Backbone, Marionette, $, _, vent) -> + class Models.NotificationItem extends Backbone.Model + urlRoot: com.podnoms.settings.urlRoot + "activity/" + + parse: (model) -> + model.human_date = moment(model.date).fromNow() + model + + Models.NotificationItem \ No newline at end of file diff --git a/static/js/dss/apps/notifications/models/notificationCollection.coffee b/static/js/dss/apps/notifications/models/notificationCollection.coffee new file mode 100644 index 0000000..714797e --- /dev/null +++ b/static/js/dss/apps/notifications/models/notificationCollection.coffee @@ -0,0 +1,27 @@ +@Dss.module "NotificationApp.Models", (Models, App, Backbone, Marionette, $, _, vent) -> + class Models.NotificationCollection extends Backbone.Collection + page: 0 + model: Models.NotificationItem + limit: 5 + + newCount: -> + return @is_new + + url: -> + com.podnoms.settings.urlRoot + "notification/?limit=" + @limit + "&offset=" + Math.max(@page - 1, 0) * @limit + + initialize: -> + @listenTo App.vent, "model:notification:new", (url) => + console.log("NotificationCollection: notification:new") + item = new NotificationItem() + item.fetch + url: url + success: (response) => + console.log("NotificationCollection: item fetched") + console.log(response) + @add response + + comparator: (item)-> + -item.id + + Models.NotificationCollection \ No newline at end of file diff --git a/static/js/dss/apps/notifications/views/notificationsItemView.coffee b/static/js/dss/apps/notifications/views/notificationsItemView.coffee new file mode 100644 index 0000000..1c28997 --- /dev/null +++ b/static/js/dss/apps/notifications/views/notificationsItemView.coffee @@ -0,0 +1,4 @@ +@Dss.module "NotificationApp.Views", (Views, App, Backbone, Marionette) -> + class Views.NotificationsItemView extends Marionette.CompositeView + template: "notificationsitemview" + tagName: "li" diff --git a/static/js/dss/apps/notifications/views/notificationsListView.coffee b/static/js/dss/apps/notifications/views/notificationsListView.coffee new file mode 100644 index 0000000..17bc8fa --- /dev/null +++ b/static/js/dss/apps/notifications/views/notificationsListView.coffee @@ -0,0 +1,51 @@ +@Dss.module "NotificationApp.Views", (Views, App, Backbone, Marionette) -> + class Views.NotificationsListView extends Marionette.CompositeView + + template: "notificationslistview" + itemView: Views.NotificationsItemView + itemViewContainer: "#notif_list_node" + tagName: "li" + + events: + "click #notifications-dropdown": "showNotifications" + ui: + notificationSurround: "#notification-surround" + notificationCountBadge: "#notification-count-badge" + notificationCount: "#notification-count" + + initialize: => + #quick and dirty check to see if user is logged in + @collection = new App.NotificationApp.Models.NotificationCollection + @collection.fetch( + success: => + @renderBeacon() + @collection.on 'add': (model, collection)=> + @collection.meta.is_new += 1 + @renderBeacon(model) + error: => + $(@ui.notificationSurround).hide() + ) + + renderBeacon: (model) -> + newCount = @collection.meta.is_new + if newCount == 0 + $(@ui.notificationCount).text("Notifications") + $(@ui.notificationCountBadge).hide() + else + $(@ui.notificationCount).text(newCount + " new notifications") + $(@ui.notificationCountBadge).show() + $(@ui.notificationCountBadge).addClass('animate pulse') + $('#notification-icon', @el).addClass('icon-animated-bell') + + $(@ui.notificationCountBadge).text(newCount) + + showNotifications: -> + console.log("NotificationsListView: showNotifications") + $.ajax + url: '/ajax/mark_read/' + type: 'post' + success: => + $(@ui.notificationCountBadge).hide() + @collection.meta.is_new = 0 + + Views.NotificationsListView diff --git a/static/js/dss/apps/nowplaying/views/nowPlayingView.coffee b/static/js/dss/apps/nowplaying/views/nowPlayingView.coffee new file mode 100644 index 0000000..2776bdf --- /dev/null +++ b/static/js/dss/apps/nowplaying/views/nowPlayingView.coffee @@ -0,0 +1,47 @@ +@Dss.module "NowPlayingApp.Views", (Views, App, Backbone, Marionette, $) -> + class Views.NowPlayingView extends Marionette.ItemView + className: "now-playing" + + events: { + "click #now-playing-play": "doPlay", + "click #now-playing-pause": "doPause" + } + + initialize: (options)-> + console.log "NowPlayingView: initialize " + options.source + @source = options.source + if options.source is 'mix' + @template = "nowplaying" + else + @template = _.template(LiveTemplate) + + @listenTo(App.vent, 'mix:play', @mixPlay) + @listenTo(App.vent, 'mix:pause', @mixPause) + $('#now-playing-pause', @el).hide() + true + + onRender: -> + @mixPlay() + true + + mixPause: (model) -> + console.log "NowPlayingView: mixPause" + $('#now-playing-play', @el).show() + $('#now-playing-pause', @el).hide() + true + + mixPlay: (model) -> + console.log "NowPlayingView: mixPlay" + $('#now-playing-play', @el).hide() + $('#now-playing-pause', @el).show() + true + + doPlay: -> + console.log "NowPlayingView: doPlay" + App.vent.trigger('mix:play', @model) + true + + doPause: -> + console.log "NowPlayingView: doPause" + App.vent.trigger('mix:pause', @model) + true diff --git a/static/js/dss/apps/search/views/searchItemView.coffee b/static/js/dss/apps/search/views/searchItemView.coffee new file mode 100644 index 0000000..bdd5528 --- /dev/null +++ b/static/js/dss/apps/search/views/searchItemView.coffee @@ -0,0 +1,4 @@ +@Dss.module "SearchApp.Views", (Views, App, Backbone, Marionette, $, _, vent) -> + class Views.SearchItemView extends Marionette.ItemView + template: "searchresultview" + el: "li" \ No newline at end of file diff --git a/static/js/dss/apps/search/views/searchView.coffee b/static/js/dss/apps/search/views/searchView.coffee index 984ef48..e415e87 100644 --- a/static/js/dss/apps/search/views/searchView.coffee +++ b/static/js/dss/apps/search/views/searchView.coffee @@ -1,13 +1,17 @@ @Dss.module "SearchApp.Views", (Views, App, Backbone, Marionette, $, _, vent) -> - class Views.SearchView extends Marionette.Layout + class Views.SearchView extends Marionette.CompositeView template: "search" + itemView: Views.SearchItemView + itemViewEl: "#search-results" + ui: searchText: '#search-text' events: 'keyup #search-text': 'doSearch' 'blur #search-text': 'closeSearch' + engine: compile: (template) -> compiled = _.template(template) @@ -15,26 +19,33 @@ compiled context closeSearch: () -> - $("#suggestions").fadeOut() + $(@itemViewEl).fadeOut() + + appendHtml: -> + console.log("Appending html") doSearch: () -> inputString = @ui.searchText.val() if inputString.length is 0 - $("#suggestions").fadeOut() + $(@itemViewEl).fadeOut() else - results = new MixCollection() + results = new App.MixApp.Models.MixCollection() results.fetch data: $.param( limit: "4" title__icontains: inputString ) - success: (data) -> - $("#suggestions", @el).find("li:gt(0)").remove() - $("#suggestions").fadeIn() # Hide the suggestions box - results.each (item)-> - html = new SearchItemView() - $("#suggestions", @el).append html.template(item.attributes) + success: (data) => + $(@itemViewEl).find("li:gt(0)").remove() + $(@itemViewEl).fadeIn() + results.each (item)=> + view = new Views.SearchItemView({model: item}) + data = view.serializeData(); + data = view.mixinTemplateHelpers(data); + template = view.getTemplate(); + html = Marionette.Renderer.render(template, data); + $(@itemViewEl).append html return Views.SearchView \ No newline at end of file diff --git a/static/js/dss/apps/sidebar/views/sidebarView.coffee b/static/js/dss/apps/sidebar/views/sidebarView.coffee new file mode 100644 index 0000000..7f6ea39 --- /dev/null +++ b/static/js/dss/apps/sidebar/views/sidebarView.coffee @@ -0,0 +1,52 @@ +@Dss.module "SidebarApp.Views", (Views, App, Backbone, Marionette, $, _, vent) -> + class Views.SidebarView extends Marionette.Layout + template: "sidebarview" + regions: + topRegion: '#sidebar-now-playing' + streamRegion: '#sidebar-stream-content' + + + initialize: -> + this.listenTo(App.vent, 'mix:init', @mixInit) + this.listenTo(App.vent, 'mix:play', @mixPlay) + this.listenTo(App.vent, 'mix:pause', @mixPause) + this.listenTo(App.vent, 'live:started', @liveStarted) + this.listenTo(App.vent, 'live:stopped', @liveStopped) + return + + onRender: -> + return + + onShow: -> + @streamRegion.show(new App.ActivityApp.Views.ActivityListView()) + $(@topRegion.el).hide() + return + + mixInit: (model) -> + $(@topRegion.el).show() + @topRegion.show(new App.NowPlayingApp.Views.NowPlayingView({ + source: 'mix', + model: model + })) + + liveStarted: -> + $(@topRegion.el).show() + $.getJSON "/ajax/live_now_playing/", (data) => + App.vent.trigger('mix:stop') + @topRegion.show(new NowPlayingView({ + source: 'live' + model: new Backbone.Model({ + mix_image: "/static/img/radio.jpg", + item_url: "", + title: data.description, + user_profile_url: "", + user_name: data.title + }) + })) + true + + liveStopped: -> + @topRegion.close() + + Views.SidebarView + diff --git a/static/js/dss/apps/user/views/userItemView.coffee b/static/js/dss/apps/user/views/userItemView.coffee index d6e2c60..667daae 100644 --- a/static/js/dss/apps/user/views/userItemView.coffee +++ b/static/js/dss/apps/user/views/userItemView.coffee @@ -4,8 +4,8 @@ className: "row" events: - "click #follow-button": -> vent.trigger("user:follow", @model) - "click #follow-button-login": -> vent.trigger("app:login", @model) + "click #follow-button": -> App.vent.trigger("user:follow", @model) + "click #follow-button-login": -> App.vent.trigger("app:login", @model) initialize: => @listenTo(@model, 'change:is_following', @render) diff --git a/static/js/dss/apps/user/views/userProfileView.coffee b/static/js/dss/apps/user/views/userProfileView.coffee index c3e7867..74aa741 100644 --- a/static/js/dss/apps/user/views/userProfileView.coffee +++ b/static/js/dss/apps/user/views/userProfileView.coffee @@ -3,8 +3,8 @@ template: "userprofileview" events: - "click #follow-button": -> vent.trigger("user:follow", @model) - "click #follow-button-login": -> vent.trigger("app:login", @model) + "click #follow-button": -> App.vent.trigger("user:follow", @model) + "click #follow-button-login": -> App.vent.trigger("app:login", @model) initialize: => @listenTo(@model, 'change:is_following', @render) diff --git a/static/js/dss/config/renderer.coffee b/static/js/dss/config/renderer.coffee index 2f1ad89..0d61a7a 100644 --- a/static/js/dss/config/renderer.coffee +++ b/static/js/dss/config/renderer.coffee @@ -14,3 +14,6 @@ _.addTemplateHelpers secondsToHms: (d) -> utils.secondsToHms d + + canHomepage: () -> + return com.podnoms.settings.canHomepage diff --git a/static/js/dss/lib/audioController.coffee b/static/js/dss/lib/audioController.coffee index 0dadcc8..f43035f 100644 --- a/static/js/dss/lib/audioController.coffee +++ b/static/js/dss/lib/audioController.coffee @@ -40,14 +40,13 @@ @setupPlayer el, data.stream_url peneloPlay.startPlaying success: => - vent.trigger("mix:play", model) - vent.trigger("live:stop") + App.vent.trigger("mix:play", model) + App.vent.trigger("live:stop") utils.checkPlayCount() return error: => utils.showWarning "Ooops", "Error playing mix. If you have a flash blocker, please disable it for this site. Otherwise, do please try again." return - com.podnoms.storage.setItem "now_playing", @id return isPlayingId: (id) -> diff --git a/static/js/dss/lib/controller.coffee b/static/js/dss/lib/controller.coffee index e03c986..e5bbfc1 100644 --- a/static/js/dss/lib/controller.coffee +++ b/static/js/dss/lib/controller.coffee @@ -54,7 +54,7 @@ download_allowed: true, is_featured: false }); - App.contentRegion.show(new MixEditView({model: mix})) + App.contentRegion.show(new App.MixApp.Views.MixEditView({model: mix})) true editMix: (slug) -> @@ -62,7 +62,7 @@ mix = new App.MixApp.Models.MixItem({id: slug}) mix.fetch( success: -> - App.contentRegion.show(new MixEditView(model: mix)) + App.contentRegion.show(new App.MixApp.Views.MixEditView(model: mix)) ) true diff --git a/static/js/dss/lib/peneloPlay.coffee b/static/js/dss/lib/peneloPlay.coffee index 09159b7..820b05c 100644 --- a/static/js/dss/lib/peneloPlay.coffee +++ b/static/js/dss/lib/peneloPlay.coffee @@ -8,168 +8,175 @@ ((if h > 0 then h + ":" else "")) + ((if m > 0 then ((if h > 0 and m < 10 then "0" else "")) + m + ":" else "00:")) + ((if s < 10 then "0" else "")) + s else "00:00:00" - @i = {} - @bounds = {} - @_player = undefined - @_src = undefined + ui = {} + bounds = {} + _player = undefined + _src = undefined _mouseDown: (event) -> - @_player.setPosition (Peneloplay._getCalculatedDuration() / 100) * ((event.pageX - @ui.wrapper.offset().left) / @bounds.waveformWidth) * 100 if @_player + _player.setPosition (@_getCalculatedDuration() / 100) * ((event.pageX - ui.wrapper.offset().left) / bounds.waveformWidth) * 100 if _player $(event.currentTarget).mouseup $.proxy(@_mouseDown, this) return _mouseMove: (event) -> - @ui.seekHead.css "left", (event.offsetX + @bounds.waveformLeft) #.fadeIn('fast'); + ui.seekHead.css "left", (event.offsetX + bounds.waveformLeft) #.fadeIn('fast'); return _mouseLeave: -> - @ui.seekHead.hide() - @ui.wrapper.unbind "mousedown" - @ui.wrapper.unbind "mousemove" + ui.seekHead.hide() + ui.wrapper.unbind "mousedown" + ui.wrapper.unbind "mousemove" return _mouseEnter: -> - @ui.wrapper.mousedown $.proxy(@_mouseDown, this) - @ui.wrapper.mousemove $.proxy(@_mouseMove, this) - @ui.seekHead.show() + ui.wrapper.mousedown $.proxy(@_mouseDown, this) + ui.wrapper.mousemove $.proxy(@_mouseMove, this) + ui.seekHead.show() return _hookupMouseEntryEvents: -> - if @ui.wrapper - @ui.wrapper.mouseenter $.proxy(@_mouseEnter, this) - @ui.wrapper.mouseleave $.proxy(@_mouseLeave, this) + if ui.wrapper + ui.wrapper.mouseenter $.proxy(@_mouseEnter, this) + ui.wrapper.mouseleave $.proxy(@_mouseLeave, this) return _teardownMouseEntryEvents: -> - if @ui.wrapper - @ui.wrapper.unbind "mouseenter" - @ui.wrapper.unbind "mouseleave" + if ui.wrapper + ui.wrapper.unbind "mouseenter" + ui.wrapper.unbind "mouseleave" return _getCalculatedDuration: -> - if @_player.instanceOptions.isMovieStar - @_player.duration + if _player.instanceOptions.isMovieStar + _player.duration else - @_player.durationEstimate + _player.durationEstimate stopPlaying: -> - if @_player - @_player.stop() - soundManager.destroySound @_player.sID + if _player + _player.stop() + soundManager.destroySound _player.sID @_teardownMouseEntryEvents() - @_player = `undefined` + _player = `undefined` return setupPlayer: (el, src) -> - @_src = src if src + _src = src if src @_el = el #check all required elements are available - @ui.instance = el.find(".pnp-instance") - @ui.wrapper = el.find(".pnp-wrapper") - @ui.waveform = el.find(".pnp-waveform") - @ui.timeDuration = el.find(".pnp-time-display-label-duration") - @ui.timeElapsed = el.find(".pnp-time-display-label-elapsed") - @ui.downloadOverlay = el.find(".pnp-download-overlay") - @ui.playedOverlay = el.find(".pnp-played-overlay") - @ui.seekHead = el.find(".pnp-seekhead") - @bounds.waveformWidth = @ui.waveform.width() - @bounds.waveformHeight = @ui.waveform.height() - @bounds.waveformLeft = @ui.waveform.position().left - Peneloplay.setupUIWidgets() + ui.instance = el.find(".pnp-instance") + ui.wrapper = el.find(".pnp-wrapper") + ui.waveform = el.find(".pnp-waveform") + ui.timeDuration = el.find(".pnp-time-display-label-duration") + ui.timeElapsed = el.find(".pnp-time-display-label-elapsed") + ui.downloadOverlay = el.find(".pnp-download-overlay") + ui.playedOverlay = el.find(".pnp-played-overlay") + ui.seekHead = el.find(".pnp-seekhead") + bounds.waveformWidth = ui.waveform.width() + bounds.waveformHeight = ui.waveform.height() + bounds.waveformLeft = ui.waveform.position().left + @setupUIWidgets() this setupUIWidgets: -> - @ui.seekHead.animate - top: @ui.waveform.position().top - left: @ui.waveform.position().left - height: @ui.waveform.height() + ui.seekHead.animate + top: ui.waveform.position().top + left: ui.waveform.position().left + height: ui.waveform.height() - @ui.timeElapsed.show() - @ui.timeElapsed.animate - top: @ui.waveform.position().top - left: @ui.waveform.position().left + ui.timeElapsed.show() + ui.timeElapsed.animate + top: ui.waveform.position().top + left: ui.waveform.position().left - @ui.timeDuration.show() - @ui.timeDuration.animate - top: @ui.waveform.position().top - left: (@ui.waveform.position().left + @ui.waveform.width()) - @ui.timeDuration.width() + ui.timeDuration.show() + ui.timeDuration.animate + top: ui.waveform.position().top + left: (ui.waveform.position().left + ui.waveform.width()) - ui.timeDuration.width() - @ui.downloadOverlay.animate - top: @ui.waveform.position().top - left: @ui.waveform.position().left - height: @ui.waveform.height() + if soundManager.html5.mp3 + ui.downloadOverlay.hide() + else + ui.downloadOverlay.animate + top: ui.waveform.position().top + left: ui.waveform.position().left + height: ui.waveform.height() - @ui.playedOverlay.show() - @ui.playedOverlay.animate - top: @ui.waveform.position().top - left: @ui.waveform.position().left - height: @ui.waveform.height() - if @_player - if @_player.paused - percentageWidth = (bounds.waveformWidth / 100) * ((@_player.position / Peneloplay._getCalculatedDuration()) * 100) - @ui.playedOverlay.css "width", percentageWidth - Peneloplay._hookupMouseEntryEvents() + ui.playedOverlay.show() + ui.playedOverlay.animate + top: ui.waveform.position().top + left: ui.waveform.position().left + height: ui.waveform.height() + + if _player + if _player.paused + percentageWidth = (bounds.waveformWidth / 100) * ((_player.position / @_getCalculatedDuration()) * 100) + ui.playedOverlay.css "width", percentageWidth + @_hookupMouseEntryEvents() return startPlaying: (args)-> console.log "Starting to play" - Peneloplay.setupUIWidgets() + @setupUIWidgets() #clear any existing sounds - Peneloplay.stopPlaying() - @_player = soundManager.createSound( + @stopPlaying() + _player = soundManager.createSound id: "pnp-current-sound" - url: @_src - whileloading: -> - percentageFinished = (@_player.bytesLoaded / @_player.bytesTotal) * 100 - percentageWidth = (bounds.waveformWidth / 100) * percentageFinished - @ui.downloadOverlay.css "width", percentageWidth + url: _src + + #Might not need the progress overlay if firefucks get their act together + whileloading: => + if not soundManager.html5.mp3 + percentageFinished = (_player.bytesLoaded / _player.bytesTotal) * 100 + percentageWidth = (bounds.waveformWidth / 100) * percentageFinished + ui.downloadOverlay.css "width", percentageWidth return - whileplaying: -> - percentageWidth = (bounds.waveformWidth / 100) * ((@_player.position / Peneloplay._getCalculatedDuration()) * 100) - @ui.playedOverlay.css "width", percentageWidth - @ui.timeElapsed.text _secondsToHms(@_player.position / 1000) + whileplaying: => + percentageWidth = (bounds.waveformWidth / 100) * ((_player.position / @_getCalculatedDuration()) * 100) + ui.playedOverlay.css "width", percentageWidth + ui.timeElapsed.text _secondsToHms(_player.position / 1000) return - ) - @_player.play onplay: -> - args[0].success() + + _player.play onplay: -> + args.success() return - Peneloplay._hookupMouseEntryEvents() + @_hookupMouseEntryEvents() return pause: -> - @_player.pause() if @_player.playState is 1 + _player.pause() if _player.playState is 1 return resume: -> - @_player.resume() if @_player.paused + _player.resume() if _player.paused return getMixState: -> - if not @_player or @_player.playState is 0 + if not _player or _player.playState is 0 return 0 - else return 2 if @_player.paused + else return 2 if _player.paused 1 playLive: (args)-> - Peneloplay.stopPlaying() - @_player = soundManager.createSound( + @stopPlaying() + _player = soundManager.createSound( id: "com.podnoms.player-live" url: com.podnoms.settings.liveStreamRoot volume: 50 stream: true useMovieStar: true ) - @_player.play onplay: -> - args[0].success() + _player.play onplay: -> + args.success() return return stopLive: (args)-> - Peneloplay.stopPlaying() - args[0].success() + @stopPlaying() + args.success() return diff --git a/static/js/dss/lib/social.coffee b/static/js/dss/lib/social.coffee new file mode 100644 index 0000000..86cd302 --- /dev/null +++ b/static/js/dss/lib/social.coffee @@ -0,0 +1,44 @@ +@social = do -> + postFacebookLike: (mixId) -> + + #first off, find if the current user has allowed facebook likes + $.getJSON "social/like/" + mixId + "/", (data) -> + utils.showAlert "Posted your like to facebook, you can stop this in your settings page.", "Cheers feen" + + + generateEmbedCode: (model) -> + console.log("Generating embed code"); + utils.modal "/dlg/embed/" + model.get('slug') + + sharePageToTwitter: (model) -> + + #We get the URL of the link + loc = $(this).attr("href") + + #We get the title of the link + title = $(this).attr("title") + + #We trigger a new window with the Twitter dialog, in the middle of the page + window.open "http://twitter.com/share?url=" + "http://" + window.location.host + "/" + model.get("item_url") + "&text=" + model.get("title"), "twitterwindow", "height=450, width=550, top=" + ($(window).height() / 2 - 225) + ", left=" + $(window).width() / 2 + ", toolbar=0, location=0, menubar=0, directories=0, scrollbars=0" + + sharePageToFacebook: (model) -> + FB.init({ + appId : '154504534677009', + xfbml : true + }); + FB.getLoginStatus (oResponse) -> + if oResponse.status is "connected" + FB.ui + method: "feed" + name: "Check out this mix on Deep South Sounds" + display: "iframe" + link: "http://" + window.location.host + "/" + model.get("item_url") + picture: model.get("mix_image") + caption: model.get("title") + description: model.get("description") + , (response) -> + if response and response.post_id + utils.showAlert "Success", "Post shared to facebook" + else + utils.showError "Error", "Failure sharing post" + diff --git a/static/js/dss/lib/utils.coffee b/static/js/dss/lib/utils.coffee index 7e627f9..b1700a1 100644 --- a/static/js/dss/lib/utils.coffee +++ b/static/js/dss/lib/utils.coffee @@ -1,4 +1,20 @@ @utils = do -> + getCookie: (name) -> + cookieValue = null + if document.cookie and document.cookie isnt "" + cookies = document.cookie.split(";") + i = 0 + + while i < cookies.length + cookie = jQuery.trim(cookies[i]) + + # Does this cookie string begin with the name we want? + if cookie.substring(0, name.length + 1) is (name + "=") + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)) + break + i++ + cookieValue + modal: (url) -> return if $('#modal-header').length if url @@ -109,3 +125,87 @@ isMe: (id) -> id == com.podnoms.settings.currentUser +$(document).ready -> + window.location.hash = "" if window.location.hash is "#_=_" + Backbone.history.navigate "/" if window.location.hash is "upload#" + unless Array::indexOf + console.log "Shimming indexOf for IE8" + Array::indexOf = (searchElement) -> #, fromIndex + "use strict" + throw new TypeError() unless this? + n = undefined + k = undefined + t = Object(this) + len = t.length >>> 0 + return -1 if len is 0 + n = 0 + if arguments_.length > 1 + n = Number(arguments_[1]) + unless n is n # shortcut for verifying if it's NaN + n = 0 + else n = (n > 0 or -1) * Math.floor(Math.abs(n)) if n isnt 0 and n isnt Infinity and n isnt -Infinity + return -1 if n >= len + k = (if n >= 0 then n else Math.max(len - Math.abs(n), 0)) + while k < len + return k if k of t and t[k] is searchElement + k++ + -1 + return + +$(document).ajaxSend (event, xhr, settings) -> + getCookie = (name) -> + cookieValue = null + if document.cookie and document.cookie isnt "" + cookies = document.cookie.split(";") + i = 0 + + while i < cookies.length + cookie = jQuery.trim(cookies[i]) + + # Does this cookie string begin with the name we want? + if cookie.substring(0, name.length + 1) is (name + "=") + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)) + break + i++ + cookieValue + sameOrigin = (url) -> + + # url could be relative or scheme relative or absolute + host = document.location.host # host + port + protocol = document.location.protocol + sr_origin = "//" + host + origin = protocol + sr_origin + + # Allow absolute or scheme relative URLs to same origin + + # or any other URL that isn't scheme relative or absolute i.e relative. + (url is origin or url.slice(0, origin.length + 1) is origin + "/") or (url is sr_origin or url.slice(0, + sr_origin.length + 1) is sr_origin + "/") or not (/^(\/\/|http:|https:).*/.test(url)) + safeMethod = (method) -> + /^(GET|HEAD|OPTIONS|TRACE)$/.test method + xhr.setRequestHeader "X-CSRFToken", getCookie("csrftoken") if typeof (xhr.setRequestHeader) is typeof (Function) if not safeMethod(settings.type) and sameOrigin(settings.url) + return + +$.ajaxSetup + beforeSend: (xhr, settings) -> + + # Only send the token to relative URLs i.e. locally. + xhr.setRequestHeader "X-CSRFToken", utils.getCookie("csrftoken") unless /^http:.*/.test(settings.url) or /^https:.*/.test(settings.url) + return + + statusCode: + 401: -> + vent.trigger "app:login" + window.location.replace "/" + return + + 403: -> + vent.trigger "app:denied" + window.location.replace "/" + return + +unless com.podnoms.settings.isDebug + + #console.log("Looking under the hood? Check us out on github https://github.com/fergalmoran/dss"); + console = {} + console.log = (message) -> \ No newline at end of file diff --git a/static/js/dss/templates/activityitemview.jst b/static/js/dss/templates/activityitemview.jst new file mode 100644 index 0000000..9330ca5 --- /dev/null +++ b/static/js/dss/templates/activityitemview.jst @@ -0,0 +1,25 @@ +
+
+ avatar image +
+ +
+
+ + <%= human_date %> +
+ + +
+ <%= verb %> <%= item_name %> +
+ +
+ + + +
+
+
diff --git a/static/js/dss/templates/activitylistview.jst b/static/js/dss/templates/activitylistview.jst new file mode 100644 index 0000000..55d6a74 --- /dev/null +++ b/static/js/dss/templates/activitylistview.jst @@ -0,0 +1,11 @@ +
+

+ + Activity +

+
+
+
+ +
+
diff --git a/static/js/dss/templates/commentitemview.jst b/static/js/dss/templates/commentitemview.jst index 8dc59eb..ce31417 100644 --- a/static/js/dss/templates/commentitemview.jst +++ b/static/js/dss/templates/commentitemview.jst @@ -10,7 +10,7 @@
<%= comment %>
diff --git a/static/js/dss/templates/header.jst b/static/js/dss/templates/header.jst index 8af5a12..7edd224 100644 --- a/static/js/dss/templates/header.jst +++ b/static/js/dss/templates/header.jst @@ -43,14 +43,12 @@ <% if (com.podnoms.settings.currentUser != -1) { %>
  • - {% thumbnail user|avatar_image "36x36" crop="center" as im %} - AAProfileImg - {% endthumbnail %} + AAProfileImg @@ -62,7 +60,7 @@
  • - + Profile diff --git a/static/js/dss/templates/mixeditview.jst b/static/js/dss/templates/mixeditview.jst new file mode 100644 index 0000000..63aec6c --- /dev/null +++ b/static/js/dss/templates/mixeditview.jst @@ -0,0 +1,149 @@ +
    +
    +

    New Mix Wizard

    + +
    + +
    +
    +
    +
    +
    +
      +
    • + 1 + Mix +
    • +
    • + 2 + Details +
    • +
    • + 3 + Flair +
    • +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + + +
    + Your browser is too old for uploading file
    + Please come back with Chrome or Firefox +
    +
    +
    + +
    +
    + + + +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    + + +
    + +
    +
    +
    +
    +
    Mix Image (click to change)
    + +
    +
    + +
    +
    + + Select image + Change + + + Remove +
    +
    +
    + +
    +
    + + <% if (canHomepage()) { %> + + <% } %> +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    +
    +
    \ No newline at end of file diff --git a/static/js/dss/templates/mixitemview.jst b/static/js/dss/templates/mixitemview.jst index bdc77e3..8c137bd 100644 --- a/static/js/dss/templates/mixitemview.jst +++ b/static/js/dss/templates/mixitemview.jst @@ -89,19 +89,13 @@ - Like - <% if (liked) { %> - d - <% } %> + Like<%if (liked) {%>d<% } %> <% } %> diff --git a/static/js/dss/templates/notificationsitemview.jst b/static/js/dss/templates/notificationsitemview.jst new file mode 100644 index 0000000..39065fe --- /dev/null +++ b/static/js/dss/templates/notificationsitemview.jst @@ -0,0 +1,13 @@ + + Avatar Image + + + <%= user_name %> + <%= verb %> <%= target %> + + + + <%= humanise(date) %> + + + diff --git a/static/js/dss/templates/notificationslistview.jst b/static/js/dss/templates/notificationslistview.jst new file mode 100644 index 0000000..48a2d59 --- /dev/null +++ b/static/js/dss/templates/notificationslistview.jst @@ -0,0 +1,11 @@ + + + + + + diff --git a/static/js/dss/templates/nowplaying.jst b/static/js/dss/templates/nowplaying.jst new file mode 100644 index 0000000..862dffd --- /dev/null +++ b/static/js/dss/templates/nowplaying.jst @@ -0,0 +1,30 @@ +
    +
    + + Now Playing +
    +
    + +
    + +
    diff --git a/static/js/dss/templates/search.jst b/static/js/dss/templates/search.jst index df5585c..64bbd11 100644 --- a/static/js/dss/templates/search.jst +++ b/static/js/dss/templates/search.jst @@ -6,7 +6,7 @@ -