Fixed comments (kinda)

This commit is contained in:
Fergal Moran
2013-12-16 22:31:35 +00:00
parent 234c36be5c
commit cbb88e0b3a
59 changed files with 18643 additions and 12768 deletions

View File

@@ -52,7 +52,7 @@ CACHE_ROOT = localsettings.CACHE_ROOT
STATIC_URL = localsettings.STATIC_URL if hasattr(localsettings, 'STATIC_URL') else '/static/'
if DEBUG:
MEDIA_URL = '/media/'
MEDIA_URL = localsettings.MEDIA_URL if hasattr(localsettings, 'MEDIA_URL') else '/media/'
else:
MEDIA_URL = localsettings.MEDIA_URL if hasattr(localsettings, 'MEDIA_URL') else '/static/'
@@ -222,7 +222,9 @@ PIPELINE_CSS = {
INTERNAL_IPS = ('127.0.0.1', '86.44.166.21', '192.168.1.111')
GOOGLE_ANALYTICS_CODE = localsettings.GOOGLE_ANALYTICS_CODE
TASTYPIE_DATETIME_FORMATTING = 'rfc-2822'
TASTYPIE_ALLOW_MISSING_SLASH = True
SENDFILE_BACKEND = localsettings.SENDFILE_BACKEND
SENDFILE_ROOT = os.path.join(MEDIA_ROOT, 'mixes')

View File

@@ -2,9 +2,9 @@ from tastypie import fields
from tastypie.authentication import Authentication
from tastypie.authorization import Authorization
from tastypie.exceptions import ImmediateHttpResponse
from tastypie.http import HttpForbidden, HttpBadRequest
from tastypie.http import HttpBadRequest, HttpMethodNotAllowed, HttpUnauthorized, HttpApplicationError, HttpNotImplemented
from spa.api.v1.BackboneCompatibleResource import BackboneCompatibleResource
from spa.models import Mix
from spa.models import Mix, UserProfile
from spa.models.comment import Comment
@@ -21,32 +21,34 @@ class CommentResource(BackboneCompatibleResource):
authentication = Authentication()
always_return_data = True
def dehydrate(self, bundle):
if bundle.obj.user is not None:
bundle.data['avatar_image'] = bundle.obj.user.get_profile().get_avatar_image()
bundle.data['user_url'] = bundle.obj.user.get_profile().get_absolute_url()
bundle.data['user_name'] = bundle.obj.user.get_profile().get_nice_name()
else:
bundle.data['avatar_image'] = UserProfile.get_default_avatar_image()
bundle.data['user_url'] = "/"
bundle.data['user_name'] = "Anonymouse"
return bundle
def obj_create(self, bundle, **kwargs):
bundle.data['user'] = bundle.request.user
del bundle.data['avatar_image']
del bundle.data['user_url']
del bundle.data['user_name']
try:
if 'mix_id' in bundle.data:
mix = Mix.objects.get(pk=bundle.data['mix_id'])
mix = Mix.objects.get_by_id_or_slug(bundle.data['mix_id'])
if mix is not None:
return super(CommentResource, self).obj_create(bundle, user=bundle.request.user, mix=mix)
if bundle.request.user.is_authenticated():
return super(CommentResource, self).obj_create(bundle, user=bundle.request.user or None, mix=mix)
else:
return super(CommentResource, self).obj_create(bundle, mix=mix)
else:
return HttpBadRequest("Unable to find mix for supplied mix_id (candidate fields are slug & id).")
return HttpBadRequest("Missing mix_id field.")
except ImmediateHttpResponse, e:
self.logger.error("Error creating comment (%s)" % e.message)
return HttpUnauthorized("Git tae fuck!")
except Exception, e:
self.logger.error("Error creating comment (%s)" % e.message)
pass
raise ImmediateHttpResponse(
HttpBadRequest("Unable to hydrate comment from supplied data.")
)
def obj_update(self, bundle, skip_errors=False, **kwargs):
del bundle.data['avatar_image']
del bundle.data['user_url']
del bundle.data['user_name']
return super(CommentResource, self).obj_update(bundle, bundle.request)
def dehydrate(self, bundle):
bundle.data['avatar_image'] = bundle.obj.user.get_profile().get_small_profile_image()
bundle.data['user_url'] = bundle.obj.user.get_absolute_url()
bundle.data['user_name'] = bundle.obj.user.get_profile().get_nice_name() or bundle.obj.user.get_profile().display_name
return bundle
return HttpApplicationError("Unable to hydrate comment from supplied data.")

View File

@@ -164,9 +164,6 @@ class MixResource(BackboneCompatibleResource):
return semi_filtered
def hydrate_favourited(self, bundle):
return bundle
def dehydrate_mix_image(self, bundle):
return bundle.obj.get_image_url(size="160x110")

View File

@@ -0,0 +1,233 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Comment.user'
db.alter_column(u'spa_comment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True))
def backwards(self, orm):
# Changing field 'Comment.user'
db.alter_column(u'spa_comment', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(default=-1, to=orm['auth.User']))
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'spa._lookup': {
'Meta': {'object_name': '_Lookup'},
'description': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'spa.activity': {
'Meta': {'object_name': 'Activity'},
'date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['spa.UserProfile']", 'null': 'True', 'blank': 'True'})
},
'spa.activitydownload': {
'Meta': {'object_name': 'ActivityDownload', '_ormbases': ['spa.Activity']},
u'activity_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa.Activity']", 'unique': 'True', 'primary_key': 'True'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_downloads'", 'to': "orm['spa.Mix']"})
},
'spa.activityfavourite': {
'Meta': {'object_name': 'ActivityFavourite', '_ormbases': ['spa.Activity']},
u'activity_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa.Activity']", 'unique': 'True', 'primary_key': 'True'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_favourites'", 'to': "orm['spa.Mix']"})
},
'spa.activityfollow': {
'Meta': {'object_name': 'ActivityFollow', '_ormbases': ['spa.Activity']},
u'activity_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa.Activity']", 'unique': 'True', 'primary_key': 'True'}),
'to_user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_follow'", 'to': "orm['spa.UserProfile']"})
},
'spa.activitylike': {
'Meta': {'object_name': 'ActivityLike', '_ormbases': ['spa.Activity']},
u'activity_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa.Activity']", 'unique': 'True', 'primary_key': 'True'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_likes'", 'to': "orm['spa.Mix']"})
},
'spa.activityplay': {
'Meta': {'object_name': 'ActivityPlay', '_ormbases': ['spa.Activity']},
u'activity_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa.Activity']", 'unique': 'True', 'primary_key': 'True'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_plays'", 'to': "orm['spa.Mix']"})
},
'spa.chatmessage': {
'Meta': {'object_name': 'ChatMessage'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.TextField', [], {}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'chat_messages'", 'null': 'True', 'to': "orm['spa.UserProfile']"})
},
'spa.comment': {
'Meta': {'object_name': 'Comment'},
'comment': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['spa.Mix']"}),
'time_index': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'spa.event': {
'Meta': {'object_name': 'Event'},
'attendees': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'attendees'", 'symmetrical': 'False', 'to': u"orm['auth.User']"}),
'date_created': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2013, 11, 27, 0, 0)'}),
'event_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2013, 11, 27, 0, 0)'}),
'event_description': ('tinymce.models.HTMLField', [], {}),
'event_recurrence': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['spa.Recurrence']"}),
'event_time': ('django.db.models.fields.TimeField', [], {'default': 'datetime.datetime(2013, 11, 27, 0, 0)'}),
'event_title': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
'event_venue': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['spa.Venue']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'spa.genre': {
'Meta': {'object_name': 'Genre'},
'description': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
},
'spa.label': {
'Meta': {'object_name': 'Label'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'spa.mix': {
'Meta': {'object_name': 'Mix'},
'description': ('django.db.models.fields.TextField', [], {}),
'download_allowed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'duration': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'favourites': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'favourites'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['spa.UserProfile']"}),
'genres': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['spa.Genre']", 'symmetrical': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_featured': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'likes': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'likes'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['spa.UserProfile']"}),
'local_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
'mix_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '1024', 'blank': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'uid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '38', 'blank': 'True'}),
'upload_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 11, 27, 0, 0)'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'mixes'", 'to': "orm['spa.UserProfile']"}),
'waveform_generated': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
},
'spa.notification': {
'Meta': {'object_name': 'Notification'},
'accepted_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'from_user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'notifications'", 'null': 'True', 'to': "orm['spa.UserProfile']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'notification_text': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
'notification_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
'target': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
'to_user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'to_notications'", 'to': "orm['spa.UserProfile']"}),
'verb': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'})
},
'spa.purchaselink': {
'Meta': {'object_name': 'PurchaseLink'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'track': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'purchase_link'", 'to': "orm['spa.Tracklist']"}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
},
'spa.recurrence': {
'Meta': {'object_name': 'Recurrence', '_ormbases': ['spa._Lookup']},
u'_lookup_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['spa._Lookup']", 'unique': 'True', 'primary_key': 'True'})
},
'spa.release': {
'Meta': {'object_name': 'Release'},
'embed_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'release_artist': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'release_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2013, 11, 27, 0, 0)'}),
'release_description': ('django.db.models.fields.TextField', [], {}),
'release_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'release_label': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['spa.Label']"}),
'release_title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['spa.UserProfile']"})
},
'spa.releaseaudio': {
'Meta': {'object_name': 'ReleaseAudio'},
'description': ('django.db.models.fields.TextField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'local_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'release': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'release_audio'", 'null': 'True', 'to': "orm['spa.Release']"})
},
'spa.tracklist': {
'Meta': {'object_name': 'Tracklist'},
'artist': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'index': ('django.db.models.fields.SmallIntegerField', [], {}),
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'mix': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tracklist'", 'to': "orm['spa.Mix']"}),
'remixer': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'timeindex': ('django.db.models.fields.TimeField', [], {'null': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'spa.userprofile': {
'Meta': {'object_name': 'UserProfile'},
'activity_sharing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'activity_sharing_networks': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'avatar_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '1024', 'blank': 'True'}),
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'social'", 'max_length': '15'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'country': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}),
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '35', 'blank': 'True'}),
'following': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'followers'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['spa.UserProfile']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_known_session': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'default': 'None', 'max_length': '50', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': u"orm['auth.User']"})
},
'spa.venue': {
'Meta': {'object_name': 'Venue'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
'venue_address': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
'venue_image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}),
'venue_name': ('django.db.models.fields.CharField', [], {'max_length': '250'})
}
}
complete_apps = ['spa']

View File

@@ -37,7 +37,7 @@ class Activity(_BaseModel):
notification.from_user = self.user
notification.to_user = self.get_target_user()
notification.notification_text = "%s %s %s" % (
self.user.get_nice_name() or "Anonymous", self.get_verb_past(), self.get_object_name_for_notification())
self.user.get_nice_name() or "Anonymouse", self.get_verb_past(), self.get_object_name_for_notification())
notification.notification_url = self.get_object_url()
notification.verb = self.get_verb_past()

View File

@@ -8,7 +8,7 @@ class Comment(_BaseModel):
class Meta:
app_label = 'spa'
user = models.ForeignKey(User, editable=False)
user = models.ForeignKey(User, editable=False, null=True, blank=True)
mix = models.ForeignKey(Mix, editable=False, null=True, blank=True, related_name='comments')
comment = models.CharField(max_length=1024)
date_created = models.DateTimeField(auto_now=True)

View File

@@ -2,10 +2,13 @@ import os
import rfc822
from datetime import datetime
import urlparse
from logilab.common.registry import ObjectNotFound
from psycopg2.errorcodes import OBJECT_NOT_IN_PREREQUISITE_STATE
from sorl.thumbnail import get_thumbnail
from django.contrib.sites.models import Site
from django.db import models
from core.utils import url
from core.utils.audio import Mp3FileNotFoundException
from core.utils.audio.mp3 import mp3_length, tag_mp3
from core.utils.url import unique_slugify
from spa.models.activity import ActivityDownload, ActivityPlay
@@ -28,11 +31,23 @@ def mix_image_name(instance, filename):
class MixManager(models.Manager):
pass
def get_by_id_or_slug(self, id_or_slug):
"""
Tries to get a mix using the slug first
If this fails then try getting by id
"""
try:
return super(MixManager, self).get(slug=id_or_slug)
except ObjectNotFound:
return super(MixManager, self).get(slug=id_or_slug)
class Mix(_BaseModel):
class Meta:
app_label = 'spa'
objects = MixManager()
title = models.CharField(max_length=150)
description = models.TextField()
upload_date = models.DateTimeField(default=datetime.now())
@@ -64,7 +79,11 @@ class Mix(_BaseModel):
#Check for the unlikely event that the waveform has been generated
if os.path.isfile(self.get_waveform_path()):
self.waveform_generated = True
try:
self.duration = mp3_length(self.get_absolute_path())
except Mp3FileNotFoundException:
#Not really bothered about this in save as it can be called before we have an mp3
pass
super(Mix, self).save(force_insert, force_update, using, update_fields)
@@ -112,7 +131,6 @@ class Mix(_BaseModel):
def get_waveform_url(self):
if self.waveform_generated and os.path.exists(self.get_waveform_path()):
waveform_root = localsettings.WAVEFORM_URL if hasattr(localsettings,
'WAVEFORM_URL') else "%swaveforms" % settings.MEDIA_URL
ret = "%s/%s.%s" % (waveform_root, self.uid, "png")
@@ -130,7 +148,7 @@ class Mix(_BaseModel):
name, extension = os.path.splitext(self.mix_image.file.name)
return os.path.join(settings.MEDIA_ROOT, 'mix-images', "%s.%s", (self.uid, extension))
def get_image_url(self, size='160x160'):
def get_image_url(self, size='160x160', default=''):
try:
ret = get_thumbnail(self.mix_image, size, crop='center')
return "%s/%s" % (settings.MEDIA_URL, ret.name)

View File

@@ -226,5 +226,5 @@ class UserProfile(_BaseModel):
@classmethod
def get_default_moniker(cls):
return "Anonymous"
return "Anonymouse"

View File

@@ -13,14 +13,14 @@ register = template.Library()
@register.filter
def nice_name(user):
if user == "":
return "Anonymous"
return "Anonymouse"
if user.is_authenticated():
profile = user.get_profile()
if profile is not None:
if profile.display_name <> "":
return profile.display_name
else:
return "Anonymous"
return "Anonymouse"
return user.get_full_name() or user.username

View File

@@ -75,11 +75,6 @@ define ['backbone', 'marionette', 'vent', 'utils',
no: ->
console.log("Controller: mixDeleteNO!!")
@listenTo vent, "mix:comment", (model, comment) ->
console.log "App(vent): mix:favourite"
model.save 'favourited', !model.get('favourited'), patch: true
true
@listenTo vent, "user:follow", (model)->
console.log "App(vent): user:follow"
user = new UserItem({id: com.podnoms.settings.currentUser })

View File

@@ -86,13 +86,6 @@
}
});
});
this.listenTo(vent, "mix:comment", function(model, comment) {
console.log("App(vent): mix:favourite");
model.save('favourited', !model.get('favourited'), {
patch: true
});
return true;
});
this.listenTo(vent, "user:follow", function(model) {
var target, user,
_this = this;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.4.0
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,

View File

@@ -1,6 +1,6 @@
define(['backbone', 'backbone.relational'], function (Backbone) {
define(['backbone', 'backbone-associations'], function (Backbone) {
var TastypieModel = Backbone.RelationalModel.extend({
var TastypieModel = Backbone.AssociatedModel.extend({
base_url: function () {
var temp_url = Backbone.Model.prototype.url.call(this);
return (temp_url.charAt(temp_url.length - 1) == '/' ? temp_url : temp_url + '/');

View File

@@ -1,11 +1,11 @@
define ['app', 'marionette', 'vent', 'utils'
'views/mix/mixListLayout', 'views/mix/mixListView', 'views/mix/mixDetailView'
'views/mix/mixEditView', 'views/user/userProfileView', 'views/user/userListView', 'views/user/userEditView',
'models/mix/mixItem', 'models/mix/mixCollection', 'models/user/userItem'],
'models/mix/mixCollection', 'models/mix/mixItem', 'models/user/userItem'],
(App, Marionette, vent, utils,
MixListLayout, MixListView, MixDetailView,
MixEditView, UserProfileView, UserListView, UserEditView,
MixItem, MixCollection, UserItem)->
MixCollection, MixItem, UserItem)->
class DssController extends Marionette.Controller
initialize: ->

View File

@@ -3,7 +3,7 @@
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app', 'marionette', 'vent', 'utils', 'views/mix/mixListLayout', 'views/mix/mixListView', 'views/mix/mixDetailView', 'views/mix/mixEditView', 'views/user/userProfileView', 'views/user/userListView', 'views/user/userEditView', 'models/mix/mixItem', 'models/mix/mixCollection', 'models/user/userItem'], function(App, Marionette, vent, utils, MixListLayout, MixListView, MixDetailView, MixEditView, UserProfileView, UserListView, UserEditView, MixItem, MixCollection, UserItem) {
define(['app', 'marionette', 'vent', 'utils', 'views/mix/mixListLayout', 'views/mix/mixListView', 'views/mix/mixDetailView', 'views/mix/mixEditView', 'views/user/userProfileView', 'views/user/userListView', 'views/user/userEditView', 'models/mix/mixCollection', 'models/mix/mixItem', 'models/user/userItem'], function(App, Marionette, vent, utils, MixListLayout, MixListView, MixDetailView, MixEditView, UserProfileView, UserListView, UserEditView, MixCollection, MixItem, UserItem) {
var DssController;
DssController = (function(_super) {

View File

@@ -1,18 +1,18 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app.lib/dssView', 'utils', 'ace-editable', 'lib/bootstrap-typeahead'], function(DssView, utils) {
var EditableView, _ref;
var EditableView;
EditableView = (function(_super) {
__extends(EditableView, _super);
function EditableView() {
this.setupImageEditable = __bind(this.setupImageEditable, this); _ref = EditableView.__super__.constructor.apply(this, arguments);
return _ref;
this.setupImageEditable = __bind(this.setupImageEditable, this);
return EditableView.__super__.constructor.apply(this, arguments);
}
EditableView.prototype.events = {
@@ -22,7 +22,6 @@
EditableView.prototype.changeSelect = function(evt) {
var changed, obj, objInst, value;
changed = evt.currentTarget;
if (id) {
value = $(evt.currentTarget).val();
@@ -34,7 +33,6 @@
EditableView.prototype.changed = function(evt) {
var changed, obj, objInst, value;
return;
changed = evt.currentTarget;
if (changed.id) {
@@ -54,7 +52,6 @@
EditableView.prototype._bakeForm = function(el, lookups) {
var labels, mapped, model;
model = this.model;
labels = void 0;
mapped = void 0;
@@ -107,7 +104,6 @@
EditableView.prototype._saveChanges = function() {
var args, error, _results;
args = arguments;
if (!this.model.isValid()) {
if (this.model.errors) {
@@ -128,9 +124,7 @@
};
EditableView.prototype.setupImageEditable = function(options) {
var e,
_this = this;
var _this = this;
$.fn.editable.defaults.mode = 'inline';
try {
if (/msie\s*(8|7|6)/.test(navigator.userAgent.toLowerCase())) {
@@ -170,15 +164,13 @@
});
}
});
} catch (_error) {
e = _error;
} catch (e) {
return console.log(e);
}
};
EditableView.prototype.uploadImage = function(options) {
var $form, deferred, e, fd, file_input, files, iframe_id;
var $form, deferred, fd, file_input, files, iframe_id;
$form = options.el.next().find(".editableform:eq(0)");
file_input = $form.find("input[type=file]:eq(0)");
if (!("FormData" in window)) {
@@ -196,7 +188,6 @@
$form.get(0).submit();
setTimeout((function() {
var iframe;
iframe = document.getElementById(iframe_id);
if (iframe != null) {
iframe.src = "about:blank";
@@ -211,8 +202,7 @@
fd = null;
try {
fd = new FormData($form.get(0));
} catch (_error) {
e = _error;
} catch (e) {
fd = new FormData();
$.each($form.serializeArray(), function(index, item) {
return fd.append(item.name, item.value);
@@ -238,7 +228,6 @@
data: fd,
xhr: function() {
var req;
req = $.ajaxSettings.xhr();
return req;
},

View File

@@ -1,5 +1,6 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
define(['marionette'], function() {
return new Backbone.Wreqr.EventAggregator;
});

View File

@@ -1,14 +1,12 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette'], function(Marionette) {
var PanningRegion, getPrefixedCssProp, _ref;
var PanningRegion, getPrefixedCssProp;
getPrefixedCssProp = function(baseProp) {
var str;
str = Modernizr.prefixed(baseProp);
str = str.replace(/([A-Z])/g, function(str, m1) {
return "-" + m1.toLowerCase();
@@ -16,18 +14,17 @@
return str;
};
PanningRegion = (function(_super) {
__extends(PanningRegion, _super);
function PanningRegion() {
_ref = PanningRegion.__super__.constructor.apply(this, arguments);
return _ref;
return PanningRegion.__super__.constructor.apply(this, arguments);
}
PanningRegion.prototype.el = "#content";
PanningRegion.prototype.initialize = function() {
var transEndEventNames;
transEndEventNames = {
WebkitTransition: "webkitTransitionEnd",
MozTransition: "transitionend",
@@ -43,7 +40,6 @@
PanningRegion.prototype.transitionToView = function(newView, type) {
var self, view;
self = this;
view = this.currentView;
if (!view || view.isClosed) {
@@ -53,7 +49,6 @@
Marionette.triggerMethod.call(this, "willTransition", view);
newView.on("render", function() {
var $background, newViewMatrix, translation, worldBgMatrix, worldContentMatrix;
self.$el.off(self.transEndEventName);
translation = void 0;
if (type === "slide") {

View File

@@ -41,18 +41,36 @@ define ['jquery', 'bootstrap', 'toastr'], ($, bootstrap, toastr) ->
@modal "/dlg/PlayCountLoginAlert"
true
toastOptions: ->
toastr.options =
closeButton: true
debug: false
positionClass: "toast-bottom-left"
onclick: null
showDuration: "300"
hideDuration: "1000"
timeOut: "5000"
extendedTimeOut: "1000"
showEasing: "swing"
hideEasing: "linear"
showMethod: "fadeIn"
hideMethod: "fadeOut"
showError: (title, message) ->
@toastOptions()
toastr.error message, title
showWarning: (title, message) ->
@toastOptions()
toastr.warning message, title
showMessage: (title, message) ->
toastOptions()
toastr.success message, title
showAlert: (title, message) ->
@showMessage title, message
showMessage: (title, message) ->
toastr.success message, title
generateGuid: ->
"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace /[xy]/g, (c) ->
r = Math.random() * 16 | 0

View File

@@ -58,18 +58,37 @@
}
return true;
},
toastOptions: function() {
return toastr.options = {
closeButton: true,
debug: false,
positionClass: "toast-bottom-left",
onclick: null,
showDuration: "300",
hideDuration: "1000",
timeOut: "5000",
extendedTimeOut: "1000",
showEasing: "swing",
hideEasing: "linear",
showMethod: "fadeIn",
hideMethod: "fadeOut"
};
},
showError: function(title, message) {
this.toastOptions();
return toastr.error(message, title);
},
showWarning: function(title, message) {
this.toastOptions();
return toastr.warning(message, title);
},
showMessage: function(title, message) {
toastOptions();
return toastr.success(message, title);
},
showAlert: function(title, message) {
return this.showMessage(title, message);
},
showMessage: function(title, message) {
return toastr.success(message, title);
},
generateGuid: function() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r, v;

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['backbone', 'vent', 'models/activity/activityItem', 'app.lib/backbone.dss.model.collection'], function(Backbone, vent, ActivityItem, DssCollection) {
var ActivityCollection, _ref;
var ActivityCollection;
ActivityCollection = (function(_super) {
__extends(ActivityCollection, _super);
function ActivityCollection() {
_ref = ActivityCollection.__super__.constructor.apply(this, arguments);
return _ref;
return ActivityCollection.__super__.constructor.apply(this, arguments);
}
ActivityCollection.prototype.model = ActivityItem;
@@ -20,10 +19,8 @@
ActivityCollection.prototype.initialize = function() {
var _this = this;
return this.listenTo(vent, "model:activity:new", function(url) {
var item;
console.log("ActivityCollection: activity:new");
item = new ActivityItem();
return item.fetch({

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['backbone', 'moment'], function(Backbone, moment) {
var ActivityItem, _ref;
var ActivityItem;
ActivityItem = (function(_super) {
__extends(ActivityItem, _super);
function ActivityItem() {
_ref = ActivityItem.__super__.constructor.apply(this, arguments);
return _ref;
return ActivityItem.__super__.constructor.apply(this, arguments);
}
ActivityItem.prototype.urlRoot = com.podnoms.settings.urlRoot + "activity/";

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

View File

@@ -1,11 +1,6 @@
define ['app.lib/backbone.dss.model'], \
(DSSModel) ->
class CommentItem extends DSSModel
urlRoot: com.podnoms.settings.urlRoot + "comments/"
defaults:
avatar_image: com.podnoms.settings.avatarImage
user_name: com.podnoms.settings.userName
user_url: com.podnoms.settings.userUrl
date_created: ""
define ['backbone', 'backbone-associations'],
(Backbone) ->
class CommentItem extends Backbone.Model
urlRoot: com.podnoms.settings.urlRoot + "comments"
CommentItem

View File

@@ -1,31 +1,23 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app.lib/backbone.dss.model'], function(DSSModel) {
var CommentItem, _ref;
define(['backbone', 'backbone-associations'], function(Backbone) {
var CommentItem;
CommentItem = (function(_super) {
__extends(CommentItem, _super);
function CommentItem() {
_ref = CommentItem.__super__.constructor.apply(this, arguments);
return _ref;
return CommentItem.__super__.constructor.apply(this, arguments);
}
CommentItem.prototype.urlRoot = com.podnoms.settings.urlRoot + "comments/";
CommentItem.prototype.defaults = {
avatar_image: com.podnoms.settings.avatarImage,
user_name: com.podnoms.settings.userName,
user_url: com.podnoms.settings.userUrl,
date_created: ""
};
CommentItem.prototype.urlRoot = com.podnoms.settings.urlRoot + "comments";
return CommentItem;
})(DSSModel);
})(Backbone.Model);
return CommentItem;
});

View File

@@ -1,16 +1,29 @@
define ['models/comment/commentCollection', 'models/comment/commentItem', 'app.lib/backbone.dss.model'], \
(CommentCollection, CommentItem, DSSModel) ->
class MixItem extends DSSModel
define ['utils', 'vent', 'models/comment/commentCollection', 'models/comment/commentItem', 'app.lib/backbone.dss.model'],
(utils, vent, CommentCollection, CommentItem, DssModel) ->
class MixItem extends DssModel
urlRoot: com.podnoms.settings.urlRoot + "mix/"
"""
relations: [
type: Backbone.HasMany
key: "comments"
relatedModel: CommentItem
collectionType: CommentCollection
reverseRelation:
key: "hasItems"
includeInJSON: "id"
type: Backbone.Many #nature of the relation
key: "comments" #attribute of Model
relatedModel: CommentItem #AssociatedModel for attribute key
]
"""
addComment: (comment, success, error) ->
c = undefined
if comment
c = @get("comments").create(
comment: comment
mix_id: @get("slug")
)
c.save null,
success: ->
success()
error: ->
error()
else
error "Comment cannot be empty"
MixItem

View File

@@ -1,27 +1,55 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['models/comment/commentCollection', 'models/comment/commentItem', 'app.lib/backbone.dss.model'], function(CommentCollection, CommentItem, DSSModel) {
var MixItem, _ref;
define(['utils', 'vent', 'models/comment/commentCollection', 'models/comment/commentItem', 'app.lib/backbone.dss.model'], function(utils, vent, CommentCollection, CommentItem, DssModel) {
var MixItem;
return MixItem = (function(_super) {
MixItem = (function(_super) {
__extends(MixItem, _super);
function MixItem() {
_ref = MixItem.__super__.constructor.apply(this, arguments);
return _ref;
return MixItem.__super__.constructor.apply(this, arguments);
}
MixItem.prototype.urlRoot = com.podnoms.settings.urlRoot + "mix/";
"relations: [\n type: Backbone.HasMany\n key: \"comments\"\n relatedModel: CommentItem\n collectionType: CommentCollection\n reverseRelation:\n key: \"hasItems\"\n includeInJSON: \"id\"\n ]";
MixItem.prototype.relations = [
{
type: Backbone.Many,
key: "comments",
relatedModel: CommentItem
}
];
MixItem.prototype.addComment = function(comment, success, error) {
var c;
c = void 0;
if (comment) {
c = this.get("comments").create({
comment: comment,
mix_id: this.get("slug")
});
return c.save(null, {
success: function() {
return success();
},
error: function() {
return error();
}
});
} else {
return error("Comment cannot be empty");
}
};
MixItem;
return MixItem;
})(DSSModel);
return MixItem;
})(DssModel);
});
}).call(this);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['backbone', 'models/user/userItem', 'app.lib/backbone.dss.model.collection'], function(Backbone, UserItem, DssCollection) {
var UserCollection, _ref;
var UserCollection;
UserCollection = (function(_super) {
__extends(UserCollection, _super);
function UserCollection() {
_ref = UserCollection.__super__.constructor.apply(this, arguments);
return _ref;
return UserCollection.__super__.constructor.apply(this, arguments);
}
UserCollection.prototype.page = 0;

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app.lib/backbone.dss.model'], function(DssModel) {
var UserItem, _ref;
var UserItem;
UserItem = (function(_super) {
__extends(UserItem, _super);
function UserItem() {
_ref = UserItem.__super__.constructor.apply(this, arguments);
return _ref;
return UserItem.__super__.constructor.apply(this, arguments);
}
UserItem.prototype.urlRoot = com.podnoms.settings.urlRoot + "user/";

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'text!/tpl/ActivityListItemView'], function(Marionette, Template) {
var ActivityItemView, _ref;
var ActivityItemView;
return ActivityItemView = (function(_super) {
__extends(ActivityItemView, _super);
function ActivityItemView() {
_ref = ActivityItemView.__super__.constructor.apply(this, arguments);
return _ref;
return ActivityItemView.__super__.constructor.apply(this, arguments);
}
ActivityItemView.prototype.template = _.template(Template);

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'models/activity/activityCollection', 'views/activity/activityItemView', 'text!/tpl/ActivityListView'], function(Marionette, ActivityCollection, ActivityItemView, Template) {
var ActivityListView, _ref;
var ActivityListView;
ActivityListView = (function(_super) {
__extends(ActivityListView, _super);
function ActivityListView() {
_ref = ActivityListView.__super__.constructor.apply(this, arguments);
return _ref;
return ActivityListView.__super__.constructor.apply(this, arguments);
}
ActivityListView.prototype.template = _.template(Template);
@@ -31,7 +30,6 @@
ActivityListView.prototype.appendHtml = function(collectionView, itemView, index) {
var children, childrenContainer;
childrenContainer = (collectionView.itemViewContainer ? collectionView.$(collectionView.itemViewContainer) : collectionView.$el);
children = childrenContainer.children();
if (children.size() <= index) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'text!/tpl/CommentItemView'], function(Marionette, Template) {
var CommentItemView, _ref;
var CommentItemView;
CommentItemView = (function(_super) {
__extends(CommentItemView, _super);
function CommentItemView() {
_ref = CommentItemView.__super__.constructor.apply(this, arguments);
return _ref;
return CommentItemView.__super__.constructor.apply(this, arguments);
}
CommentItemView.prototype.template = _.template(Template);

View File

@@ -1,34 +1,58 @@
define ['marionette',
'utils',
'models/mix/mixItem',
'models/comment/commentItem',
'models/comment/commentCollection',
'views/comment/commentListView',
'views/mix/mixItemView',
'text!/tpl/MixDetailView',
'vent'],
(Marionette,
MixItem,
CommentItem,
MixItemView,
Template,
vent) ->
(Marionette, utils, MixItem, CommentItem, CommentsCollection, CommentsListView, MixItemView, Template, vent) ->
class MixDetailView extends Marionette.Layout
template: _.template(Template)
regions:{
regions:
mix: "#mix"
comments: "#comments"
}
ui:
commentText: '#comment-text'
events:
"click #btn-add-comment": "addComment"
addComment: ->
comment = "123"
initialize: ->
@model.on('nested-change', @modelChanged)
onRender: ->
view = new MixItemView({tagName: "div", className: "mix-listing audio-listing-single", model: @model})
@mix.show(view)
@mix.show view
@renderComments()
renderComments: ->
console.log "MixDetailView: Rendering comments"
comments = new CommentsCollection()
comments.url = @model.get("resource_uri") + "/comments/"
comments.mix_id = @model.id
comments.mix = @model
comments.fetch success: (data) ->
content = new CommentsListView(collection: comments).render()
$("#comments", @el).html content.el
true
true
modelChanged: =>
console.log("MixDetailView: modelChanged")
@render()
addComment: ->
activeTab = $("ul#mix-tab li.active", @el)
comment = @ui.commentText.val()
@model.addComment comment, (=>
@ui.commentText.val ""
utils.showMessage "Comment saved.."
activeTab.tab().show()
), (error) =>
utils.showError "Woops \n" + error
$('#comment-input').addClass('has-error')
$('#comment-text').focus()
MixDetailView

View File

@@ -1,15 +1,17 @@
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'models/mix/mixItem', 'models/comment/commentItem', 'views/mix/mixItemView', 'text!/tpl/MixDetailView', 'vent'], function(Marionette, MixItem, CommentItem, MixItemView, Template, vent) {
define(['marionette', 'utils', 'models/mix/mixItem', 'models/comment/commentItem', 'models/comment/commentCollection', 'views/comment/commentListView', 'views/mix/mixItemView', 'text!/tpl/MixDetailView', 'vent'], function(Marionette, utils, MixItem, CommentItem, CommentsCollection, CommentsListView, MixItemView, Template, vent) {
var MixDetailView;
MixDetailView = (function(_super) {
return MixDetailView = (function(_super) {
__extends(MixDetailView, _super);
function MixDetailView() {
this.modelChanged = __bind(this.modelChanged, this);
return MixDetailView.__super__.constructor.apply(this, arguments);
}
@@ -28,9 +30,8 @@
"click #btn-add-comment": "addComment"
};
MixDetailView.prototype.addComment = function() {
var comment;
return comment = "123";
MixDetailView.prototype.initialize = function() {
return this.model.on('nested-change', this.modelChanged);
};
MixDetailView.prototype.onRender = function() {
@@ -41,13 +42,54 @@
model: this.model
});
this.mix.show(view);
return this.renderComments();
};
MixDetailView.prototype.renderComments = function() {
var comments;
console.log("MixDetailView: Rendering comments");
comments = new CommentsCollection();
comments.url = this.model.get("resource_uri") + "/comments/";
comments.mix_id = this.model.id;
comments.mix = this.model;
comments.fetch({
success: function(data) {
var content;
content = new CommentsListView({
collection: comments
}).render();
$("#comments", this.el).html(content.el);
return true;
}
});
return true;
};
MixDetailView.prototype.modelChanged = function() {
console.log("MixDetailView: modelChanged");
return this.render();
};
MixDetailView.prototype.addComment = function() {
var activeTab, comment,
_this = this;
activeTab = $("ul#mix-tab li.active", this.el);
comment = this.ui.commentText.val();
this.model.addComment(comment, (function() {
_this.ui.commentText.val("");
utils.showMessage("Comment saved..");
return activeTab.tab().show();
}), function(error) {
utils.showError("Woops \n" + error);
$('#comment-input').addClass('has-error');
return $('#comment-text').focus();
});
return MixDetailView;
};
return MixDetailView;
})(Marionette.Layout);
return MixDetailView;
});
}).call(this);

View File

@@ -1,10 +1,6 @@
define ['moment', 'app', 'vent', 'marionette', 'utils',
'models/comment/commentCollection',
'views/comment/commentListView',
'text!/tpl/MixListItemView'],
(moment, App, vent, Marionette, utils,
CommentsCollection,
CommentsListView,
Template) ->
class MixItemView extends Marionette.ItemView
template: _.template(Template)
@@ -31,6 +27,7 @@ define ['moment', 'app', 'vent', 'marionette', 'utils',
initialize: =>
@listenTo(@model, 'change:favourited', @render)
@listenTo(@model, 'change:liked', @render)
@listenTo(@model, 'nested-change', @render)
@listenTo(vent, 'mix:play', @mixPlay)
@listenTo(vent, 'mix:pause', @mixPause)
true
@@ -40,10 +37,7 @@ define ['moment', 'app', 'vent', 'marionette', 'utils',
if @model.get('duration')
$('#player-duration-' + id, this.el).text(@model.secondsToHms('duration'))
@renderGenres()
@renderComments()
return
onShow: ->
@@ -60,17 +54,6 @@ define ['moment', 'app', 'vent', 'marionette', 'utils',
true
true
renderComments: =>
comments = new CommentsCollection()
comments.url = @model.get("resource_uri") + "comments/"
comments.mix_id = @model.id
comments.mix = @model
comments.fetch success: (data) ->
content = new CommentsListView(collection: comments).render()
$("#comments", @el).html content.el
true
true
doStart: =>
console.log("MixItemView: mixStart")
this.ui.playButton

View File

@@ -4,7 +4,7 @@
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['moment', 'app', 'vent', 'marionette', 'utils', 'models/comment/commentCollection', 'views/comment/commentListView', 'text!/tpl/MixListItemView'], function(moment, App, vent, Marionette, utils, CommentsCollection, CommentsListView, Template) {
define(['moment', 'app', 'vent', 'marionette', 'utils', 'text!/tpl/MixListItemView'], function(moment, App, vent, Marionette, utils, Template) {
var MixItemView;
MixItemView = (function(_super) {
@@ -13,8 +13,6 @@
function MixItemView() {
this.doStart = __bind(this.doStart, this);
this.renderComments = __bind(this.renderComments, this);
this.renderGenres = __bind(this.renderGenres, this);
this.onRender = __bind(this.onRender, this);
@@ -49,6 +47,7 @@
MixItemView.prototype.initialize = function() {
this.listenTo(this.model, 'change:favourited', this.render);
this.listenTo(this.model, 'change:liked', this.render);
this.listenTo(this.model, 'nested-change', this.render);
this.listenTo(vent, 'mix:play', this.mixPlay);
this.listenTo(vent, 'mix:pause', this.mixPause);
return true;
@@ -61,7 +60,6 @@
$('#player-duration-' + id, this.el).text(this.model.secondsToHms('duration'));
}
this.renderGenres();
this.renderComments();
};
MixItemView.prototype.onShow = function() {
@@ -82,25 +80,6 @@
return true;
};
MixItemView.prototype.renderComments = function() {
var comments;
comments = new CommentsCollection();
comments.url = this.model.get("resource_uri") + "comments/";
comments.mix_id = this.model.id;
comments.mix = this.model;
comments.fetch({
success: function(data) {
var content;
content = new CommentsListView({
collection: comments
}).render();
$("#comments", this.el).html(content.el);
return true;
}
});
return true;
};
MixItemView.prototype.doStart = function() {
console.log("MixItemView: mixStart");
this.ui.playButton.toggleClass('play-button-small-start', false).toggleClass('play-button-small-resume', false).toggleClass('play-button-small-pause', true);

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'text!/tpl/NotificationsItemView'], function(Marionette, Template) {
var NotificationsItemView, _ref;
var NotificationsItemView;
return NotificationsItemView = (function(_super) {
__extends(NotificationsItemView, _super);
function NotificationsItemView() {
_ref = NotificationsItemView.__super__.constructor.apply(this, arguments);
return _ref;
return NotificationsItemView.__super__.constructor.apply(this, arguments);
}
NotificationsItemView.prototype.template = _.template(Template);

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['underscore', 'backbone', 'marionette', 'vent', 'views/activity/activityListView', 'views/widgets/nowPlayingView', 'text!/tpl/SidebarView'], function(_, Backbone, Marionette, vent, ActivityListView, NowPlayingView, Template) {
var SidebarView, _ref;
var SidebarView;
SidebarView = (function(_super) {
__extends(SidebarView, _super);
function SidebarView() {
_ref = SidebarView.__super__.constructor.apply(this, arguments);
return _ref;
return SidebarView.__super__.constructor.apply(this, arguments);
}
SidebarView.prototype.template = _.template(Template);
@@ -44,7 +43,6 @@
SidebarView.prototype.liveStarted = function() {
var _this = this;
console.log("SidebarView: livePlay");
$.getJSON("ajax/live_now_playing/", function(data) {
$(_this.topRegion.el).show();

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app', 'utils', 'moment', 'marionette', 'vent', 'app.lib/editableView', 'models/user/userItem', 'text!/tpl/UserProfileView', 'ace-editable', 'wysiwyg'], function(App, utils, moment, Marionette, vent, EditableView, UserItem, Template) {
var UserProfileView, _ref;
var UserProfileView;
UserProfileView = (function(_super) {
__extends(UserProfileView, _super);
function UserProfileView() {
_ref = UserProfileView.__super__.constructor.apply(this, arguments);
return _ref;
return UserProfileView.__super__.constructor.apply(this, arguments);
}
UserProfileView.prototype.template = _.template(Template);
@@ -24,7 +23,6 @@
UserProfileView.prototype.onDomRefresh = function() {
var _this = this;
console.log("UserProfileView: initialize");
this.setupImageEditable({
el: $("#avatar", this.el),

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'vent', 'text!/tpl/NowPlayingView'], function(Marionette, vent, Template) {
var NowPlayingView, _ref;
var NowPlayingView;
NowPlayingView = (function(_super) {
__extends(NowPlayingView, _super);
function NowPlayingView() {
_ref = NowPlayingView.__super__.constructor.apply(this, arguments);
return _ref;
return NowPlayingView.__super__.constructor.apply(this, arguments);
}
NowPlayingView.prototype.template = _.template(Template);

View File

@@ -1,17 +1,16 @@
// Generated by CoffeeScript 1.6.2
// Generated by CoffeeScript 1.4.0
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['jquery', 'underscore', 'marionette', 'vent', 'text!/tpl/SearchView', 'text!/tpl/SearchResultView', 'lib/bootstrap-typeahead'], function($, _, Marionette, vent, Template, SearchResultView) {
var SearchView, _ref;
var SearchView;
SearchView = (function(_super) {
__extends(SearchView, _super);
function SearchView() {
_ref = SearchView.__super__.constructor.apply(this, arguments);
return _ref;
return SearchView.__super__.constructor.apply(this, arguments);
}
SearchView.prototype.template = _.template(Template);
@@ -23,7 +22,6 @@
SearchView.prototype.engine = {
compile: function(template) {
var compiled;
compiled = _.template(template);
return {
render: function(context) {
@@ -35,7 +33,6 @@
SearchView.prototype.onShow = function() {
var t;
if (typeof typeahead !== "undefined" && typeahead !== null) {
t = $('#search-text', this.el).typeahead({
name: "search",

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
/**
* Created by fergalm on 11/12/13.
*/

View File

@@ -0,0 +1,574 @@
//
// Backbone-associations.js 0.5.4
//
// (c) 2013 Dhruva Ray, Jaynti Kanani, Persistent Systems Ltd.
// Backbone-associations may be freely distributed under the MIT license.
// For all details and documentation:
// https://github.com/dhruvaray/backbone-associations/
//
// Initial Setup
// --------------
(function () {
"use strict";
// Save a reference to the global object (`window` in the browser, `exports`
// on the server).
var root = this;
// The top-level namespace. All public Backbone classes and modules will be attached to this.
// Exported for the browser and CommonJS.
var _, Backbone, BackboneModel, BackboneCollection, ModelProto,
CollectionProto, defaultEvents, AssociatedModel, pathChecker,
collectionEvents, delimiters, pathSeparator;
if (typeof exports !== 'undefined') {
_ = require('underscore');
Backbone = require('backbone');
if (typeof module !== 'undefined' && module.exports) {
module.exports = Backbone;
}
exports = Backbone;
} else {
_ = root._;
Backbone = root.Backbone;
}
// Create local reference `Model` prototype.
BackboneModel = Backbone.Model;
BackboneCollection = Backbone.Collection;
ModelProto = BackboneModel.prototype;
CollectionProto = BackboneCollection.prototype;
// Built-in Backbone `events`.
defaultEvents = ["change", "add", "remove", "reset", "sort", "destroy"];
collectionEvents = ["reset", "sort"];
Backbone.Associations = {
VERSION: "0.5.4"
};
// Define `getter` and `setter` for `separator`
var getSeparator = function() {
return pathSeparator;
};
// Define `setSeperator`
var setSeparator = function(value) {
if (!_.isString(value) || _.size(value) < 1) {
value = ".";
}
// set private properties
pathSeparator = value;
pathChecker = new RegExp("[\\" + pathSeparator + "\\[\\]]+", "g");
delimiters = new RegExp("[^\\" + pathSeparator + "\\[\\]]+", "g");
};
try {
// Define `SEPERATOR` property to Backbone.Associations
Object.defineProperty(Backbone.Associations, 'SEPARATOR', {
enumerable: true,
get: getSeparator,
set: setSeparator
});
} catch (e) {}
// Backbone.AssociatedModel
// --------------
//Add `Many` and `One` relations to Backbone Object.
Backbone.Associations.Many = Backbone.Many = "Many";
Backbone.Associations.One = Backbone.One = "One";
Backbone.Associations.Self = Backbone.Self = "Self";
// Set default separator
Backbone.Associations.SEPARATOR = ".";
Backbone.Associations.getSeparator = getSeparator;
Backbone.Associations.setSeparator = setSeparator;
setSeparator();
// Define `AssociatedModel` (Extends Backbone.Model).
AssociatedModel = Backbone.AssociatedModel = Backbone.Associations.AssociatedModel = BackboneModel.extend({
// Define relations with Associated Model.
relations:undefined,
// Define `Model` property which can keep track of already fired `events`,
// and prevent redundant event to be triggered in case of cyclic model graphs.
_proxyCalls:undefined,
// Get the value of an attribute.
get:function (attr) {
var obj = ModelProto.get.call(this, attr);
return obj ? obj : this._getAttr.apply(this, arguments);
},
// Set a hash of model attributes on the Backbone Model.
set:function (key, value, options) {
var attributes, result;
// Duplicate backbone's behavior to allow separate key/value parameters,
// instead of a single 'attributes' object.
if (_.isObject(key) || key == null) {
attributes = key;
options = value;
} else {
attributes = {};
attributes[key] = value;
}
result = this._set(attributes, options);
// Trigger events which have been blocked until the entire object graph is updated.
this._processPendingEvents();
return result;
},
// Works with an attribute hash and options + fully qualified paths
_set:function (attributes, options) {
var attr, modelMap, modelId, obj, result = this;
if (!attributes) return this;
for (attr in attributes) {
//Create a map for each unique object whose attributes we want to set
modelMap || (modelMap = {});
if (attr.match(pathChecker)) {
var pathTokens = getPathArray(attr), initials = _.initial(pathTokens),
last = pathTokens[pathTokens.length - 1],
parentModel = this.get(initials);
if (parentModel instanceof AssociatedModel) {
obj = modelMap[parentModel.cid] || (modelMap[parentModel.cid] = {'model':parentModel, 'data':{}});
obj.data[last] = attributes[attr];
}
} else {
obj = modelMap[this.cid] || (modelMap[this.cid] = {'model':this, 'data':{}});
obj.data[attr] = attributes[attr];
}
}
if (modelMap) {
for (modelId in modelMap) {
obj = modelMap[modelId];
this._setAttr.call(obj.model, obj.data, options) || (result = false);
}
} else {
result = this._setAttr.call(this, attributes, options);
}
return result;
},
// Set a hash of model attributes on the object,
// fire Backbone `event` with options.
// It maintains relations between models during the set operation.
// It also bubbles up child events to the parent.
_setAttr:function (attributes, options) {
var attr;
// Extract attributes and options.
options || (options = {});
if (options.unset) for (attr in attributes) attributes[attr] = void 0;
this.parents = this.parents || [];
if (this.relations) {
// Iterate over `this.relations` and `set` model and collection values
// if `relations` are available.
_.each(this.relations, function (relation) {
var relationKey = relation.key,
relatedModel = relation.relatedModel,
collectionType = relation.collectionType,
map = relation.map,
currVal = this.attributes[relationKey],
idKey = currVal && currVal.idAttribute,
val, relationOptions, data, relationValue, newCtx = false;
// Call function if relatedModel is implemented as a function
if (relatedModel && !(relatedModel.prototype instanceof BackboneModel))
relatedModel = _.isFunction(relatedModel) ?
relatedModel.call(this, relation, attributes) :
relatedModel;
// Get class if relation and map is stored as a string.
if (relatedModel && _.isString(relatedModel)) {
relatedModel = (relatedModel === Backbone.Self) ? this.constructor : map2Scope(relatedModel);
}
collectionType && _.isString(collectionType) && (collectionType = map2Scope(collectionType));
map && _.isString(map) && (map = map2Scope(map));
// Merge in `options` specific to this relation.
relationOptions = relation.options ? _.extend({}, relation.options, options) : options;
if ((!relatedModel) && (!collectionType))
throw new Error('specify either a relatedModel or collectionType');
if (attributes[relationKey]) {
// Get value of attribute with relation key in `val`.
val = _.result(attributes, relationKey);
// Map `val` if a transformation function is provided.
val = map ? map.call(this, val, collectionType ? collectionType : relatedModel) : val;
// If `relation.type` is `Backbone.Many`,
// Create `Backbone.Collection` with passed data and perform Backbone `set`.
if (relation.type === Backbone.Many) {
// `collectionType` of defined `relation` should be instance of `Backbone.Collection`.
if (collectionType && !collectionType.prototype instanceof BackboneCollection) {
throw new Error('collectionType must inherit from Backbone.Collection');
}
if (currVal) {
// Setting this flag will prevent events from firing immediately. That way clients
// will not get events until the entire object graph is updated.
currVal._deferEvents = true;
// Use Backbone.Collection's `reset` or smart `set` method
currVal[relationOptions.reset ? 'reset' : 'set'](
val instanceof BackboneCollection ? val.models : val, relationOptions);
data = currVal;
} else {
newCtx = true;
if (val instanceof BackboneCollection) {
data = val;
} else {
data = collectionType ? new collectionType() : this._createCollection(relatedModel);
data[relationOptions.reset ? 'reset' : 'set'](val, relationOptions);
}
}
} else if (relation.type === Backbone.One) {
if (!relatedModel)
throw new Error('specify a relatedModel for Backbone.One type');
if (!(relatedModel.prototype instanceof Backbone.AssociatedModel))
throw new Error('specify an AssociatedModel for Backbone.One type');
data = val instanceof AssociatedModel ? val : new relatedModel(val, relationOptions);
//Is the passed in data for the same key?
if (currVal && data.attributes[idKey] &&
currVal.attributes[idKey] === data.attributes[idKey]) {
// Setting this flag will prevent events from firing immediately. That way clients
// will not get events until the entire object graph is updated.
currVal._deferEvents = true;
// Perform the traditional `set` operation
currVal._set(val instanceof AssociatedModel ? val.attributes : val, relationOptions);
data = currVal;
} else {
newCtx = true;
}
} else {
throw new Error('type attribute must be specified and have the values Backbone.One or Backbone.Many');
}
attributes[relationKey] = data;
relationValue = data;
// Add proxy events to respective parents.
// Only add callback if not defined or new Ctx has been identified.
if (newCtx || (relationValue && !relationValue._proxyCallback)) {
relationValue._proxyCallback = function () {
return this._bubbleEvent.call(this, relationKey, relationValue, arguments);
};
relationValue.on("all", relationValue._proxyCallback, this);
}
}
//Distinguish between the value of undefined versus a set no-op
if (attributes.hasOwnProperty(relationKey)) {
//Maintain reverse pointers - a.k.a parents
var updated = attributes[relationKey];
var original = this.attributes[relationKey];
if (updated) {
updated.parents = updated.parents || [];
(_.indexOf(updated.parents, this) == -1) && updated.parents.push(this);
} else if (original && original.parents.length > 0) { // New value is undefined
original.parents = _.difference(original.parents, [this]);
// Don't bubble to this parent anymore
original._proxyCallback && original.off("all", original._proxyCallback, this);
}
}
}, this);
}
// Return results for `BackboneModel.set`.
return ModelProto.set.call(this, attributes, options);
},
// Bubble-up event to `parent` Model
_bubbleEvent:function (relationKey, relationValue, eventArguments) {
var args = eventArguments,
opt = args[0].split(":"),
eventType = opt[0],
catch_all = args[0] == "nested-change",
eventObject = args[1],
colObject = args[2],
indexEventObject = -1,
_proxyCalls = relationValue._proxyCalls,
cargs,
eventPath,
basecolEventPath,
isDefaultEvent = _.indexOf(defaultEvents, eventType) !== -1;
//Short circuit the listen in to the nested-graph event
if (catch_all) return;
// Change the event name to a fully qualified path.
_.size(opt) > 1 && (eventPath = opt[1]);
if (_.indexOf(collectionEvents, eventType) !== -1) {
colObject = eventObject;
}
// Find the specific object in the collection which has changed.
if (relationValue instanceof BackboneCollection && isDefaultEvent && eventObject) {
var pathTokens = getPathArray(eventPath),
initialTokens = _.initial(pathTokens), colModel;
colModel = relationValue.find(function (model) {
if (eventObject === model) return true;
if (!model) return false;
var changedModel = model.get(initialTokens);
if ((changedModel instanceof AssociatedModel || changedModel instanceof BackboneCollection)
&& eventObject === changedModel)
return true;
changedModel = model.get(pathTokens);
if ((changedModel instanceof AssociatedModel || changedModel instanceof BackboneCollection)
&& eventObject === changedModel)
return true;
if (changedModel instanceof BackboneCollection && colObject
&& colObject === changedModel)
return true;
});
colModel && (indexEventObject = relationValue.indexOf(colModel));
}
// Manipulate `eventPath`.
eventPath = relationKey + ((indexEventObject !== -1 && (eventType === "change" || eventPath)) ?
"[" + indexEventObject + "]" : "") + (eventPath ? pathSeparator + eventPath : "");
// Short circuit collection * events
if (/\[\*\]/g.test(eventPath)) return this;
basecolEventPath = eventPath.replace(/\[\d+\]/g, '[*]');
cargs = [];
cargs.push.apply(cargs, args);
cargs[0] = eventType + ":" + eventPath;
// If event has been already triggered as result of same source `eventPath`,
// no need to re-trigger event to prevent cycle.
_proxyCalls = relationValue._proxyCalls = (_proxyCalls || {});
if (this._isEventAvailable.call(this, _proxyCalls, eventPath)) return this;
// Add `eventPath` in `_proxyCalls` to keep track of already triggered `event`.
_proxyCalls[eventPath] = true;
// Set up previous attributes correctly.
if ("change" === eventType) {
this._previousAttributes[relationKey] = relationValue._previousAttributes;
this.changed[relationKey] = relationValue;
}
// Bubble up event to parent `model` with new changed arguments.
this.trigger.apply(this, cargs);
//Only fire for change. Not change:attribute
if ("change" === eventType && this.get(eventPath) != args[2]) {
var ncargs = ["nested-change", eventPath, args[1]];
args[2] && ncargs.push(args[2]); //args[2] will be options if present
this.trigger.apply(this, ncargs);
}
// Remove `eventPath` from `_proxyCalls`,
// if `eventPath` and `_proxyCalls` are available,
// which allow event to be triggered on for next operation of `set`.
if (_proxyCalls && eventPath) delete _proxyCalls[eventPath];
// Create a collection modified event with wild-card
if (eventPath !== basecolEventPath) {
cargs[0] = eventType + ":" + basecolEventPath;
this.trigger.apply(this, cargs);
}
return this;
},
// Has event been fired from this source. Used to prevent event recursion in cyclic graphs
_isEventAvailable:function (_proxyCalls, path) {
return _.find(_proxyCalls, function (value, eventKey) {
return path.indexOf(eventKey, path.length - eventKey.length) !== -1;
});
},
// Returns New `collection` of type `relation.relatedModel`.
_createCollection:function (type) {
var collection, relatedModel = type;
_.isString(relatedModel) && (relatedModel = map2Scope(relatedModel));
// Creates new `Backbone.Collection` and defines model class.
if (relatedModel && (relatedModel.prototype instanceof AssociatedModel) || _.isFunction(relatedModel)) {
collection = new BackboneCollection();
collection.model = relatedModel;
} else {
throw new Error('type must inherit from Backbone.AssociatedModel');
}
return collection;
},
// Process all pending events after the entire object graph has been updated
_processPendingEvents:function () {
if (!this._processedEvents) {
this._processedEvents = true;
this._deferEvents = false;
// Trigger all pending events
_.each(this._pendingEvents, function (e) {
e.c.trigger.apply(e.c, e.a);
});
this._pendingEvents = [];
// Traverse down the object graph and call process pending events on sub-trees
_.each(this.relations, function (relation) {
var val = this.attributes[relation.key];
val && val._processPendingEvents();
}, this);
delete this._processedEvents;
}
},
// Override trigger to defer events in the object graph.
trigger:function (name) {
// Defer event processing
if (this._deferEvents) {
this._pendingEvents = this._pendingEvents || [];
// Maintain a queue of pending events to trigger after the entire object graph is updated.
this._pendingEvents.push({c:this, a:arguments});
} else {
ModelProto.trigger.apply(this, arguments);
}
},
// The JSON representation of the model.
toJSON:function (options) {
var json = {}, aJson;
json[this.idAttribute] = this.id;
if (!this.visited) {
this.visited = true;
// Get json representation from `BackboneModel.toJSON`.
json = ModelProto.toJSON.apply(this, arguments);
// If `this.relations` is defined, iterate through each `relation`
// and added it's json representation to parents' json representation.
if (this.relations) {
_.each(this.relations, function (relation) {
var attr = this.attributes[relation.key];
if (attr) {
aJson = attr.toJSON ? attr.toJSON(options) : attr;
json[relation.key] = _.isArray(aJson) ? _.compact(aJson) : aJson;
}
}, this);
}
delete this.visited;
}
return json;
},
// Create a new model with identical attributes to this one.
clone:function () {
return new this.constructor(this.toJSON());
},
// Call this if you want to set an `AssociatedModel` to a falsy value like undefined/null directly.
// Not calling this will leak memory and have wrong parents.
// See test case "parent relations"
cleanup:function () {
_.each(this.relations, function (relation) {
var val = this.attributes[relation.key];
val && (val.parents = _.difference(val.parents, [this]));
}, this);
this.off();
},
// Navigate the path to the leaf object in the path to query for the attribute value
_getAttr:function (path) {
var result = this,
//Tokenize the path
attrs = getPathArray(path),
key,
i;
if (_.size(attrs) < 1) return;
for (i = 0; i < attrs.length; i++) {
key = attrs[i];
if (!result) break;
//Navigate the path to get to the result
result = result instanceof BackboneCollection
? (isNaN(key) ? undefined : result.at(key))
: result.attributes[key];
}
return result;
}
});
// Tokenize the fully qualified event path
var getPathArray = function (path) {
if (path === '') return [''];
return _.isString(path) ? (path.match(delimiters)) : path || [];
};
var map2Scope = function (path) {
return _.reduce(path.split(pathSeparator), function (memo, elem) {
return memo[elem];
}, root);
};
//Infer the relation from the collection's parents and find the appropriate map for the passed in `models`
var map2models = function (parents, target, models) {
var relation, surrogate;
//Iterate over collection's parents
_.find(parents, function (parent) {
//Iterate over relations
relation = _.find(parent.relations, function (rel) {
return parent.get(rel.key) === target;
}, this);
if (relation) {
surrogate = parent;//surrogate for transformation
return true;//break;
}
}, this);
//If we found a relation and it has a mapping function
if (relation && relation.map) {
return relation.map.call(surrogate, models, target);
}
return models;
};
var proxies = {};
// Proxy Backbone collection methods
_.each(['set', 'remove', 'reset'], function (method) {
proxies[method] = BackboneCollection.prototype[method];
CollectionProto[method] = function (models, options) {
//Short-circuit if this collection doesn't hold `AssociatedModels`
if (this.model.prototype instanceof AssociatedModel && this.parents) {
//Find a map function if available and perform a transformation
arguments[0] = map2models(this.parents, this, models);
}
return proxies[method].apply(this, arguments);
}
});
// Override trigger to defer events in the object graph.
proxies['trigger'] = CollectionProto['trigger'];
CollectionProto['trigger'] = function (name) {
if (this._deferEvents) {
this._pendingEvents = this._pendingEvents || [];
// Maintain a queue of pending events to trigger after the entire object graph is updated.
this._pendingEvents.push({c:this, a:arguments});
} else {
proxies['trigger'].apply(this, arguments);
}
};
// Attach process pending event functionality on collections as well. Re-use from `AssociatedModel`
CollectionProto._processPendingEvents = AssociatedModel.prototype._processPendingEvents;
}).call(this);

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ requirejs.config({
site: 'app/site',
jquery: 'lib/jquery',
backbone: 'lib/backbone',
'backbone.relational': 'lib/backbone.relational',
'backbone-associations': 'lib/backbone.associations',
'backbone.syphon': 'lib/backbone.syphon',
marionette: 'lib/backbone.marionette',
bootstrap: 'lib/bootstrap',
@@ -59,6 +59,10 @@ requirejs.config({
exports: 'Backbone',
deps: ['jquery', 'underscore']
},
'backbone-associations': {
exports: 'Backbone.AssociatedModel',
deps: ['backbone']
},
bootstrap: {
exports: 'bootstrap',
deps: ['jquery']

View File

@@ -5,7 +5,7 @@
</div>
<div class="row well-sm">
<section id="mix-comment">
<div class="input-group">
<div class="input-group" id="comment-input">
<span class="input-group-btn">
<button class="btn btn-sm btn-default"
id="btn-add-comment"
@@ -14,20 +14,20 @@
Add comment!
</button>
</span>
<input class="form-control input-mask-date" type="text" id="comment-text" name="new-comment">
<input class="form-control" type="text" id="comment-text" name="new-comment">
</div>
</section>
</div>
<div class="row">
<section id="mix-detail-section">
<ul id="mix-tab" class="nav nav-tabs" data-tabs="tabs">
<li class="active">
<li class="active" id="tab-description">
<a data-bypass="true" href="#description" data-toggle="tab">
<i class="orange icon-terminal bigger-120"></i>
Description
</a>
</li>
<li>
<li id="tab-comments">
<a data-bypass="true" href="#comments" data-toggle="tab">
<i class="orange icon-comments bigger-120"></i>
Comments