diff --git a/dss/settings.py b/dss/settings.py index 70682d9..5418cfd 100755 --- a/dss/settings.py +++ b/dss/settings.py @@ -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') diff --git a/spa/api/v1/CommentResource.py b/spa/api/v1/CommentResource.py index 170a7ee..3a70a1e 100755 --- a/spa/api/v1/CommentResource.py +++ b/spa/api/v1/CommentResource.py @@ -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.") diff --git a/spa/api/v1/MixResource.py b/spa/api/v1/MixResource.py index cacc779..2dcb4d7 100755 --- a/spa/api/v1/MixResource.py +++ b/spa/api/v1/MixResource.py @@ -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") diff --git a/spa/migrations/0038_auto__chg_field_comment_user.py b/spa/migrations/0038_auto__chg_field_comment_user.py new file mode 100644 index 0000000..e993a56 --- /dev/null +++ b/spa/migrations/0038_auto__chg_field_comment_user.py @@ -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'] \ No newline at end of file diff --git a/spa/models/activity.py b/spa/models/activity.py index 7ca3d4d..45cacf3 100755 --- a/spa/models/activity.py +++ b/spa/models/activity.py @@ -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() diff --git a/spa/models/comment.py b/spa/models/comment.py index 68a913f..4e9070a 100755 --- a/spa/models/comment.py +++ b/spa/models/comment.py @@ -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) diff --git a/spa/models/mix.py b/spa/models/mix.py index 82b0ae1..66fb3a5 100755 --- a/spa/models/mix.py +++ b/spa/models/mix.py @@ -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 - self.duration = mp3_length(self.get_absolute_path()) + 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) diff --git a/spa/models/userprofile.py b/spa/models/userprofile.py index e0ac220..b78ca9d 100755 --- a/spa/models/userprofile.py +++ b/spa/models/userprofile.py @@ -226,5 +226,5 @@ class UserProfile(_BaseModel): @classmethod def get_default_moniker(cls): - return "Anonymous" + return "Anonymouse" diff --git a/spa/templatetags/spa_extras.py b/spa/templatetags/spa_extras.py index d3e40cd..0ec4ddd 100755 --- a/spa/templatetags/spa_extras.py +++ b/spa/templatetags/spa_extras.py @@ -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 diff --git a/static/js/app/appv2.coffee b/static/js/app/appv2.coffee index ecd376a..aeda8b5 100755 --- a/static/js/app/appv2.coffee +++ b/static/js/app/appv2.coffee @@ -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 }) diff --git a/static/js/app/appv2.js b/static/js/app/appv2.js index cfa9489..98e4a07 100755 --- a/static/js/app/appv2.js +++ b/static/js/app/appv2.js @@ -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; diff --git a/static/js/app/lib/audioController.js b/static/js/app/lib/audioController.js index d838a1e..69cc676 100755 --- a/static/js/app/lib/audioController.js +++ b/static/js/app/lib/audioController.js @@ -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, diff --git a/static/js/app/lib/backbone.dss.model.js b/static/js/app/lib/backbone.dss.model.js index 29f3430..f030607 100755 --- a/static/js/app/lib/backbone.dss.model.js +++ b/static/js/app/lib/backbone.dss.model.js @@ -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 + '/'); diff --git a/static/js/app/lib/controller.coffee b/static/js/app/lib/controller.coffee index c1f8bd0..cccc5f1 100755 --- a/static/js/app/lib/controller.coffee +++ b/static/js/app/lib/controller.coffee @@ -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: -> diff --git a/static/js/app/lib/controller.js b/static/js/app/lib/controller.js index 39791c9..ff3c49d 100755 --- a/static/js/app/lib/controller.js +++ b/static/js/app/lib/controller.js @@ -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) { diff --git a/static/js/app/lib/editableView.js b/static/js/app/lib/editableView.js index d47c1ef..25dbe08 100755 --- a/static/js/app/lib/editableView.js +++ b/static/js/app/lib/editableView.js @@ -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; }, diff --git a/static/js/app/lib/eventAggregator.js b/static/js/app/lib/eventAggregator.js index 6788e5e..c5aba48 100755 --- a/static/js/app/lib/eventAggregator.js +++ b/static/js/app/lib/eventAggregator.js @@ -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; }); diff --git a/static/js/app/lib/panningRegion.js b/static/js/app/lib/panningRegion.js index febb8de..3c073dd 100755 --- a/static/js/app/lib/panningRegion.js +++ b/static/js/app/lib/panningRegion.js @@ -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") { diff --git a/static/js/app/lib/utils.coffee b/static/js/app/lib/utils.coffee index b495b96..e4bea1f 100755 --- a/static/js/app/lib/utils.coffee +++ b/static/js/app/lib/utils.coffee @@ -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 diff --git a/static/js/app/lib/utils.js b/static/js/app/lib/utils.js index ff2aed9..6c10fe8 100755 --- a/static/js/app/lib/utils.js +++ b/static/js/app/lib/utils.js @@ -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; diff --git a/static/js/app/models/activity/activityCollection.js b/static/js/app/models/activity/activityCollection.js index 2ee3d85..58ad5c4 100755 --- a/static/js/app/models/activity/activityCollection.js +++ b/static/js/app/models/activity/activityCollection.js @@ -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({ diff --git a/static/js/app/models/activity/activityItem.js b/static/js/app/models/activity/activityItem.js index a519ff8..ede631b 100755 --- a/static/js/app/models/activity/activityItem.js +++ b/static/js/app/models/activity/activityItem.js @@ -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/"; diff --git a/static/js/app/models/comment/commentCollection.js b/static/js/app/models/comment/commentCollection.js index be62a52..f1862e5 100755 --- a/static/js/app/models/comment/commentCollection.js +++ b/static/js/app/models/comment/commentCollection.js @@ -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; }; diff --git a/static/js/app/models/comment/commentItem.coffee b/static/js/app/models/comment/commentItem.coffee index d904f51..17da06e 100755 --- a/static/js/app/models/comment/commentItem.coffee +++ b/static/js/app/models/comment/commentItem.coffee @@ -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 \ No newline at end of file + CommentItem \ No newline at end of file diff --git a/static/js/app/models/comment/commentItem.js b/static/js/app/models/comment/commentItem.js index 2289df8..9117559 100755 --- a/static/js/app/models/comment/commentItem.js +++ b/static/js/app/models/comment/commentItem.js @@ -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; }); diff --git a/static/js/app/models/mix/mixItem.coffee b/static/js/app/models/mix/mixItem.coffee index 96055dd..93bf13b 100755 --- a/static/js/app/models/mix/mixItem.coffee +++ b/static/js/app/models/mix/mixItem.coffee @@ -1,16 +1,29 @@ -define ['models/comment/commentCollection', 'models/comment/commentItem', 'app.lib/backbone.dss.model'], \ - (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" - ] - """ +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.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 \ No newline at end of file diff --git a/static/js/app/models/mix/mixItem.js b/static/js/app/models/mix/mixItem.js index 4c28ea0..0d658a3 100755 --- a/static/js/app/models/mix/mixItem.js +++ b/static/js/app/models/mix/mixItem.js @@ -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); diff --git a/static/js/app/models/notifications/notificationItem.js b/static/js/app/models/notifications/notificationItem.js index 8f2d28a..4576ed1 100644 --- a/static/js/app/models/notifications/notificationItem.js +++ b/static/js/app/models/notifications/notificationItem.js @@ -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; }; diff --git a/static/js/app/models/user/userCollection.js b/static/js/app/models/user/userCollection.js index c5f7728..b1d43e7 100755 --- a/static/js/app/models/user/userCollection.js +++ b/static/js/app/models/user/userCollection.js @@ -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; diff --git a/static/js/app/models/user/userItem.js b/static/js/app/models/user/userItem.js index 99ebecc..392390d 100755 --- a/static/js/app/models/user/userItem.js +++ b/static/js/app/models/user/userItem.js @@ -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/"; diff --git a/static/js/app/views/activity/activityItemView.js b/static/js/app/views/activity/activityItemView.js index 482626d..2233943 100755 --- a/static/js/app/views/activity/activityItemView.js +++ b/static/js/app/views/activity/activityItemView.js @@ -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); diff --git a/static/js/app/views/activity/activityListView.js b/static/js/app/views/activity/activityListView.js index 2573ed5..aab218a 100755 --- a/static/js/app/views/activity/activityListView.js +++ b/static/js/app/views/activity/activityListView.js @@ -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) { diff --git a/static/js/app/views/chat/chatView.js b/static/js/app/views/chat/chatView.js index 2b8ab9f..08e9e94 100644 --- a/static/js/app/views/chat/chatView.js +++ b/static/js/app/views/chat/chatView.js @@ -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; }; diff --git a/static/js/app/views/comment/commentItemView.js b/static/js/app/views/comment/commentItemView.js index 8b47684..75dda35 100755 --- a/static/js/app/views/comment/commentItemView.js +++ b/static/js/app/views/comment/commentItemView.js @@ -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); diff --git a/static/js/app/views/mix/mixDetailView.coffee b/static/js/app/views/mix/mixDetailView.coffee index 094a461..c2a6a85 100755 --- a/static/js/app/views/mix/mixDetailView.coffee +++ b/static/js/app/views/mix/mixDetailView.coffee @@ -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) -> - class MixDetailView extends Marionette.Layout +(Marionette, utils, MixItem, CommentItem, CommentsCollection, CommentsListView, MixItemView, Template, vent) -> + class MixDetailView extends Marionette.Layout - template: _.template(Template) - regions:{ - mix: "#mix" - comments: "#comments" - } - ui: - commentText: '#comment-text' - events: - "click #btn-add-comment": "addComment" + template: _.template(Template) + regions: + mix: "#mix" + comments: "#comments" + ui: + commentText: '#comment-text' + events: + "click #btn-add-comment": "addComment" + initialize: -> + @model.on('nested-change', @modelChanged) - addComment: -> - comment = "123" + onRender: -> + view = new MixItemView({tagName: "div", className: "mix-listing audio-listing-single", model: @model}) + @mix.show view + @renderComments() - onRender: -> - view = new MixItemView({tagName: "div", className: "mix-listing audio-listing-single", model: @model}) - @mix.show(view) - true + 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 - MixDetailView + 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 diff --git a/static/js/app/views/mix/mixDetailView.js b/static/js/app/views/mix/mixDetailView.js index 3dd1791..95866c0 100644 --- a/static/js/app/views/mix/mixDetailView.js +++ b/static/js/app/views/mix/mixDetailView.js @@ -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); diff --git a/static/js/app/views/mix/mixItemView.coffee b/static/js/app/views/mix/mixItemView.coffee index 02fa0ab..415424f 100755 --- a/static/js/app/views/mix/mixItemView.coffee +++ b/static/js/app/views/mix/mixItemView.coffee @@ -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 diff --git a/static/js/app/views/mix/mixItemView.js b/static/js/app/views/mix/mixItemView.js index 5f472b5..bf4f8aa 100755 --- a/static/js/app/views/mix/mixItemView.js +++ b/static/js/app/views/mix/mixItemView.js @@ -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); diff --git a/static/js/app/views/notifications/notificationsItemView.js b/static/js/app/views/notifications/notificationsItemView.js index 61bef18..8d86740 100644 --- a/static/js/app/views/notifications/notificationsItemView.js +++ b/static/js/app/views/notifications/notificationsItemView.js @@ -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); diff --git a/static/js/app/views/sidebar/sidebarView.js b/static/js/app/views/sidebar/sidebarView.js index 992c56e..b9f6142 100755 --- a/static/js/app/views/sidebar/sidebarView.js +++ b/static/js/app/views/sidebar/sidebarView.js @@ -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(); diff --git a/static/js/app/views/user/userProfileView.js b/static/js/app/views/user/userProfileView.js index 338caa1..c54aac3 100644 --- a/static/js/app/views/user/userProfileView.js +++ b/static/js/app/views/user/userProfileView.js @@ -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), diff --git a/static/js/app/views/widgets/nowPlayingView.js b/static/js/app/views/widgets/nowPlayingView.js index 31b6187..6ae48df 100755 --- a/static/js/app/views/widgets/nowPlayingView.js +++ b/static/js/app/views/widgets/nowPlayingView.js @@ -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); diff --git a/static/js/app/views/widgets/searchView.js b/static/js/app/views/widgets/searchView.js index b799a25..a5d1d21 100644 --- a/static/js/app/views/widgets/searchView.js +++ b/static/js/app/views/widgets/searchView.js @@ -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", diff --git a/static/js/lib/ace-elements.js b/static/js/lib/ace-elements.js index fd86eb0..a81e384 100644 --- a/static/js/lib/ace-elements.js +++ b/static/js/lib/ace-elements.js @@ -1,366 +1,366 @@ if(! ('ace' in window) ) window['ace'] = {} jQuery(function() { - //at some places we try to use 'tap' event instead of 'click' if jquery mobile plugin is available - window['ace'].click_event = $.fn.tap ? "tap" : "click"; + //at some places we try to use 'tap' event instead of 'click' if jquery mobile plugin is available + window['ace'].click_event = $.fn.tap ? "tap" : "click"; }); (function($ , undefined) { - var multiplible = 'multiple' in document.createElement('INPUT'); - var hasFileList = 'FileList' in window;//file list enabled in modern browsers - var hasFileReader = 'FileReader' in window; + var multiplible = 'multiple' in document.createElement('INPUT'); + var hasFileList = 'FileList' in window;//file list enabled in modern browsers + var hasFileReader = 'FileReader' in window; - var Ace_File_Input = function(element , settings) { - var self = this; - this.settings = $.extend({}, $.fn.ace_file_input.defaults, settings); + var Ace_File_Input = function(element , settings) { + var self = this; + this.settings = $.extend({}, $.fn.ace_file_input.defaults, settings); - this.$element = $(element); - this.element = element; - this.disabled = false; - this.can_reset = true; + this.$element = $(element); + this.element = element; + this.disabled = false; + this.can_reset = true; - this.$element.on('change.ace_inner_call', function(e , ace_inner_call){ - if(ace_inner_call === true) return;//this change event is called from above drop event - return handle_on_change.call(self); - }); - - this.$element.wrap('
'); - - this.apply_settings(); - } - Ace_File_Input.error = { - 'FILE_LOAD_FAILED' : 1, - 'IMAGE_LOAD_FAILED' : 2, - 'THUMBNAIL_FAILED' : 3 - }; + this.$element.on('change.ace_inner_call', function(e , ace_inner_call){ + if(ace_inner_call === true) return;//this change event is called from above drop event + return handle_on_change.call(self); + }); + + this.$element.wrap('
'); + + this.apply_settings(); + } + Ace_File_Input.error = { + 'FILE_LOAD_FAILED' : 1, + 'IMAGE_LOAD_FAILED' : 2, + 'THUMBNAIL_FAILED' : 3 + }; - Ace_File_Input.prototype.apply_settings = function() { - var self = this; - var remove_btn = !!this.settings.icon_remove; + Ace_File_Input.prototype.apply_settings = function() { + var self = this; + var remove_btn = !!this.settings.icon_remove; - this.multi = this.$element.attr('multiple') && multiplible; - this.well_style = this.settings.style == 'well'; + this.multi = this.$element.attr('multiple') && multiplible; + this.well_style = this.settings.style == 'well'; - if(this.well_style) this.$element.parent().addClass('ace-file-multiple'); - else this.$element.parent().removeClass('ace-file-multiple'); + if(this.well_style) this.$element.parent().addClass('ace-file-multiple'); + else this.$element.parent().removeClass('ace-file-multiple'); - this.$element.parent().find(':not(input[type=file])').remove();//remove all except our input, good for when changing settings - this.$element.after(''+(remove_btn ? '' : '')); - this.$label = this.$element.next(); + this.$element.parent().find(':not(input[type=file])').remove();//remove all except our input, good for when changing settings + this.$element.after(''+(remove_btn ? '' : '')); + this.$label = this.$element.next(); - this.$label.on('click', function(){//firefox mobile doesn't allow 'tap'! - if(!this.disabled && !self.element.disabled && !self.$element.attr('readonly')) - self.$element.click(); - }) + this.$label.on('click', function(){//firefox mobile doesn't allow 'tap'! + if(!this.disabled && !self.element.disabled && !self.$element.attr('readonly')) + self.$element.click(); + }) - if(remove_btn) this.$label.next('a').on(ace.click_event, function(){ - if(! self.can_reset ) return false; - - var ret = true; - if(self.settings.before_remove) ret = self.settings.before_remove.call(self.element); - if(!ret) return false; - return self.reset_input(); - }); + if(remove_btn) this.$label.next('a').on(ace.click_event, function(){ + if(! self.can_reset ) return false; + + var ret = true; + if(self.settings.before_remove) ret = self.settings.before_remove.call(self.element); + if(!ret) return false; + return self.reset_input(); + }); - if(this.settings.droppable && hasFileList) { - enable_drop_functionality.call(this); - } - } + if(this.settings.droppable && hasFileList) { + enable_drop_functionality.call(this); + } + } - Ace_File_Input.prototype.show_file_list = function($files) { - var files = typeof $files === "undefined" ? this.$element.data('ace_input_files') : $files; - if(!files || files.length == 0) return; + Ace_File_Input.prototype.show_file_list = function($files) { + var files = typeof $files === "undefined" ? this.$element.data('ace_input_files') : $files; + if(!files || files.length == 0) return; - ////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////// - if(this.well_style) { - this.$label.find('.file-name').remove(); - if(!this.settings.btn_change) this.$label.addClass('hide-placeholder'); - } - this.$label.attr('data-title', this.settings.btn_change).addClass('selected'); - - for (var i = 0; i < files.length; i++) { - var filename = typeof files[i] === "string" ? files[i] : $.trim( files[i].name ); - var index = filename.lastIndexOf("\\") + 1; - if(index == 0)index = filename.lastIndexOf("/") + 1; - filename = filename.substr(index); - - var fileIcon = 'icon-file'; - if((/\.(jpe?g|png|gif|svg|bmp|tiff?)$/i).test(filename)) { - fileIcon = 'icon-picture'; - } - else if((/\.(mpe?g|flv|mov|avi|swf|mp4|mkv|webm|wmv|3gp)$/i).test(filename)) fileIcon = 'icon-film'; - else if((/\.(mp3|ogg|wav|wma|amr|aac)$/i).test(filename)) fileIcon = 'icon-music'; + if(this.well_style) { + this.$label.find('.file-name').remove(); + if(!this.settings.btn_change) this.$label.addClass('hide-placeholder'); + } + this.$label.attr('data-title', this.settings.btn_change).addClass('selected'); + + for (var i = 0; i < files.length; i++) { + var filename = typeof files[i] === "string" ? files[i] : $.trim( files[i].name ); + var index = filename.lastIndexOf("\\") + 1; + if(index == 0)index = filename.lastIndexOf("/") + 1; + filename = filename.substr(index); + + var fileIcon = 'icon-file'; + if((/\.(jpe?g|png|gif|svg|bmp|tiff?)$/i).test(filename)) { + fileIcon = 'icon-picture'; + } + else if((/\.(mpe?g|flv|mov|avi|swf|mp4|mkv|webm|wmv|3gp)$/i).test(filename)) fileIcon = 'icon-film'; + else if((/\.(mp3|ogg|wav|wma|amr|aac)$/i).test(filename)) fileIcon = 'icon-music'; - if(!this.well_style) this.$label.find('.file-name').attr({'data-title':filename}).find('[class*="icon-"]').attr('class', fileIcon); - else { - this.$label.append(''); - var type = $.trim(files[i].type); - var can_preview = hasFileReader && this.settings.thumbnail - && - ( (type.length > 0 && type.match('image')) || (type.length == 0 && fileIcon == 'icon-picture') )//the second one is for Android's default browser which gives an empty text for file.type - if(can_preview) { - var self = this; - $.when(preview_image.call(this, files[i])).fail(function(result){ - //called on failure to load preview - if(self.settings.preview_error) self.settings.preview_error.call(self, filename, result.code); - }); - } - } + if(!this.well_style) this.$label.find('.file-name').attr({'data-title':filename}).find('[class*="icon-"]').attr('class', fileIcon); + else { + this.$label.append(''); + var type = $.trim(files[i].type); + var can_preview = hasFileReader && this.settings.thumbnail + && + ( (type.length > 0 && type.match('image')) || (type.length == 0 && fileIcon == 'icon-picture') )//the second one is for Android's default browser which gives an empty text for file.type + if(can_preview) { + var self = this; + $.when(preview_image.call(this, files[i])).fail(function(result){ + //called on failure to load preview + if(self.settings.preview_error) self.settings.preview_error.call(self, filename, result.code); + }); + } + } - } + } - return true; - } + return true; + } - Ace_File_Input.prototype.reset_input = function() { - this.$label.attr({'data-title':this.settings.btn_choose, 'class':'file-label'}) - .find('.file-name:first').attr({'data-title':this.settings.no_file , 'class':'file-name'}) - .find('[class*="icon-"]').attr('class', this.settings.no_icon) - .prev('img').remove(); - if(!this.settings.no_icon) this.$label.find('[class*="icon-"]').remove(); - - this.$label.find('.file-name').not(':first').remove(); - - if(this.$element.data('ace_input_files')) { - this.$element.removeData('ace_input_files'); - this.$element.removeData('ace_input_method'); - } + Ace_File_Input.prototype.reset_input = function() { + this.$label.attr({'data-title':this.settings.btn_choose, 'class':'file-label'}) + .find('.file-name:first').attr({'data-title':this.settings.no_file , 'class':'file-name'}) + .find('[class*="icon-"]').attr('class', this.settings.no_icon) + .prev('img').remove(); + if(!this.settings.no_icon) this.$label.find('[class*="icon-"]').remove(); + + this.$label.find('.file-name').not(':first').remove(); + + if(this.$element.data('ace_input_files')) { + this.$element.removeData('ace_input_files'); + this.$element.removeData('ace_input_method'); + } - this.reset_input_field(); - - return false; - } + this.reset_input_field(); + + return false; + } - Ace_File_Input.prototype.reset_input_field = function() { - //http://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery/13351234#13351234 - this.$element.wrap('
').closest('form').get(0).reset(); - this.$element.unwrap(); - } - - Ace_File_Input.prototype.enable_reset = function(can_reset) { - this.can_reset = can_reset; - } + Ace_File_Input.prototype.reset_input_field = function() { + //http://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery/13351234#13351234 + this.$element.wrap('').closest('form').get(0).reset(); + this.$element.unwrap(); + } + + Ace_File_Input.prototype.enable_reset = function(can_reset) { + this.can_reset = can_reset; + } - Ace_File_Input.prototype.disable = function() { - this.disabled = true; - this.$element.attr('disabled', 'disabled').addClass('disabled'); - } - Ace_File_Input.prototype.enable = function() { - this.disabled = false; - this.$element.removeAttr('disabled').removeClass('disabled'); - } - - Ace_File_Input.prototype.files = function() { - return $(this).data('ace_input_files') || null; - } - Ace_File_Input.prototype.method = function() { - return $(this).data('ace_input_method') || ''; - } - - Ace_File_Input.prototype.update_settings = function(new_settings) { - this.settings = $.extend({}, this.settings, new_settings); - this.apply_settings(); - } + Ace_File_Input.prototype.disable = function() { + this.disabled = true; + this.$element.attr('disabled', 'disabled').addClass('disabled'); + } + Ace_File_Input.prototype.enable = function() { + this.disabled = false; + this.$element.removeAttr('disabled').removeClass('disabled'); + } + + Ace_File_Input.prototype.files = function() { + return $(this).data('ace_input_files') || null; + } + Ace_File_Input.prototype.method = function() { + return $(this).data('ace_input_method') || ''; + } + + Ace_File_Input.prototype.update_settings = function(new_settings) { + this.settings = $.extend({}, this.settings, new_settings); + this.apply_settings(); + } - var enable_drop_functionality = function() { - var self = this; - var dropbox = this.element.parentNode; - $(dropbox).on('dragenter', function(e){ - e.preventDefault(); - e.stopPropagation(); - }).on('dragover', function(e){ - e.preventDefault(); - e.stopPropagation(); - }).on('drop', function(e){ - e.preventDefault(); - e.stopPropagation(); + var enable_drop_functionality = function() { + var self = this; + var dropbox = this.element.parentNode; + $(dropbox).on('dragenter', function(e){ + e.preventDefault(); + e.stopPropagation(); + }).on('dragover', function(e){ + e.preventDefault(); + e.stopPropagation(); + }).on('drop', function(e){ + e.preventDefault(); + e.stopPropagation(); - var dt = e.originalEvent.dataTransfer; - var files = dt.files; - if(!self.multi && files.length > 1) {//single file upload, but dragged multiple files - var tmpfiles = []; - tmpfiles.push(files[0]); - files = tmpfiles;//keep only first file - } - - var ret = true; - if(self.settings.before_change) ret = self.settings.before_change.call(self.element, files, true);//true means files have been dropped - if(!ret || ret.length == 0) { - return false; - } - - //user can return a modified File Array as result - if(ret instanceof Array || (hasFileList && ret instanceof FileList)) files = ret; - - - self.$element.data('ace_input_files', files);//save files data to be used later by user - self.$element.data('ace_input_method', 'drop'); + var dt = e.originalEvent.dataTransfer; + var files = dt.files; + if(!self.multi && files.length > 1) {//single file upload, but dragged multiple files + var tmpfiles = []; + tmpfiles.push(files[0]); + files = tmpfiles;//keep only first file + } + + var ret = true; + if(self.settings.before_change) ret = self.settings.before_change.call(self.element, files, true);//true means files have been dropped + if(!ret || ret.length == 0) { + return false; + } + + //user can return a modified File Array as result + if(ret instanceof Array || (hasFileList && ret instanceof FileList)) files = ret; + + + self.$element.data('ace_input_files', files);//save files data to be used later by user + self.$element.data('ace_input_method', 'drop'); - self.show_file_list(files); - - - self.$element.triggerHandler('change' , [true]);//true means inner_call - return true; - }); - } - - - var handle_on_change = function() { - var ret = true; - if(this.settings.before_change) ret = this.settings.before_change.call(this.element, this.element.files || [this.element.value]/*make it an array*/, false);//false means files have been selected, not dropped - if(!ret || ret.length == 0) { - if(!this.$element.data('ace_input_files')) this.reset_input_field();//if nothing selected before, reset because of the newly unacceptable (ret=false||length=0) selection - return false; - } - + self.show_file_list(files); + + + self.$element.triggerHandler('change' , [true]);//true means inner_call + return true; + }); + } + + + var handle_on_change = function() { + var ret = true; + if(this.settings.before_change) ret = this.settings.before_change.call(this.element, this.element.files || [this.element.value]/*make it an array*/, false);//false means files have been selected, not dropped + if(!ret || ret.length == 0) { + if(!this.$element.data('ace_input_files')) this.reset_input_field();//if nothing selected before, reset because of the newly unacceptable (ret=false||length=0) selection + return false; + } + - //user can return a modified File Array as result - var files = !hasFileList ? null ://for old IE, etc - ((ret instanceof Array || ret instanceof FileList) ? ret : this.element.files); - this.$element.data('ace_input_method', 'select'); + //user can return a modified File Array as result + var files = !hasFileList ? null ://for old IE, etc + ((ret instanceof Array || ret instanceof FileList) ? ret : this.element.files); + this.$element.data('ace_input_method', 'select'); - if(files && files.length > 0) {//html5 - this.$element.data('ace_input_files', files); - } - else { - var name = $.trim( this.element.value ); - if(name && name.length > 0) { - files = [] - files.push(name); - this.$element.data('ace_input_files', files); - } - } + if(files && files.length > 0) {//html5 + this.$element.data('ace_input_files', files); + } + else { + var name = $.trim( this.element.value ); + if(name && name.length > 0) { + files = [] + files.push(name); + this.$element.data('ace_input_files', files); + } + } - if(!files || files.length == 0) return false; - this.show_file_list(files); + if(!files || files.length == 0) return false; + this.show_file_list(files); - return true; - } + return true; + } - var preview_image = function(file) { - var self = this; - var $span = self.$label.find('.file-name:last');//it should be out of onload, otherwise all onloads may target the same span because of delays - - var deferred = new $.Deferred - var reader = new FileReader(); - reader.onload = function (e) { - $span.prepend(""); - var img = $span.find('img:last').get(0); + var preview_image = function(file) { + var self = this; + var $span = self.$label.find('.file-name:last');//it should be out of onload, otherwise all onloads may target the same span because of delays + + var deferred = new $.Deferred + var reader = new FileReader(); + reader.onload = function (e) { + $span.prepend(""); + var img = $span.find('img:last').get(0); - $(img).one('load', function() { - //if image loaded successfully - var size = 50; - if(self.settings.thumbnail == 'large') size = 150; - else if(self.settings.thumbnail == 'fit') size = $span.width(); - $span.addClass(size > 50 ? 'large' : ''); + $(img).one('load', function() { + //if image loaded successfully + var size = 50; + if(self.settings.thumbnail == 'large') size = 150; + else if(self.settings.thumbnail == 'fit') size = $span.width(); + $span.addClass(size > 50 ? 'large' : ''); - var thumb = get_thumbnail(img, size, file.type); - if(thumb == null) { - //if making thumbnail fails - $(this).remove(); - deferred.reject({code:Ace_File_Input.error['THUMBNAIL_FAILED']}); - return; - } + var thumb = get_thumbnail(img, size, file.type); + if(thumb == null) { + //if making thumbnail fails + $(this).remove(); + deferred.reject({code:Ace_File_Input.error['THUMBNAIL_FAILED']}); + return; + } - var w = thumb.w, h = thumb.h; - if(self.settings.thumbnail == 'small') {w=h=size;}; - $(img).css({'background-image':'url('+thumb.src+')' , width:w, height:h}) - .data('thumb', thumb.src) - .attr({src:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg=='}) - .show() + var w = thumb.w, h = thumb.h; + if(self.settings.thumbnail == 'small') {w=h=size;}; + $(img).css({'background-image':'url('+thumb.src+')' , width:w, height:h}) + .data('thumb', thumb.src) + .attr({src:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg=='}) + .show() - /////////////////// - deferred.resolve(); - }).one('error', function() { - //for example when a file has image extenstion, but format is something else - $span.find('img').remove(); - deferred.reject({code:Ace_File_Input.error['IMAGE_LOAD_FAILED']}); - }); + /////////////////// + deferred.resolve(); + }).one('error', function() { + //for example when a file has image extenstion, but format is something else + $span.find('img').remove(); + deferred.reject({code:Ace_File_Input.error['IMAGE_LOAD_FAILED']}); + }); - img.src = e.target.result; - } - reader.onerror = function (e) { - deferred.reject({code:Ace_File_Input.error['FILE_LOAD_FAILED']}); - } - reader.readAsDataURL(file); + img.src = e.target.result; + } + reader.onerror = function (e) { + deferred.reject({code:Ace_File_Input.error['FILE_LOAD_FAILED']}); + } + reader.readAsDataURL(file); - return deferred.promise(); - } + return deferred.promise(); + } - var get_thumbnail = function(img, size, type) { - - var w = img.width, h = img.height; - if(w > size || h > size) { - if(w > h) { - h = parseInt(size/w * h); - w = size; - } else { - w = parseInt(size/h * w); - h = size; - } - } + var get_thumbnail = function(img, size, type) { + + var w = img.width, h = img.height; + if(w > size || h > size) { + if(w > h) { + h = parseInt(size/w * h); + w = size; + } else { + w = parseInt(size/h * w); + h = size; + } + } - var dataURL - try { - var canvas = document.createElement('canvas'); - canvas.width = w; canvas.height = h; - var context = canvas.getContext('2d'); - context.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h); - dataURL = canvas.toDataURL(/*type == 'image/jpeg' ? type : 'image/png', 10*/) - } catch(e) { - dataURL = null; - } + var dataURL + try { + var canvas = document.createElement('canvas'); + canvas.width = w; canvas.height = h; + var context = canvas.getContext('2d'); + context.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h); + dataURL = canvas.toDataURL(/*type == 'image/jpeg' ? type : 'image/png', 10*/) + } catch(e) { + dataURL = null; + } - //there was only one image that failed in firefox completely randomly! so let's double check it - if(!( /^data\:image\/(png|jpe?g|gif);base64,[0-9A-Za-z\+\/\=]+$/.test(dataURL)) ) dataURL = null; - if(! dataURL) return null; + //there was only one image that failed in firefox completely randomly! so let's double check it + if(!( /^data\:image\/(png|jpe?g|gif);base64,[0-9A-Za-z\+\/\=]+$/.test(dataURL)) ) dataURL = null; + if(! dataURL) return null; - return {src: dataURL, w:w, h:h}; - } + return {src: dataURL, w:w, h:h}; + } - /////////////////////////////////////////// - $.fn.ace_file_input = function (option,value) { - var retval; + /////////////////////////////////////////// + $.fn.ace_file_input = function (option,value) { + var retval; - var $set = this.each(function () { - var $this = $(this); - var data = $this.data('ace_file_input'); - var options = typeof option === 'object' && option; + var $set = this.each(function () { + var $this = $(this); + var data = $this.data('ace_file_input'); + var options = typeof option === 'object' && option; - if (!data) $this.data('ace_file_input', (data = new Ace_File_Input(this, options))); - if (typeof option === 'string') retval = data[option](value); - }); + if (!data) $this.data('ace_file_input', (data = new Ace_File_Input(this, options))); + if (typeof option === 'string') retval = data[option](value); + }); - return (retval === undefined) ? $set : retval; - }; + return (retval === undefined) ? $set : retval; + }; - $.fn.ace_file_input.defaults = { - style:false, - no_file:'No File ...', - no_icon:'icon-upload-alt', - btn_choose:'Choose', - btn_change:'Change', - icon_remove:'icon-remove', - droppable:false, - thumbnail:false,//large, fit, small - - //callbacks - before_change:null, - before_remove:null, - preview_error:null + $.fn.ace_file_input.defaults = { + style:false, + no_file:'No File ...', + no_icon:'icon-upload-alt', + btn_choose:'Choose', + btn_change:'Change', + icon_remove:'icon-remove', + droppable:false, + thumbnail:false,//large, fit, small + + //callbacks + before_change:null, + before_remove:null, + preview_error:null } @@ -374,76 +374,76 @@ jQuery(function() { (function($ , undefined) { - $.fn.ace_spinner = function(options) { - - //when min is negative, the input maxlength does not account for the extra minus sign - this.each(function() { - var icon_up = options.icon_up || 'icon-chevron-up' - var icon_down = options.icon_down || 'icon-chevron-down' - var on_sides = options.on_sides || false - - var btn_up_class = options.btn_up_class || '' - var btn_down_class = options.btn_down_class || '' - - var max = options.max || 999 - max = (''+max).length - - $(this).addClass('spinner-input form-control').wrap('
') - var $parent_div = $(this).closest('.ace-spinner').spinner(options).wrapInner("
") + $.fn.ace_spinner = function(options) { + + //when min is negative, the input maxlength does not account for the extra minus sign + this.each(function() { + var icon_up = options.icon_up || 'icon-chevron-up' + var icon_down = options.icon_down || 'icon-chevron-down' + var on_sides = options.on_sides || false + + var btn_up_class = options.btn_up_class || '' + var btn_down_class = options.btn_down_class || '' + + var max = options.max || 999 + max = (''+max).length + + $(this).addClass('spinner-input form-control').wrap('
') + var $parent_div = $(this).closest('.ace-spinner').spinner(options).wrapInner("
") - if(on_sides) - { - $(this).before('
\ - \ -
') - .after('
\ - \ -
') - - $parent_div.addClass('touch-spinner') - $parent_div.css('width' , (max * 20 + 40)+'px') - } - else { - $(this).after('
\ - \ - \ -
') + if(on_sides) + { + $(this).before('
\ + \ +
') + .after('
\ + \ +
') + + $parent_div.addClass('touch-spinner') + $parent_div.css('width' , (max * 20 + 40)+'px') + } + else { + $(this).after('
\ + \ + \ +
') - if("ontouchend" in document || options.touch_spinner) { - $parent_div.addClass('touch-spinner') - $parent_div.css('width' , (max * 20 + 40)+'px') - } - else { - $(this).next().addClass('btn-group-vertical'); - $parent_div.css('width' , (max * 20 + 10)+'px') - } - } - - + if("ontouchend" in document || options.touch_spinner) { + $parent_div.addClass('touch-spinner') + $parent_div.css('width' , (max * 20 + 40)+'px') + } + else { + $(this).next().addClass('btn-group-vertical'); + $parent_div.css('width' , (max * 20 + 10)+'px') + } + } + + - $(this).on('mousewheel DOMMouseScroll', function(event){ - var delta = event.originalEvent.detail < 0 || event.originalEvent.wheelDelta > 0 ? 1 : -1 - $parent_div.spinner('step', delta > 0)//accepts true or false as second param - $parent_div.spinner('triggerChangedEvent') - return false - }); - var that = $(this); - $parent_div.on('changed', function(){ - that.trigger('change')//trigger the input's change event - }); - - }); - - return this; - } + $(this).on('mousewheel DOMMouseScroll', function(event){ + var delta = event.originalEvent.detail < 0 || event.originalEvent.wheelDelta > 0 ? 1 : -1 + $parent_div.spinner('step', delta > 0)//accepts true or false as second param + $parent_div.spinner('triggerChangedEvent') + return false + }); + var that = $(this); + $parent_div.on('changed', function(){ + that.trigger('change')//trigger the input's change event + }); + + }); + + return this; + } })(window.jQuery); @@ -454,28 +454,28 @@ jQuery(function() { (function($ , undefined) { - $.fn.ace_wizard = function(options) { - - this.each(function() { - var $this = $(this); - $this.wizard(); + $.fn.ace_wizard = function(options) { + + this.each(function() { + var $this = $(this); + $this.wizard(); - var buttons = $this.siblings('.wizard-actions').eq(0); - var $wizard = $this.data('wizard'); - $wizard.$prevBtn.remove(); - $wizard.$nextBtn.remove(); - - $wizard.$prevBtn = buttons.find('.btn-prev').eq(0).on(ace.click_event, function(){ - $this.wizard('previous'); - }).attr('disabled', 'disabled'); - $wizard.$nextBtn = buttons.find('.btn-next').eq(0).on(ace.click_event, function(){ - $this.wizard('next'); - }).removeAttr('disabled'); - $wizard.nextText = $wizard.$nextBtn.text(); - }); - - return this; - } + var buttons = $this.siblings('.wizard-actions').eq(0); + var $wizard = $this.data('wizard'); + $wizard.$prevBtn.remove(); + $wizard.$nextBtn.remove(); + + $wizard.$prevBtn = buttons.find('.btn-prev').eq(0).on(ace.click_event, function(){ + $this.wizard('previous'); + }).attr('disabled', 'disabled'); + $wizard.$nextBtn = buttons.find('.btn-next').eq(0).on(ace.click_event, function(){ + $this.wizard('next'); + }).removeAttr('disabled'); + $wizard.nextText = $wizard.$nextBtn.text(); + }); + + return this; + } })(window.jQuery); @@ -484,49 +484,49 @@ jQuery(function() { (function($ , undefined) { - $.fn.ace_colorpicker = function(options) { - - var settings = $.extend( { - pull_right:false, - caret:true + $.fn.ace_colorpicker = function(options) { + + var settings = $.extend( { + pull_right:false, + caret:true }, options); - - this.each(function() { - - var $that = $(this); - var colors = ''; - var color = ''; - $(this).hide().find('option').each(function() { - var $class = 'colorpick-btn'; - if(this.selected) { - $class += ' selected'; - color = this.value; - } - colors += '
  • '; - }).end().on('change.ace_inner_call', function(){ - $(this).next().find('.btn-colorpicker').css('background-color', this.value); - }) - .after('') - .next().find('.dropdown-menu').on(ace.click_event, function(e) { - var a = $(e.target); - if(!a.is('.colorpick-btn')) return false; - a.closest('ul').find('.selected').removeClass('selected'); - a.addClass('selected'); - var color = a.data('color'); + + this.each(function() { + + var $that = $(this); + var colors = ''; + var color = ''; + $(this).hide().find('option').each(function() { + var $class = 'colorpick-btn'; + if(this.selected) { + $class += ' selected'; + color = this.value; + } + colors += '
  • '; + }).end().on('change.ace_inner_call', function(){ + $(this).next().find('.btn-colorpicker').css('background-color', this.value); + }) + .after('') + .next().find('.dropdown-menu').on(ace.click_event, function(e) { + var a = $(e.target); + if(!a.is('.colorpick-btn')) return false; + a.closest('ul').find('.selected').removeClass('selected'); + a.addClass('selected'); + var color = a.data('color'); - $that.val(color).change(); + $that.val(color).change(); - e.preventDefault(); - return true;//if false, dropdown won't hide! - }); - - - }); - return this; - - } - - + e.preventDefault(); + return true;//if false, dropdown won't hide! + }); + + + }); + return this; + + } + + })(window.jQuery); @@ -541,38 +541,38 @@ jQuery(function() { (function($ , undefined) { - $.fn.ace_tree = function(options) { - var $options = { - 'open-icon' : 'icon-folder-open', - 'close-icon' : 'icon-folder-close', - 'selectable' : true, - 'selected-icon' : 'icon-ok', - 'unselected-icon' : 'tree-dot' - } - - $options = $.extend({}, $options, options) + $.fn.ace_tree = function(options) { + var $options = { + 'open-icon' : 'icon-folder-open', + 'close-icon' : 'icon-folder-close', + 'selectable' : true, + 'selected-icon' : 'icon-ok', + 'unselected-icon' : 'tree-dot' + } + + $options = $.extend({}, $options, options) - this.each(function() { - var $this = $(this); - $this.html('\ - '); - $this.addClass($options['selectable'] == true ? 'tree-selectable' : 'tree-unselectable'); - - $this.tree($options); - }); + this.each(function() { + var $this = $(this); + $this.html('\ + '); + $this.addClass($options['selectable'] == true ? 'tree-selectable' : 'tree-unselectable'); + + $this.tree($options); + }); - return this; - } + return this; + } })(window.jQuery); @@ -589,308 +589,308 @@ jQuery(function() { (function($ , undefined) { - $.fn.ace_wysiwyg = function($options , undefined) { - var options = $.extend( { - speech_button:true, - wysiwyg:{} + $.fn.ace_wysiwyg = function($options , undefined) { + var options = $.extend( { + speech_button:true, + wysiwyg:{} }, $options); - var color_values = [ - '#ac725e','#d06b64','#f83a22','#fa573c','#ff7537','#ffad46', - '#42d692','#16a765','#7bd148','#b3dc6c','#fbe983','#fad165', - '#92e1c0','#9fe1e7','#9fc6e7','#4986e7','#9a9cff','#b99aff', - '#c2c2c2','#cabdbf','#cca6ac','#f691b2','#cd74e6','#a47ae2', - '#444444' - ] + var color_values = [ + '#ac725e','#d06b64','#f83a22','#fa573c','#ff7537','#ffad46', + '#42d692','#16a765','#7bd148','#b3dc6c','#fbe983','#fad165', + '#92e1c0','#9fe1e7','#9fc6e7','#4986e7','#9a9cff','#b99aff', + '#c2c2c2','#cabdbf','#cca6ac','#f691b2','#cd74e6','#a47ae2', + '#444444' + ] - var button_defaults = - { - 'font' : { - values:['Arial', 'Courier', 'Comic Sans MS', 'Helvetica', 'Open Sans', 'Tahoma', 'Verdana'], - icon:'icon-font', - title:'Font' - }, - 'fontSize' : { - values:{5:'Huge', 3:'Normal', 1:'Small'}, - icon:'icon-text-height', - title:'Font Size' - }, - 'bold' : { - icon : 'icon-bold', - title : 'Bold (Ctrl/Cmd+B)' - }, - 'italic' : { - icon : 'icon-italic', - title : 'Italic (Ctrl/Cmd+I)' - }, - 'strikethrough' : { - icon : 'icon-strikethrough', - title : 'Strikethrough' - }, - 'underline' : { - icon : 'icon-underline', - title : 'Underline' - }, - 'insertunorderedlist' : { - icon : 'icon-list-ul', - title : 'Bullet list' - }, - 'insertorderedlist' : { - icon : 'icon-list-ol', - title : 'Number list' - }, - 'outdent' : { - icon : 'icon-indent-left', - title : 'Reduce indent (Shift+Tab)' - }, - 'indent' : { - icon : 'icon-indent-right', - title : 'Indent (Tab)' - }, - 'justifyleft' : { - icon : 'icon-align-left', - title : 'Align Left (Ctrl/Cmd+L)' - }, - 'justifycenter' : { - icon : 'icon-align-center', - title : 'Center (Ctrl/Cmd+E)' - }, - 'justifyright' : { - icon : 'icon-align-right', - title : 'Align Right (Ctrl/Cmd+R)' - }, - 'justifyfull' : { - icon : 'icon-align-justify', - title : 'Justify (Ctrl/Cmd+J)' - }, - 'createLink' : { - icon : 'icon-link', - title : 'Hyperlink', - button_text : 'Add', - placeholder : 'URL', - button_class : 'btn-primary' - }, - 'unlink' : { - icon : 'icon-unlink', - title : 'Remove Hyperlink' - }, - 'insertImage' : { - icon : 'icon-picture', - title : 'Insert picture', - button_text : ' Choose Image …', - placeholder : 'Image URL', - button_insert : 'Insert', - button_class : 'btn-success', - button_insert_class : 'btn-primary', - choose_file: true //show the choose file button? - }, - 'foreColor' : { - values : color_values, - title : 'Change Color' - }, - 'backColor' : { - values : color_values, - title : 'Change Background Color' - }, - 'undo' : { - icon : 'icon-undo', - title : 'Undo (Ctrl/Cmd+Z)' - }, - 'redo' : { - icon : 'icon-repeat', - title : 'Redo (Ctrl/Cmd+Y)' - }, - 'viewSource' : { - icon : 'icon-code', - title : 'View Source' - } - } - - var toolbar_buttons = - options.toolbar || - [ - 'font', - null, - 'fontSize', - null, - 'bold', - 'italic', - 'strikethrough', - 'underline', - null, - 'insertunorderedlist', - 'insertorderedlist', - 'outdent', - 'indent', - null, - 'justifyleft', - 'justifycenter', - 'justifyright', - 'justifyfull', - null, - 'createLink', - 'unlink', - null, - 'insertImage', - null, - 'foreColor', - null, - 'undo', - 'redo', - null, - 'viewSource' - ] + var button_defaults = + { + 'font' : { + values:['Arial', 'Courier', 'Comic Sans MS', 'Helvetica', 'Open Sans', 'Tahoma', 'Verdana'], + icon:'icon-font', + title:'Font' + }, + 'fontSize' : { + values:{5:'Huge', 3:'Normal', 1:'Small'}, + icon:'icon-text-height', + title:'Font Size' + }, + 'bold' : { + icon : 'icon-bold', + title : 'Bold (Ctrl/Cmd+B)' + }, + 'italic' : { + icon : 'icon-italic', + title : 'Italic (Ctrl/Cmd+I)' + }, + 'strikethrough' : { + icon : 'icon-strikethrough', + title : 'Strikethrough' + }, + 'underline' : { + icon : 'icon-underline', + title : 'Underline' + }, + 'insertunorderedlist' : { + icon : 'icon-list-ul', + title : 'Bullet list' + }, + 'insertorderedlist' : { + icon : 'icon-list-ol', + title : 'Number list' + }, + 'outdent' : { + icon : 'icon-indent-left', + title : 'Reduce indent (Shift+Tab)' + }, + 'indent' : { + icon : 'icon-indent-right', + title : 'Indent (Tab)' + }, + 'justifyleft' : { + icon : 'icon-align-left', + title : 'Align Left (Ctrl/Cmd+L)' + }, + 'justifycenter' : { + icon : 'icon-align-center', + title : 'Center (Ctrl/Cmd+E)' + }, + 'justifyright' : { + icon : 'icon-align-right', + title : 'Align Right (Ctrl/Cmd+R)' + }, + 'justifyfull' : { + icon : 'icon-align-justify', + title : 'Justify (Ctrl/Cmd+J)' + }, + 'createLink' : { + icon : 'icon-link', + title : 'Hyperlink', + button_text : 'Add', + placeholder : 'URL', + button_class : 'btn-primary' + }, + 'unlink' : { + icon : 'icon-unlink', + title : 'Remove Hyperlink' + }, + 'insertImage' : { + icon : 'icon-picture', + title : 'Insert picture', + button_text : ' Choose Image …', + placeholder : 'Image URL', + button_insert : 'Insert', + button_class : 'btn-success', + button_insert_class : 'btn-primary', + choose_file: true //show the choose file button? + }, + 'foreColor' : { + values : color_values, + title : 'Change Color' + }, + 'backColor' : { + values : color_values, + title : 'Change Background Color' + }, + 'undo' : { + icon : 'icon-undo', + title : 'Undo (Ctrl/Cmd+Z)' + }, + 'redo' : { + icon : 'icon-repeat', + title : 'Redo (Ctrl/Cmd+Y)' + }, + 'viewSource' : { + icon : 'icon-code', + title : 'View Source' + } + } + + var toolbar_buttons = + options.toolbar || + [ + 'font', + null, + 'fontSize', + null, + 'bold', + 'italic', + 'strikethrough', + 'underline', + null, + 'insertunorderedlist', + 'insertorderedlist', + 'outdent', + 'indent', + null, + 'justifyleft', + 'justifycenter', + 'justifyright', + 'justifyfull', + null, + 'createLink', + 'unlink', + null, + 'insertImage', + null, + 'foreColor', + null, + 'undo', + 'redo', + null, + 'viewSource' + ] - this.each(function() { - var toolbar = '
    '; + this.each(function() { + var toolbar = '
    '; - for(var tb in toolbar_buttons) if(toolbar_buttons.hasOwnProperty(tb)) { - var button = toolbar_buttons[tb]; - if(button === null){ - toolbar += '
    '; - continue; - } - - if(typeof button == "string" && button in button_defaults) { - button = button_defaults[button]; - button.name = toolbar_buttons[tb]; - } else if(typeof button == "object" && button.name in button_defaults) { - button = $.extend(button_defaults[button.name] , button); - } - else continue; - - var className = "className" in button ? button.className : ''; - switch(button.name) { - case 'font': - toolbar += ' '; - toolbar += ' '; - break; + for(var tb in toolbar_buttons) if(toolbar_buttons.hasOwnProperty(tb)) { + var button = toolbar_buttons[tb]; + if(button === null){ + toolbar += '
    '; + continue; + } + + if(typeof button == "string" && button in button_defaults) { + button = button_defaults[button]; + button.name = toolbar_buttons[tb]; + } else if(typeof button == "object" && button.name in button_defaults) { + button = $.extend(button_defaults[button.name] , button); + } + else continue; + + var className = "className" in button ? button.className : ''; + switch(button.name) { + case 'font': + toolbar += ' '; + toolbar += ' '; + break; - case 'fontSize': - toolbar += '   '; - toolbar += ' '; - break; + case 'fontSize': + toolbar += '   '; + toolbar += ' '; + break; - case 'createLink': - toolbar += '
    '; - toolbar += '
    '; - break; + case 'createLink': + toolbar += '
    '; + toolbar += '
    '; + break; - case 'insertImage': - toolbar += '
    '; - toolbar += '
    '; - break; + case 'insertImage': + toolbar += '
    '; + toolbar += '
    '; + break; - case 'foreColor': - case 'backColor': - toolbar += ' '; - toolbar += ' '; - break; + case 'foreColor': + case 'backColor': + toolbar += ' '; + toolbar += ' '; + break; - case 'viewSource': - toolbar += ' '; - break; - default: - toolbar += ' '; - break; - } - } - toolbar += '
    '; + case 'viewSource': + toolbar += ' '; + break; + default: + toolbar += ' '; + break; + } + } + toolbar += '
    '; - //if we have a function to decide where to put the toolbar, then call that - if(options.toolbar_place) toolbar = options.toolbar_place.call(this, toolbar); - //otherwise put it just before our DIV - else toolbar = $(this).before(toolbar).prev(); + //if we have a function to decide where to put the toolbar, then call that + if(options.toolbar_place) toolbar = options.toolbar_place.call(this, toolbar); + //otherwise put it just before our DIV + else toolbar = $(this).before(toolbar).prev(); - toolbar.find('a[title]').tooltip({animation:false, container:'body'}); - toolbar.find('.dropdown-menu input:not([type=file])').on(ace.click_event, function() {return false}) - .on('change', function() {$(this).closest('.dropdown-menu').siblings('.dropdown-toggle').dropdown('toggle')}) - .on('keydown', function (e) {if(e.which == 27) {this.value='';$(this).change()}}); - toolbar.find('input[type=file]').prev().on(ace.click_event, function (e) { - $(this).next().click(); - }); - toolbar.find('.wysiwyg_colorpicker').each(function() { - $(this).ace_colorpicker({pull_right:true}).change(function(){ - $(this).nextAll('input').eq(0).val(this.value).change(); - }).next().find('.btn-colorpicker').tooltip({title: this.title, animation:false, container:'body'}) - }); - - var speech_input; - if (options.speech_button && 'onwebkitspeechchange' in (speech_input = document.createElement('input'))) { - var editorOffset = $(this).offset(); - toolbar.append(speech_input); - $(speech_input).attr({type:'text', 'data-edit':'inserttext','x-webkit-speech':''}).addClass('wysiwyg-speech-input') - .css({'position':'absolute'}).offset({top: editorOffset.top, left: editorOffset.left+$(this).innerWidth()-35}); - } else speech_input = null - - - //view source - var self = $(this); - var view_source = false; - toolbar.find('a[data-view=source]').on('click', function(e){ - e.preventDefault(); - - if(!view_source) { - $('