diff --git a/core/utils/file.py b/core/utils/file.py index f697da8..930b2d4 100644 --- a/core/utils/file.py +++ b/core/utils/file.py @@ -1,5 +1,7 @@ import uuid +import os -__author__ = 'fergalm' def generate_save_file_name(prefix, filename): - return '/'.join([prefix, str(uuid.uuid1()), filename]) + filename, extension = os.path.splitext(filename) + ret = "%s%s" % ('/'.join([prefix, str(uuid.uuid1())]), extension) + return ret diff --git a/dss/settings.py b/dss/settings.py index 1c74209..636784d 100644 --- a/dss/settings.py +++ b/dss/settings.py @@ -128,6 +128,7 @@ INSTALLED_APPS = ( 'django_facebook', 'djcelery', 'crispy_forms', + 'sorl.thumbnail', #'pipeline', 'avatar', 'notification', diff --git a/requirements.txt b/requirements.txt index e57acdf..9d6b16a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +PIL Django>=1.4 MySQL-python>=1.2.3 pillow>=1.7.7 @@ -17,3 +18,4 @@ git+git://github.com/maraujop/django-crispy-forms.git#django-crispy-forms git+git://github.com/tschellenbach/Django-facebook.git#django-facebook django-grappelli humanize +sorl-thumbnail>=11.12 diff --git a/spa/ajax.py b/spa/ajax.py index 050171f..77279ba 100644 --- a/spa/ajax.py +++ b/spa/ajax.py @@ -5,14 +5,19 @@ from annoying.decorators import render_to from django.shortcuts import render_to_response import json from django.utils import simplejson +from django.views.decorators.csrf import csrf_exempt +import os from core.utils import live +from spa.models import UserProfile from spa.models.Mix import Mix from spa.models.Comment import Comment from spa.models.MixLike import MixLike +from PIL import Image +import logging +logger = logging.getLogger(__name__) class AjaxHandler(object): - import logging # Get an instance of a logger logger = logging.getLogger(__name__) @@ -31,6 +36,8 @@ class AjaxHandler(object): url(r'^release_player/(?P\d+)/$', 'spa.ajax.release_player'), url(r'^live_now_playing/$', 'spa.ajax.live_now_playing'), url(r'^like/$', 'spa.ajax.like', name='ajax_mix-description'), + url(r'^facebook_post_likes_allowed/$', 'spa.ajax.facebook_post_likes_allowed', name='ajax_facebook_post_likes_allowed'), + url(r'^upload_avatar_image/$', 'spa.ajax.upload_avatar_image', name='ajax_upload_avatar_image'), ] return pattern_list @@ -113,3 +120,27 @@ def like(request): mix.likes.add(MixLike(mix = mix, user = request.user)) mix.save() return HttpResponse(simplejson.dumps(request.raw_post_data)) + +@login_required() +def facebook_post_likes_allowed(request): + profile = request.user.get_profile(); + if profile is not None: + likes_allowed = profile.activity_sharing & UserProfile.ACTIVITY_SHARE_LIKES + facebook_allowed = profile.activity_sharing_networks & UserProfile.ACTIVITY_SHARE_NETWORK_FACEBOOK + + return HttpResponse(json.dumps(_get_json(bool(likes_allowed & facebook_allowed))), mimetype="application/json") + + return HttpResponse(json.dumps(_get_json(False)), mimetype="application/json") + +@csrf_exempt +def upload_avatar_image(request): + try: + if 'Filedata' in request.FILES: + profile = request.user.get_profile() + if profile: + profile.avatar_image = request.FILES['Filedata'] + profile.save() + return HttpResponse(json.dumps(_get_json("Success"))) + except Exception, ex: + logger.exception("Error uploading avatar") + return HttpResponse(json.dumps(_get_json("Failed"))) \ No newline at end of file diff --git a/spa/api/v1/UserResource.py b/spa/api/v1/UserResource.py index 71a4468..250dfec 100644 --- a/spa/api/v1/UserResource.py +++ b/spa/api/v1/UserResource.py @@ -8,6 +8,7 @@ from spa.models import UserProfile class UserResource(BackboneCompatibleResource): class Meta: queryset = UserProfile.objects.all() + excludes = [] authorization = Authorization() authentication = Authentication() always_return_data = True @@ -20,6 +21,22 @@ class UserResource(BackboneCompatibleResource): bundle.data['first_name'] = bundle.obj.first_name bundle.data['last_name'] = bundle.obj.last_name bundle.data['email'] = bundle.obj.email + + if bundle.obj.activity_sharing is not None: + bundle.data['activity_share_likes'] = (bundle.obj.activity_sharing & UserProfile.ACTIVITY_SHARE_LIKES) != 0; + bundle.data['activity_share_favourites'] = (bundle.obj.activity_sharing & UserProfile.ACTIVITY_SHARE_FAVOURITES) != 0; + bundle.data['activity_share_comments'] = (bundle.obj.activity_sharing & UserProfile.ACTIVITY_SHARE_COMMENTS) != 0; + else: + bundle.data['activity_share_likes'] =0 + bundle.data['activity_share_favourites'] =0 + bundle.data['activity_share_comments'] =0 + + if bundle.obj.activity_sharing_networks is not None: + bundle.data['activity_share_networks_facebook'] = (bundle.obj.activity_sharing_networks & UserProfile.ACTIVITY_SHARE_NETWORK_FACEBOOK) != 0; + bundle.data['activity_share_networks_twitter'] = (bundle.obj.activity_sharing_networks& UserProfile.ACTIVITY_SHARE_NETWORK_TWITTER) != 0; + else: + bundle.data['activity_share_networks_facebook'] = 0 + bundle.data['activity_share_networks_facebook'] = 0 return bundle def apply_authorization_limits(self, request, object_list): diff --git a/spa/models/UserProfile.py b/spa/models/UserProfile.py index d1f9662..a35665f 100644 --- a/spa/models/UserProfile.py +++ b/spa/models/UserProfile.py @@ -5,18 +5,46 @@ from django.core.urlresolvers import reverse from django.db import models from django.db.models.signals import post_save from django_gravatar.helpers import has_gravatar, get_gravatar_url +import os +from core.utils.file import generate_save_file_name from dss import settings from spa.models._BaseModel import _BaseModel +def avatar_name(instance, filename): + return generate_save_file_name('avatars', filename) class UserProfile(_BaseModel): class Meta: app_label = 'spa' + ACTIVITY_SHARE_LIKES = 1 + ACTIVITY_SHARE_FAVOURITES = 2 + ACTIVITY_SHARE_COMMENTS = 4 + + ACTIVITY_SHARE_NETWORK_FACEBOOK = 1 + ACTIVITY_SHARE_NETWORK_TWITTER = 2 + # This field is required. user = models.ForeignKey(User, unique=True) avatar_type = models.CharField(max_length=15) - avatar_image = models.ImageField(blank=True, upload_to='/avatars/') + avatar_image = models.ImageField(blank=True, upload_to=avatar_name) display_name = models.CharField(blank=True, max_length=35) + activity_sharing = models.IntegerField(default=0) + activity_sharing_networks = models.IntegerField(default=0) + def save(self, size=(260, 180)): + """ + Save Photo after ensuring it is not blank. Resize as needed. + """ + from PIL import Image + if not self.id and not self.source: + return + + super(UserProfile, self).save() + + filename = self.get_source_filename() + image = Image.open(filename) + + image.thumbnail(size, Image.ANTIALIAS) + image.save(filename) def create_user_profile(sender, instance, created, **kwargs): if created: @@ -65,4 +93,5 @@ class UserProfile(_BaseModel): return urlparse.urljoin(settings.STATIC_URL, "img/default-avatar-32.png") def save(self, force_insert=False, force_update=False, using=None): - return super(UserProfile, self).save(force_insert, force_update, using) \ No newline at end of file + return super(UserProfile, self).save(force_insert, force_update, using) + diff --git a/static/css/style.css b/static/css/style.css index 238064e..a6dfbcc 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -8,8 +8,12 @@ body { padding-bottom: 40px; padding-right: 32px; } + /* IE/Chrome image fix */ -img.event-content {width: auto; height: auto;} +img.event-content { + width: auto; + height: auto; +} #header { margin-top: 20px; @@ -23,7 +27,7 @@ img.event-content {width: auto; height: auto;} border-bottom: 3px solid #CEC3B3; } -.page-header{ +.page-header { -moz-border-bottom-colors: none; -moz-border-image: none; -moz-border-left-colors: none; @@ -154,7 +158,9 @@ ul.comment-listing .comment-entry { .list-horiz li { float: left; + list-style-type: none; position: relative; + padding-right: 20px; } .bordered-right { @@ -166,7 +172,8 @@ ul.comment-listing .comment-entry { margin-right: 7px; padding-right: 7px; } -.stats{ + +.stats { border: 0; font: 0/0 a; text-shadow: none; @@ -180,21 +187,26 @@ table.tablesorter { width: 1024px; border: 1px solid #000; } + table.tablesorter th { text-align: left; padding: 5px; background-color: #6E6E6E; } + table.tablesorter td { color: #FFF; padding: 5px; } + table.tablesorter .even { background-color: #3D3D3D; } + table.tablesorter .odd { background-color: #6E6E6E; } + table.tablesorter .header { background-image: url(../img/bg.png); background-repeat: no-repeat; @@ -205,10 +217,12 @@ table.tablesorter .header { padding-top: 8px; height: auto; } + table.tablesorter .headerSortUp { background-image: url(../img/asc.png); background-repeat: no-repeat; } + table.tablesorter .headerSortDown { background-image: url(../img/desc.png); background-repeat: no-repeat; @@ -217,6 +231,7 @@ table.tablesorter .headerSortDown { table .header { cursor: pointer; } + table .header:after { content: ""; float: right; @@ -226,19 +241,23 @@ table .header:after { border-color: #000000 transparent; visibility: hidden; } + table .headerSortUp, table .headerSortDown { background-color: #f7f7f9; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); } + table .header:hover:after { visibility: visible; } + table .headerSortDown:after, table .headerSortDown:hover:after { visibility: visible; - filter: alpha(opacity=60); + filter: alpha(opacity = 60); -moz-opacity: 0.6; opacity: 0.6; } + table .headerSortUp:after { border-bottom: none; border-left: 4px solid transparent; @@ -248,7 +267,200 @@ table .headerSortUp:after { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; - filter: alpha(opacity=60); + filter: alpha(opacity = 60); -moz-opacity: 0.6; opacity: 0.6; +} + +input[type="checkbox"] { + visibility: hidden; +} + +.slideThree { + width: 80px; + height: 26px; + background: #333; + margin: 20px auto; + -webkit-border-radius: 50px; + -moz-border-radius: 50px; + border-radius: 50px; + position: relative; + -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); + -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); +} + +.slideThree { + width: 80px; + height: 26px; + background: #333; + margin: 20px auto; + + -webkit-border-radius: 50px; + -moz-border-radius: 50px; + border-radius: 50px; + position: relative; + + -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); + -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2); +} + +.slideThree:after { + content: 'OFF'; + font: 12px/26px Arial, sans-serif; + color: #000; + position: absolute; + right: 10px; + z-index: 0; + font-weight: bold; + text-shadow: 1px 1px 0px rgba(255, 255, 255, .15); +} + +.slideThree:before { + content: 'ON'; + font: 12px/26px Arial, sans-serif; + color: #00bf00; + position: absolute; + left: 10px; + z-index: 0; + font-weight: bold; +} + +.slideThree label { + display: block; + width: 34px; + height: 20px; + + -webkit-border-radius: 50px; + -moz-border-radius: 50px; + border-radius: 50px; + + -webkit-transition: all .4s ease; + -moz-transition: all .4s ease; + -o-transition: all .4s ease; + -ms-transition: all .4s ease; + transition: all .4s ease; + cursor: pointer; + position: absolute; + top: 3px; + left: 3px; + z-index: 1; + + -webkit-box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.3); + background: #fcfff4; + + background: -webkit-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -moz-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -o-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: -ms-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + background: linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#fcfff4', endColorstr = '#b3bead', GradientType = 0); +} + +.slideThree input[type=checkbox]:checked + label { + left: 43px; +} + +.droparea { + position: relative; + text-align: center; +} + +.multiple { + position: relative; + height: 20px; +} + +.droparea div, .droparea input, .multiple div, .multiple input { + position: absolute; + top: 0; + width: 100%; + height: 100%; +} + +.droparea input, .multiple input { + cursor: pointer; + opacity: 0; +} + +.droparea .instructions, .multiple .instructions { + border: 2px dashed #ddd; + opacity: .8; +} + +.droparea .instructions.over, .multiple .instructions.over { + border: 2px dashed #000; + background: #ffa; +} + +.droparea .progress, .multiple .progress { + position: absolute; + bottom: 0; + width: 100%; + height: 0; + color: #fff; + background: #6b0; +} + +.multiple .progress { + width: 0; + height: 100%; +} + +#areas { + float: left; + width: 480px; +} + +div.spot { + float: left; + margin: 0 20px 0 0; + width: 120px; + height: 120px; +} + +.thumb { + float: left; + margin: 0 20px 20px 0; + width: 140px; + min-height: 105px; +} + +.desc { + float: right; + width: 460px; +} + +.signature a { + color: #555; + text-decoration: none; +} + +.signature img { + margin-right: 5px; + vertical-align: middle; +} + +input[type=text], textarea { + margin-bottom: 10px; + padding: 5px; + width: 288px; + height: 18px; + border: 1px solid #bbb; +} + +textarea { + height: 58px; +} + +input[type=submit] { + float: right; + margin-right: 20px; + padding: 5px 25px; + color: #111; + border: 1px solid #666; + background: #888; } \ No newline at end of file diff --git a/static/css/uploadifive.css b/static/css/uploadifive.css new file mode 100644 index 0000000..36b92fd --- /dev/null +++ b/static/css/uploadifive.css @@ -0,0 +1,72 @@ +.uploadifive-button { + background-color: #505050; + background-image: linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -o-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -moz-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -webkit-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -ms-linear-gradient(bottom, #505050 0%, #707070 100%); + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, #505050), + color-stop(1, #707070) + ); + background-position: center top; + background-repeat: no-repeat; + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border-radius: 30px; + border: 2px solid #808080; + color: #FFF; + font: bold 12px Arial, Helvetica, sans-serif; + text-align: center; + text-shadow: 0 -1px 0 rgba(0,0,0,0.25); + text-transform: uppercase; + width: 100%; +} +.uploadifive-button:hover { + background-color: #606060; + background-image: linear-gradient(top, #606060 0%, #808080 100%); + background-image: -o-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -moz-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -webkit-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -ms-linear-gradient(top, #606060 0%, #808080 100%); + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, #606060), + color-stop(1, #808080) + ); + background-position: center bottom; +} +.uploadifive-queue-item { + background-color: #F5F5F5; + border-bottom: 1px dotted #D5D5D5; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + font: 12px Arial, Helvetica, Sans-serif; + margin-top: 3px; + padding: 15px; +} +.uploadifive-queue-item .close { + background: url('../img/uploadifive-cancel.png') 0 0 no-repeat; + display: block; + float: right; + height: 16px; + text-indent: -9999px; + width: 16px; +} +.uploadifive-queue-item .progress { + border: 1px solid #D0D0D0; + height: 3px; + margin-top: 5px; + width: 100%; +} +.uploadifive-queue-item .progress-bar { + background-color: #0072BC; + height: 3px; + width: 0; +} \ No newline at end of file diff --git a/static/img/loader.gif b/static/img/loader.gif new file mode 100644 index 0000000..ab02303 Binary files /dev/null and b/static/img/loader.gif differ diff --git a/static/img/switch_handle-OLD.png b/static/img/switch_handle-OLD.png new file mode 100644 index 0000000..f9bbf78 Binary files /dev/null and b/static/img/switch_handle-OLD.png differ diff --git a/static/img/switch_handle-gray.png b/static/img/switch_handle-gray.png new file mode 100644 index 0000000..0bb007f Binary files /dev/null and b/static/img/switch_handle-gray.png differ diff --git a/static/img/switch_handle-light.png b/static/img/switch_handle-light.png new file mode 100644 index 0000000..31e10a6 Binary files /dev/null and b/static/img/switch_handle-light.png differ diff --git a/static/img/switch_handle.png b/static/img/switch_handle.png new file mode 100644 index 0000000..6a7d5c4 Binary files /dev/null and b/static/img/switch_handle.png differ diff --git a/static/img/switch_handle_pressed.png b/static/img/switch_handle_pressed.png new file mode 100644 index 0000000..a945489 Binary files /dev/null and b/static/img/switch_handle_pressed.png differ diff --git a/static/img/switch_track-dark.png b/static/img/switch_track-dark.png new file mode 100644 index 0000000..33d63f6 Binary files /dev/null and b/static/img/switch_track-dark.png differ diff --git a/static/img/switch_track-gray.png b/static/img/switch_track-gray.png new file mode 100644 index 0000000..9c1d90d Binary files /dev/null and b/static/img/switch_track-gray.png differ diff --git a/static/img/switch_track-light.png b/static/img/switch_track-light.png new file mode 100644 index 0000000..0247527 Binary files /dev/null and b/static/img/switch_track-light.png differ diff --git a/static/img/switch_track.png b/static/img/switch_track.png new file mode 100644 index 0000000..95c10bc Binary files /dev/null and b/static/img/switch_track.png differ diff --git a/static/img/uploadifive-cancel.png b/static/img/uploadifive-cancel.png new file mode 100644 index 0000000..1d97535 Binary files /dev/null and b/static/img/uploadifive-cancel.png differ diff --git a/static/js/app/social.js b/static/js/app/social.js new file mode 100644 index 0000000..20e6a61 --- /dev/null +++ b/static/js/app/social.js @@ -0,0 +1,23 @@ +postFacebookLike = function (mixId) { + //first off, find if the current user has allowed facebook likes + + $.getJSON( + 'ajax/facebook_post_likes_allowed/', + function (data) { + if (data.value) { + FB.api( + '/me/deepsouthsounds:like', + 'post', + { mix:'http://' + window.location.host + '/social/redirect/mix/' + mixId}, + function (response) { + if (!response || response.error) { + alert('Error occured: ' + response.error.message); + } else { + window.utils.showAlert("Posted your like to facebook, you can stop this in your settings page.", "Cheers feen", "alert-success", true); + } + } + ); + } + } + ); +} \ No newline at end of file diff --git a/static/js/app/views/mix.js b/static/js/app/views/mix.js index 6375ea4..e5b8477 100644 --- a/static/js/app/views/mix.js +++ b/static/js/app/views/mix.js @@ -22,18 +22,9 @@ window.MixListItemView = Backbone.View.extend({ var mode = $(e.currentTarget).data("mode"); $.post( "/ajax/like/", - { dataId:id, dataMode:mode }, - function (data) { - } + { dataId:id, dataMode:mode } ); - var body = 'This is a test of the Deep South Sounds Broadcast System. If this was real, you would be reading something useful'; - FB.api('/me/deepsouthsounds:like', 'post', { mix: 'http://' + window.location.host + '/social/redirect/mix/' + id}, function (response) { - if (!response || response.error) { - alert('Error occured: ' + response.error.message); - } else { - window.utils.showAlert("You liked this", "Cheers feen", "alert-success", true); - } - }); + postFacebookLike(id); }, playMix:function () { var id = $(this.el).data("id"); diff --git a/static/js/app/views/user.js b/static/js/app/views/user.js index d660416..8cd2f5b 100644 --- a/static/js/app/views/user.js +++ b/static/js/app/views/user.js @@ -1,39 +1,73 @@ window.UserView = Backbone.View.extend({ events:{ "click #save-changes":"saveChanges", - "click input[type=radio]": "selectAvatar", - "change input" :"changed", - "change select" :"changed" + "click input[type=radio]":"selectAvatar", + "change input":"changed", + "change select":"changed", + "change .switch":"changeSwitch" }, initialize:function () { this.render(); }, render:function () { + var model = this.model; $(this.el).html(this.template({"item":this.model.toJSON()})); + $('.switch', this.el).each(function (item) { + var val = model.get(this.id) ? "on" : "off"; + $(this).attr('checked', val == "on"); + $(this).iphoneSwitch( + val, + function (obj) { + }, + function (obj) { + }, + {speed:250, use_images:false, track_bg_color:'#333', sync_checkbox:true} + ); + }); + $("#div_avatar_image", this.el).hide(); + $('#' + this.model.get('avatar_type'), this.el).attr('checked', 'checked'); + //console.clear(); return this; }, - saveChanges: function(){ + saveChanges:function () { this.model.save( - null,{ - success: function(){ - window.utils.showAlert("Success", "Successfully updated yourself", "alert-info", true); - window.history.back(); - }, - error: function(){ - window.utils.showAlert("Success", "Successfully updated yourself", "alert-info", false); - alert("Error"); - } - }); + null, { + success:function () { + window.utils.showAlert("Success", "Successfully updated yourself", "alert-info", true); + window.history.back(); + }, + error:function () { + window.utils.showAlert("Success", "Successfully updated yourself", "alert-info", false); + alert("Error"); + } + }); return false; }, - changed:function(evt) { + changeSwitch:function (evt) { + var bit = $(evt.currentTarget).data('bitflag'); + var coalesce = $(evt.currentTarget).data('coalesce'); + if ($(evt.currentTarget).attr('checked')) { + this.model.set(coalesce, this.model.get(coalesce) | bit); + } else { + this.model.set(coalesce, this.model.get(coalesce) & ~bit); + } + this.model.save(); + }, + changed:function (evt) { var changed = evt.currentTarget; - var value = $("#"+changed.id).val(); - var obj = "{\""+changed.id +"\":\""+value+"\"}"; + var value = $("#" + changed.id).val(); + var obj = "{\"" + changed.id + "\":\"" + value + "\"}"; var objInst = JSON.parse(obj); this.model.set(objInst); }, - selectAvatar: function(evt){ - this.model.set('avatar_type', $(evt.currentTarget).val()); + selectAvatar:function (evt) { + var type = $(evt.currentTarget).val(); + this.model.set('avatar_type', type); + if (type == 'custom') { + $("#div_avatar_image", this.el).show(); + $('#file_upload').uploadifive({ + 'uploadScript':'ajax/upload_avatar_image/' + }); + } } -}); \ No newline at end of file +}) diff --git a/static/js/libs/jquery.iphone-switch.js b/static/js/libs/jquery.iphone-switch.js new file mode 100644 index 0000000..c7b7398 --- /dev/null +++ b/static/js/libs/jquery.iphone-switch.js @@ -0,0 +1,239 @@ +/******************************************************* + * jQuery iphoneSwitch plugin v0.9 * + * * + * jquery.iphoneSwitch.js * + * Author: Ammon Casey * + * Website: http://www.brokenparadigmlabs.com * + * Hosted: http://github.com/ammonkc/iPhoneSwitch * + * Twitter: @ammonkc * + * Date: 5.17.2011 * + * * + * Copyright (c) 2010, Ammon Casey * + * licensed under the MIT license: * + * http://www.opensource.org/licenses/mit-license.php * + ********************************************************/ +(function($){ + jQuery.fn.iphoneSwitch = function(start_state, switched_on_callback, switched_off_callback, options) { + + var state = (start_state == 'on' ? true : false); + + // define default settings + var settings = { + track_class : 'track', + handle_class : 'handle', + label_class : 'label', + mouse_over : 'pointer', + mouse_out : 'default', + hide_checkbox : true, + sync_checkbox : true, + use_images : true, + speed : '250', + on_label : 'On', + off_label : 'Off', + switch_height : 28, + switch_width : 93, + switch_radius : 4, + track_img : '/static/img/switch_track.png', + track_bg_color : '#5f6777', + track_width : 93, + track_height : 27, + track_padding : 0, + track_dropshadow_color : 'rgba(255, 255, 255, 0.15)', + handle_img : '/static/img/switch_handle.png', + handle_bg_color : '#f9f9f9', + handle_border_color : '#d0d0d0', + handle_height : 25, + handle_width : 40, + label_color : "#ffffff", + label_font_size : 12 + }; + + if(options) { + jQuery.extend(settings, options); + } + + // create the switch + return this.each(function() { + var checkbox = jQuery(this); + if (!checkbox.is(':checkbox')) { return; } + + var container; + var track; + var handle; + var track_padding; + + // Hide the checkbox + if (settings.hide_checkbox) {checkbox.hide();} + + // sync checkbox state with switch state + if (settings.sync_checkbox) {state = checkbox.is(':checked')} + + // use images + if (settings.use_images) { + track_bg = 'url('+settings.track_img+')'; + handle_bg = 'url('+settings.handle_img+')'; + track_padding = settings.track_padding; + }else{ + track_bg = settings.track_bg_color; + handle_bg = settings.handle_bg_color; + // tweak padding for css only version + track_padding = settings.track_padding + 1; + } + + // Positions + var offset = (settings.track_width - track_padding) - settings.handle_width; + var left = (state ? offset : track_padding); + var right = (state ? track_padding : offset); + + /**** make the container ****/ + container = jQuery('
') + .addClass('switch-container') + .css({ + 'height':settings.switch_height, + 'width':settings.switch_width, + 'position':'relative', + 'overflow':'hidden', + 'font':"normal normal normal 12px/18px 'Lucida Grande', Verdana, sans-serif" + }); + /**** make the track ****/ + track = jQuery('
') + .addClass(settings.track_class) + .css({ + 'height':settings.track_height, + 'width':settings.track_width, + 'position':'absolute', + 'background-image':track_bg, + 'background-repeat':'no-repeat' + }); + + /**** Make the handle ****/ + handle = jQuery('
') + .addClass(settings.handle_class) + .css({ + 'height':settings.handle_height, + 'width':settings.handle_width, + 'left':left, + 'right':right, + 'top':1, + 'bottom':1, + 'position':'absolute', + 'background-image':handle_bg, + 'background-repeat':'no-repeat', + 'cursor':'pointer', + '-webkit-user-select':'none', + '-moz-user-select':'none', + '-o-user-select':'none', + 'user-select':'none' + }); + + /**** Make the labels ****/ + label_on = jQuery('') + .addClass(settings.label_class) + .addClass('left') + .text(settings.on_label) + .css({ + 'height':settings.handle_height, + 'width':settings.handle_width, + 'line-height':settings.track_height + 'px', + 'color':settings.label_color, + 'font-size':settings.label_font_size, + 'text-align':'center', + 'text-shadow':'#333 0px 1px 0px', + '-webkit-user-select':'none', + '-moz-user-select':'none', + '-o-user-select':'none', + 'user-select':'none', + 'cursor':'default', + 'float':'left' + }); + label_off = jQuery('') + .addClass(settings.label_class) + .addClass('right') + .text(settings.off_label) + .css({ + 'height':settings.handle_height, + 'width':settings.handle_width, + 'line-height':settings.track_height + 'px', + 'color':settings.label_color, + 'font-size':settings.label_font_size, + 'text-align':'center', + 'text-shadow':'#333 0px 1px 0px', + '-webkit-user-select':'none', + '-moz-user-select':'none', + '-o-user-select':'none', + 'user-select':'none', + 'cursor':'default', + 'position':'absolute', + 'top':1, + 'right':1, + 'bottom':1 + }); + // CSS3 - imagless + if (!settings.use_images) { + track.css({ + 'background-color':settings.track_bg_color, + '-webkit-border-radius':settings.switch_radius, + '-moz-border-radius':settings.switch_radius, + '-o-border-radius':settings.switch_radius, + 'border-radius':settings.switch_radius, + '-webkit-box-shadow': settings.track_dropshadow_color + ' 0px 1px 1px, rgba(1, 1, 1, 0.65) 0px 3px 6px inset', + '-moz-box-shadow': settings.track_dropshadow_color + ' 0px 1px 1px, rgba(1, 1, 1, 0.65) 0px 3px 6px inset', + '-o-box-shadow': settings.track_dropshadow_color + ' 0px 1px 1px, rgba(1, 1, 1, 0.65) 0px 3px 6px inset', + 'box-shadow': settings.track_dropshadow_color + ' 0px 1px 1px, rgba(1, 1, 1, 0.65) 0px 3px 6px inset', + '-webkit-background-clip':'padding-box', + 'background-clip':'padding-box' + }); + handle.css({ + 'background':'-webkit-gradient(linear, 0% 0%, 0% 100%, from(#fcfcfc), to(#e6e6e6))', + 'background-image':'-moz-linear-gradient(-90deg, #fcfcfc, #e6e6e6)', + 'background-color':settings.handle_bg_color, + '-webkit-border-radius':settings.switch_radius -1, + '-moz-border-radius':settings.switch_radius -1, + '-o-border-radius':settings.switch_radius -1, + 'border-radius':settings.switch_radius -1, + '-webkit-box-shadow':'rgba(255,255,255,1) 0px 0px 3px inset, rgba(0, 0, 0, 0.99) 0px 0px 3px', + '-moz-box-shadow':'rgba(255,255,255,1) 0px 0px 3px inset, rgba(0, 0, 0, 0.99) 0px 0px 3px', + '-o-box-shadow':'rgba(255,255,255,1) 0px 0px 3px inset, rgba(0, 0, 0, 0.99) 0px 0px 3px', + 'box-shadow':'rgba(255,255,255,1) 0px 0px 3px inset, rgba(0, 0, 0, 0.99) 0px 0px 3px', + '-webkit-background-clip':'padding-box', + 'background-clip':'padding-box' + }); + } + + /* insert into placeholder */ + checkbox.wrap(container); + track.append(label_on) + .append(label_off) + .append(handle); + checkbox.after(track); + + var mySwitch = checkbox.parent(); + + // click handling + jQuery(mySwitch).find('.' + settings.handle_class).click(function() { + var myHandle = jQuery(this); + var cb = myHandle.parent().siblings('input:checkbox'); + var checkd = cb.is('input:checked'); + var l = (checkd ? track_padding : offset); + var r = (checkd ? offset : track_padding); + var switched_callback = (checkd ? switched_off_callback : switched_on_callback); + // slide the handle + slide_handle(myHandle, l, r, settings.speed, switched_callback); + cb.attr('checked', (checkd ? false : true)).trigger('change'); + });//- END .click() + + });//- END .each() + }//- END $.fn.iphoneSwitch() + + /*** Private functions ***/ + function slide_handle(handle, left_pos, right_pos, speed, switch_callback) + { + jQuery(handle).animate({left: left_pos,right: right_pos}, speed, function() { + if (typeof switch_callback == 'function') + { + switch_callback.call(this); + }//- END if + });//- END animate + }//- END slide_handle() + +})(jQuery); \ No newline at end of file diff --git a/static/js/libs/uploadify/jquery.uploadifive.js b/static/js/libs/uploadify/jquery.uploadifive.js new file mode 100644 index 0000000..9928813 --- /dev/null +++ b/static/js/libs/uploadify/jquery.uploadifive.js @@ -0,0 +1,887 @@ +/* +UploadiFive 1.0.5 +Copyright (c) 2012 Reactive Apps, Ronnie Garcia +Released under the UploadiFive Standard License +*/ +;(function($) { + + var methods = { + + init : function(options) { + + return this.each(function() { + + // Create a reference to the jQuery DOM object + var $this = $(this); + $this.data('uploadifive', { + inputs : {}, // The object that contains all the file inputs + inputCount : 0, // The total number of file inputs created + fileID : 0, + queue : { + count : 0, // Total number of files in the queue + selected : 0, // Number of files selected in the last select operation + replaced : 0, // Number of files replaced in the last select operation + errors : 0, // Number of files that returned an error in the last select operation + queued : 0, // Number of files added to the queue in the last select operation + cancelled : 0 // Total number of files that have been cancelled or removed from the queue + }, + uploads : { + current : 0, // Number of files currently being uploaded + attempts : 0, // Number of file uploads attempted in the last upload operation + successful : 0, // Number of files successfully uploaded in the last upload operation + errors : 0, // Number of files returning errors in the last upload operation + count : 0 // Total number of files uploaded successfully + } + }); + var $data = $this.data('uploadifive'); + + // Set the default options + var settings = $data.settings = $.extend({ + 'auto' : true, // Automatically upload a file when it's added to the queue + 'buttonClass' : false, // A class to add to the UploadiFive button + 'buttonText' : 'Select Files', // The text that appears on the UploadiFive button + 'checkScript' : false, // Path to the script that checks for existing file names + 'dnd' : true, // Allow drag and drop into the queue + 'dropTarget' : false, // Selector for the drop target + 'fileSizeLimit' : 0, // Maximum allowed size of files to upload + 'fileType' : false, // Type of files allowed (image, etc) + 'formData' : {}, // Additional data to send to the upload script + 'height' : 30, // The height of the button + 'method' : 'post', // The method to use when submitting the upload + 'multi' : true, // Set to true to allow multiple file selections + 'overrideEvents' : [], // An array of events to override + 'queueID' : false, // The ID of the file queue + 'queueSizeLimit' : 0, // The maximum number of files that can be in the queue + 'removeCompleted' : false, // Set to true to remove files that have completed uploading + 'simUploadLimit' : 0, // The maximum number of files to upload at once + 'truncateLength' : 0, // The length to truncate the file names to + 'uploadLimit' : 0, // The maximum number of files you can upload + 'uploadScript' : 'uploadifive.php', // The path to the upload script + 'width' : 100 // The width of the button + + /* + // Events + 'onAddQueueItem' : function(file) {}, // Triggered for each file that is added to the queue + 'onCancel' : function(file) {}, // Triggered when a file is cancelled or removed from the queue + 'onCheck' : function(file, exists) {}, // Triggered when the server is checked for an existing file + 'onClearQueue' : function(queue) {}, // Triggered during the clearQueue function + 'onDestroy' : function() {} // Triggered during the destroy function + 'onDrop' : function(files, numberOfFilesDropped) {}, // Triggered when files are dropped into the file queue + 'onError' : function(file, fileType, data) {}, // Triggered when an error occurs + 'onFallback' : function() {}, // Triggered if the HTML5 File API is not supported by the browser + 'onInit' : function() {}, // Triggered when UploadiFive if initialized + 'onQueueComplete' : function() {}, // Triggered once when an upload queue is done + 'onProgress' : function(file, event) {}, // Triggered during each progress update of an upload + 'onSelect' : function() {}, // Triggered once when files are selected from a dialog box + 'onUpload' : function(file) {}, // Triggered when an upload queue is started + 'onUploadComplete' : function(file, data) {}, // Triggered when a file is successfully uploaded + 'onUploadFile' : function(file) {}, // Triggered for each file being uploaded + */ + }, options); + + // Calculate the file size limit + if (isNaN(settings.fileSizeLimit)) { + var fileSizeLimitBytes = parseInt(settings.fileSizeLimit) * 1.024 + if (settings.fileSizeLimit.indexOf('KB') > -1) { + settings.fileSizeLimit = fileSizeLimitBytes * 1000; + } else if (settings.fileSizeLimit.indexOf('MB') > -1) { + settings.fileSizeLimit = fileSizeLimitBytes * 1000000; + } else if (settings.fileSizeLimit.indexOf('GB') > -1) { + settings.fileSizeLimit = fileSizeLimitBytes * 1000000000; + } + } else { + settings.fileSizeLimit = settings.fileSizeLimit * 1024; + } + + // Create a template for a file input + $data.inputTemplate = $('') + .css({ + 'opacity' : 0, + 'position' : 'absolute', + 'z-index' : 999 + }); + + // Create a new input + $data.createInput = function() { + + // Create a clone of the file input + var input = $data.inputTemplate.clone(); + // Create a unique name for the input item + var inputName = input.name = 'input' + $data.inputCount++; + // Set the multiple attribute + if (settings.multi) { + input.attr('multiple', true); + } + // Set the onchange event for the input + input.bind('change', function() { + $data.queue.selected = 0; + $data.queue.replaced = 0; + $data.queue.errors = 0; + $data.queue.queued = 0; + // Add a queue item to the queue for each file + var limit = this.files.length; + $data.queue.selected = limit; + if (($data.queue.count + limit) > settings.queueSizeLimit && settings.queueSizeLimit !== 0) { + if ($.inArray('onError', settings.overrideEvents) < 0) { + alert('The maximum number of queue items has been reached (' + settings.queueSizeLimit + '). Please select fewer files.'); + } + // Trigger the error event + if (typeof settings.onError === 'function') { + settings.onError.call($this, 'QUEUE_LIMIT_EXCEEDED'); + } + } else { + for (var n = 0; n < limit; n++) { + file = this.files[n]; + $data.addQueueItem(file); + } + $data.inputs[inputName] = this; + $data.createInput(); + } + // Upload the file if auto-uploads are enabled + if (settings.auto) { + methods.upload.call($this); + } + // Trigger the select event + if (typeof settings.onSelect === 'function') { + settings.onSelect.call($this, $data.queue); + } + }); + // Hide the existing current item and add the new one + if ($data.currentInput) { + $data.currentInput.hide(); + } + $data.button.append(input); + $data.currentInput = input; + } + + // Remove an input + $data.destroyInput = function(key) { + $($data.inputs[key]).remove(); + delete $data.inputs[key]; + $data.inputCount--; + } + + // Drop a file into the queue + $data.drop = function(e) { + $data.queue.selected = 0; + $data.queue.replaced = 0; + $data.queue.errors = 0; + $data.queue.queued = 0; + + var fileData = e.dataTransfer; + + var inputName = fileData.name = 'input' + $data.inputCount++; + // Add a queue item to the queue for each file + var limit = fileData.files.length; + $data.queue.selected = limit; + if (($data.queue.count + limit) > settings.queueSizeLimit && settings.queueSizeLimit !== 0) { + // Check if the queueSizeLimit was reached + if ($.inArray('onError', settings.overrideEvents) < 0) { + alert('The maximum number of queue items has been reached (' + settings.queueSizeLimit + '). Please select fewer files.'); + } + // Trigger the onError event + if (typeof settings.onError === 'function') { + settings.onError.call($this, 'QUEUE_LIMIT_EXCEEDED'); + } + } else { + // Add a queue item for each file + for (var n = 0; n < limit; n++) { + file = fileData.files[n]; + $data.addQueueItem(file); + } + // Save the data to the inputs object + $data.inputs[inputName] = fileData; + } + + // Upload the file if auto-uploads are enabled + if (settings.auto) { + methods.upload.call($this); + } + + // Trigger the onDrop event + if (typeof settings.onDrop === 'function') { + settings.onDrop.call($this, fileData.files, fileData.files.length); + } + + // Stop FireFox from opening the dropped file(s) + e.preventDefault(); + e.stopPropagation(); + } + + // Check if a filename exists in the queue + $data.fileExistsInQueue = function(file) { + for (var key in $data.inputs) { + input = $data.inputs[key]; + limit = input.files.length; + for (var n = 0; n < limit; n++) { + existingFile = input.files[n]; + // Check if the filename matches + if (existingFile.name == file.name && !existingFile.complete) { + return true; + } + } + } + return false; + } + + // Remove an existing file in the queue + $data.removeExistingFile = function(file) { + for (var key in $data.inputs) { + input = $data.inputs[key]; + limit = input.files.length; + for (var n = 0; n < limit; n++) { + existingFile = input.files[n]; + // Check if the filename matches + if (existingFile.name == file.name && !existingFile.complete) { + $data.queue.replaced++; + methods.cancel.call($this, existingFile, true); + } + } + } + } + + // Queue item template + $data.queueItem = $('
\ + X\ +
\ +
\ +
\ +
\ +
'); + + // Add an item to the queue + $data.addQueueItem = function(file) { + if ($.inArray('onAddQueueItem', settings.overrideEvents) < 0) { + // Check if the filename already exists in the queue + $data.removeExistingFile(file); + // Create a clone of the queue item template + file.queueItem = $data.queueItem.clone(); + // Add an ID to the queue item + file.queueItem.attr('id', settings.id + '-file-' + $data.fileID++); + // Bind the close event to the close button + file.queueItem.find('.close').bind('click', function() { + methods.cancel.call($this, file); + return false; + }); + var fileName = file.name; + if (fileName.length > settings.truncateLength && settings.truncateLength != 0) { + fileName = fileName.substring(0, settings.truncateLength) + '...'; + } + file.queueItem.find('.filename').html(fileName); + // Add a reference to the file + file.queueItem.data('file', file); + $data.queueEl.append(file.queueItem); + } + // Trigger the addQueueItem event + if (typeof settings.onAddQueueItem === 'function') { + settings.onAddQueueItem.call($this, file); + } + // Check the filetype + if (settings.fileType) { + if ($.isArray(settings.fileType)) { + var isValidFileType = false; + for (var n = 0; n < settings.fileType.length; n++) { + if (file.type.indexOf(settings.fileType[n]) > -1) { + isValidFileType = true; + } + } + if (!isValidFileType) { + $data.error('FORBIDDEN_FILE_TYPE', file); + } + } else { + if (file.type.indexOf(settings.fileType) < 0) { + $data.error('FORBIDDEN_FILE_TYPE', file); + } + } + } + // Check the filesize + if (file.size > settings.fileSizeLimit && settings.fileSizeLimit != 0) { + $data.error('FILE_SIZE_LIMIT_EXCEEDED', file); + } else { + $data.queue.queued++; + $data.queue.count++; + } + } + + // Remove an item from the queue + $data.removeQueueItem = function(file, instant, delay) { + // Set the default delay + if (!delay) delay = 0; + var fadeTime = instant ? 0 : 500; + if (file.queueItem) { + if (file.queueItem.find('.fileinfo').html() != ' - Completed') { + file.queueItem.find('.fileinfo').html(' - Cancelled'); + } + file.queueItem.find('.progress-bar').width(0); + file.queueItem.delay(delay).fadeOut(fadeTime, function() { + $(this).remove(); + }); + delete file.queueItem; + $data.queue.count--; + } + } + + // Count the number of files that need to be uploaded + $data.filesToUpload = function() { + var filesToUpload = 0; + for (var key in $data.inputs) { + input = $data.inputs[key]; + limit = input.files.length; + for (var n = 0; n < limit; n++) { + file = input.files[n]; + if (!file.skip && !file.complete) { + filesToUpload++; + } + } + } + return filesToUpload; + } + + // Check if a file exists + $data.checkExists = function(file) { + if ($.inArray('onCheck', settings.overrideEvents) < 0) { + // This request needs to be synchronous + $.ajaxSetup({ + 'async' : false + }); + // Send the filename to the check script + var checkData = $.extend(settings.formData, {filename: file.name}); + $.post(settings.checkScript, checkData, function(fileExists) { + file.exists = parseInt(fileExists); + }); + if (file.exists) { + if (!confirm('A file named ' + file.name + ' already exists in the upload folder.\nWould you like to replace it?')) { + // If not replacing the file, cancel the upload + methods.cancel.call($this, file); + return true; + } + } + } + // Trigger the check event + if (typeof settings.onCheck === 'function') { + settings.onCheck.call($this, file, file.exists); + } + return false; + } + + // Upload a single file + $data.uploadFile = function(file, uploadAll) { + if (!file.skip && !file.complete && !file.uploading) { + file.uploading = true; + $data.uploads.current++; + $data.uploads.attempted++; + + // Create a new AJAX request + xhr = file.xhr = new XMLHttpRequest(); + + // Start the upload + // Use the faster FormData if it exists + if (typeof FormData === 'function' || typeof FormData === 'object') { + + // Create a new FormData object + var formData = new FormData(); + + // Add the form data + formData.append('Filedata', file); + + // Add the rest of the formData + for (i in settings.formData) { + formData.append(i, settings.formData[i]); + } + + // Open the AJAX call + xhr.open(settings.method, settings.uploadScript, true); + + // On progress function + xhr.upload.addEventListener('progress', function(e) { + if (e.lengthComputable) { + $data.progress(e, file); + } + }, false); + + // On complete function + xhr.addEventListener('load', function(e) { + if (this.readyState == 4) { + file.uploading = false; + if (this.status == 200) { + if (file.xhr.responseText !== 'Invalid file type.') { + $data.uploadComplete(e, file, uploadAll); + } else { + $data.error(file.xhr.responseText, file, uploadAll); + } + } else if (this.status == 404) { + $data.error('404_FILE_NOT_FOUND', file, uploadAll); + } else if (this.status == 403) { + $data.error('403_FORBIDDEN', file, uplaodAll); + } else { + $data.error('Unknown Error', file, uploadAll); + } + } + }); + + // Send the form data (multipart/form-data) + xhr.send(formData); + + } else { + + // Send as binary + var reader = new FileReader(); + reader.onload = function(e) { + + // Set some file builder variables + var boundary = '-------------------------' + (new Date).getTime(), + dashes = '--', + eol = '\r\n', + binFile = ''; + + // Build an RFC2388 String + binFile += dashes + boundary + eol; + // Generate the headers + binFile += 'Content-Disposition: form-data; name="Filedata"'; + if (file.name) { + binFile += '; filename="' + file.name + '"'; + } + binFile += eol; + binFile += 'Content-Type: application/octet-stream' + eol + eol; + binFile += e.target.result + eol; + + for (key in settings.formData) { + binFile += dashes + boundary + eol; + binFile += 'Content-Disposition: form-data; name="' + key + '"' + eol + eol; + binFile += settings.formData[key] + eol; + } + + binFile += dashes + boundary + dashes + eol; + + // On progress function + xhr.upload.addEventListener('progress', function(e) { + $data.progress(e, file); + }, false); + + // On complete function + xhr.addEventListener('load', function(e) { + file.uploading = false; + var status = this.status; + if (status == 404) { + $data.error('404_FILE_NOT_FOUND', file, uploadAll); + } else { + if (file.xhr.responseText != 'Invalid file type.') { + $data.uploadComplete(e, file, uploadAll); + } else { + $data.error(file.xhr.responseText, file, uploadAll); + } + } + }, false); + + // Open the ajax request + var url = settings.uploadScript; + if (settings.method == 'get') { + var params = $(settings.formData).param(); + url += params; + } + xhr.open(settings.method, settings.uploadScript, true); + xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); + + // Trigger the uploadFile event + if (typeof settings.onUploadFile === 'function') { + settings.onUploadFile.call($this, file); + } + + // Send the file for upload + xhr.sendAsBinary(binFile); + } + reader.readAsBinaryString(file); + + } + } + } + + // Update a file upload's progress + $data.progress = function(e, file) { + if ($.inArray('onProgress', settings.overrideEvents) < 0) { + if (e.lengthComputable) { + var percent = Math.round((e.loaded / e.total) * 100); + } + file.queueItem.find('.fileinfo').html(' - ' + percent + '%'); + file.queueItem.find('.progress-bar').css('width', percent + '%'); + } + // Trigger the progress event + if (typeof settings.onProgress === 'function') { + settings.onProgress.call($this, file, e); + } + } + + // Trigger an error + $data.error = function(errorType, file, uploadAll) { + if ($.inArray('onError', settings.overrideEvents) < 0) { + // Get the error message + switch(errorType) { + case '404_FILE_NOT_FOUND': + errorMsg = '404 Error'; + break; + case '403_FORBIDDEN': + errorMsg = '403 Forbidden'; + break; + case 'FORBIDDEN_FILE_TYPE': + errorMsg = 'Forbidden File Type'; + break; + case 'FILE_SIZE_LIMIT_EXCEEDED': + errorMsg = 'File Too Large'; + break; + default: + errorMsg = 'Unknown Error'; + break; + } + + // Add the error class to the queue item + file.queueItem.addClass('error') + // Output the error in the queue item + .find('.fileinfo').html(' - ' + errorMsg); + // Hide the + file.queueItem.find('.progress').remove(); + } + // Trigger the error event + if (typeof settings.onError === 'function') { + settings.onError.call($this, errorType, file); + } + file.skip = true; + if (errorType == '404_FILE_NOT_FOUND') { + $data.uploads.errors++; + } else { + $data.queue.errors++; + } + if (uploadAll) { + methods.upload.call($this, null, true); + } + } + + // Trigger when a single file upload is complete + $data.uploadComplete = function(e, file, uploadAll) { + if ($.inArray('onUploadComplete', settings.overrideEvents) < 0) { + file.queueItem.find('.progress-bar').css('width', '100%'); + file.queueItem.find('.fileinfo').html(' - Completed'); + file.queueItem.find('.progress').slideUp(250); + file.queueItem.addClass('complete'); + } + // Trigger the complete event + if (typeof settings.onUploadComplete === 'function') { + settings.onUploadComplete.call($this, file, file.xhr.responseText); + } + if (settings.removeCompleted) { + setTimeout(function() { methods.cancel.call($this, file); }, 3000); + } + file.complete = true; + $data.uploads.successful++; + $data.uploads.count++; + $data.uploads.current--; + delete file.xhr; + if (uploadAll) { + methods.upload.call($this, null, true); + } + } + + // Trigger when all the files are done uploading + $data.queueComplete = function() { + // Trigger the queueComplete event + if (typeof settings.onQueueComplete === 'function') { + settings.onQueueComplete.call($this, $data.uploads); + } + } + + // ---------------------- + // Initialize UploadiFive + // ---------------------- + + // Check if HTML5 is available + if (window.File && window.FileList && window.Blob && (window.FileReader || window.FormData)) { + // Assign an ID to the object + settings.id = 'uploadifive-' + $this.attr('id'); + + // Wrap the file input in a div with overflow set to hidden + $data.button = $('
' + settings.buttonText + '
'); + if (settings.buttonClass) $data.button.addClass(settings.buttonClass); + + // Style the button wrapper + $data.button.css({ + 'height' : settings.height, + 'line-height' : settings.height + 'px', + 'overflow' : 'hidden', + 'position' : 'relative', + 'text-align' : 'center', + 'width' : settings.width + }); + + // Insert the button above the file input + $this.before($data.button) + // Add the file input to the button + .appendTo($data.button) + // Modify the styles of the file input + .hide(); + + // Create a new input + $data.createInput.call($this); + + // Position the browse files button under the cursor + $data.button.mousemove(function(e) { + var offset = $data.button.offset(); + $data.currentInput.css({ + 'left' : e.pageX - offset.left - $this.width() + 10, + 'top' : e.pageY - offset.top - $this.height() + 10 + }); + }); + + // Create the queue container + if (!settings.queueID) { + settings.queueID = settings.id + '-queue'; + $data.queueEl = $('
'); + $data.button.after($data.queueEl); + } else { + $data.queueEl = $('#' + settings.queueID); + } + + // Add drag and drop functionality + if (settings.dnd) { + var $dropTarget = settings.dropTarget ? $(settings.dropTarget) : $data.queueEl.get(0); + $dropTarget.addEventListener('dragleave', function(e) { + // Stop FireFox from opening the dropped file(s) + e.preventDefault(); + e.stopPropagation(); + }, false); + $dropTarget.addEventListener('dragenter', function(e) { + // Stop FireFox from opening the dropped file(s) + e.preventDefault(); + e.stopPropagation(); + }, false); + $dropTarget.addEventListener('dragover', function(e) { + // Stop FireFox from opening the dropped file(s) + e.preventDefault(); + e.stopPropagation(); + }, false); + $dropTarget.addEventListener('drop', $data.drop, false); + } + + // Send as binary workaround for Chrome + if (!XMLHttpRequest.prototype.sendAsBinary) { + XMLHttpRequest.prototype.sendAsBinary = function(datastr) { + function byteValue(x) { + return x.charCodeAt(0) & 0xff; + } + var ords = Array.prototype.map.call(datastr, byteValue); + var ui8a = new Uint8Array(ords); + this.send(ui8a.buffer); + } + } + + // Trigger the oninit event + if (typeof settings.onInit === 'function') { + settings.onInit.call($this); + } + + } else { + + // Trigger the fallback event + if (typeof settings.onFallback === 'function') { + settings.onFallback.call($this); + } + return false; + + } + + }); + + }, + + + // Write some data to the console + debug : function() { + + return this.each(function() { + + console.log($(this).data('uploadifive')); + + }); + + }, + + // Clear all the items from the queue + clearQueue : function() { + + this.each(function() { + + var $this = $(this), + $data = $this.data('uploadifive'), + settings = $data.settings; + + for (var key in $data.inputs) { + input = $data.inputs[key]; + limit = input.files.length; + for (i = 0; i < limit; i++) { + file = input.files[i]; + methods.cancel.call($this, file); + } + } + // Trigger the onClearQueue event + if (typeof settings.onClearQueue === 'function') { + settings.onClearQueue.call($this, $('#' + $data.options.queueID)); + } + + }); + + }, + + // Cancel a file upload in progress or remove a file from the queue + cancel : function(file, fast) { + + this.each(function() { + + var $this = $(this), + $data = $this.data('uploadifive'), + settings = $data.settings; + + // If user passed a queue item ID instead of file... + if (typeof file === 'string') { + if (!isNaN(file)) { + fileID = 'uploadifive-' + $(this).attr('id') + '-file-' + file; + } + file = $('#' + fileID).data('file'); + } + + file.skip = true; + $data.filesCancelled++; + if (file.uploading) { + $data.uploads.current--; + file.uploading = false; + file.xhr.abort(); + delete file.xhr; + methods.upload.call($this); + } + if ($.inArray('onCancel', settings.overrideEvents) < 0) { + $data.removeQueueItem(file, fast); + } + + // Trigger the cancel event + if (typeof settings.onCancel === 'function') { + settings.onCancel.call($this, file); + } + + }); + + }, + + // Upload the files in the queue + upload : function(file, keepVars) { + + this.each(function() { + + var $this = $(this), + $data = $this.data('uploadifive'), + settings = $data.settings; + + if (file) { + + $data.uploadFile.call($this, file); + + } else { + + // Check if the upload limit was reached + if (($data.uploads.count + $data.uploads.current) < settings.uploadLimit || settings.uploadLimit == 0) { + if (!keepVars) { + $data.uploads.attempted = 0; + $data.uploads.successsful = 0; + $data.uploads.errors = 0; + var filesToUpload = $data.filesToUpload(); + // Trigger the onUpload event + if (typeof settings.onUpload === 'function') { + settings.onUpload.call($this, filesToUpload); + } + } + + // Loop through the files + $('#' + settings.queueID).find('.uploadifive-queue-item').not('.error, .complete').each(function() { + _file = $(this).data('file'); + // Check if the simUpload limit was reached + if (($data.uploads.current >= settings.simUploadLimit && settings.simUploadLimit !== 0) || ($data.uploads.current >= settings.uploadLimit && settings.uploadLimit !== 0) || ($data.uploads.count >= settings.uploadLimit && settings.uploadLimit !== 0)) { + return false; + } + if (settings.checkScript) { + // Let the loop know that we're already processing this file + _file.checking = true; + skipFile = $data.checkExists(_file); + _file.checking = false; + if (!skipFile) { + $data.uploadFile(_file, true); + } + } else { + $data.uploadFile(_file, true); + } + }); + if ($('#' + settings.queueID).find('.uploadifive-queue-item').not('.error, .complete').size() == 0) { + $data.queueComplete(); + } + } else { + if ($data.uploads.current == 0) { + if ($.inArray('onError', settings.overrideEvents) < 0) { + if ($data.filesToUpload() > 0 && settings.uploadLimit != 0) { + alert('The maximum upload limit has been reached.'); + } + } + // Trigger the onError event + if (typeof settings.onError === 'function') { + settings.onError.call($this, 'UPLOAD_LIMIT_EXCEEDED', $data.filesToUpload()); + } + } + } + + } + + }); + + }, + + // Destroy an instance of UploadiFive + destroy : function() { + + this.each(function() { + + var $this = $(this), + $data = $this.data('uploadifive'), + settings = $data.settings; + + // Clear the queue + methods.clearQueue.call($this); + // Destroy the queue if it was created + if (!settings.queueID) $('#' + settings.queueID).remove(); + // Remove extra inputs + $this.siblings('input').remove(); + // Show the original file input + $this.show() + // Move the file input out of the button + .insertBefore($data.button); + // Delete the button + $data.button.remove(); + // Trigger the destroy event + if (typeof settings.onDestroy === 'function') { + settings.onDestroy.call($this); + } + + }); + + } + + } + + $.fn.uploadifive = function(method) { + + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method) { + return methods.init.apply(this, arguments); + } else { + $.error('The method ' + method + ' does not exist in $.uploadify'); + } + + } + +})(jQuery); + +/* I gave the queueItems IDs and they each have a reference to the file held in the 'data' obj. */ \ No newline at end of file diff --git a/static/js/libs/uploadify/jquery.uploadifive.min.js b/static/js/libs/uploadify/jquery.uploadifive.min.js new file mode 100644 index 0000000..2155fb9 --- /dev/null +++ b/static/js/libs/uploadify/jquery.uploadifive.min.js @@ -0,0 +1,6 @@ +/* +UploadiFive 1.0.5 +Copyright (c) 2012 Reactive Apps, Ronnie Garcia +Released under the UploadiFive Standard License +*/ +;(function(b){var a={init:function(c){return this.each(function(){var g=b(this);g.data("uploadifive",{inputs:{},inputCount:0,fileID:0,queue:{count:0,selected:0,replaced:0,errors:0,queued:0,cancelled:0},uploads:{current:0,attempts:0,successful:0,errors:0,count:0}});var d=g.data("uploadifive");var f=d.settings=b.extend({auto:true,buttonClass:false,buttonText:"Select Files",checkScript:false,dnd:true,dropTarget:false,fileSizeLimit:0,fileType:false,formData:{},height:30,method:"post",multi:true,overrideEvents:[],queueID:false,queueSizeLimit:0,removeCompleted:false,simUploadLimit:0,truncateLength:0,uploadLimit:0,uploadScript:"uploadifive.php",width:100},c);if(isNaN(f.fileSizeLimit)){var e=parseInt(f.fileSizeLimit)*1.024;if(f.fileSizeLimit.indexOf("KB")>-1){f.fileSizeLimit=e*1000;}else{if(f.fileSizeLimit.indexOf("MB")>-1){f.fileSizeLimit=e*1000000;}else{if(f.fileSizeLimit.indexOf("GB")>-1){f.fileSizeLimit=e*1000000000;}}}}else{f.fileSizeLimit=f.fileSizeLimit*1024;}d.inputTemplate=b('').css({opacity:0,position:"absolute","z-index":999});d.createInput=function(){var j=d.inputTemplate.clone();var k=j.name="input"+d.inputCount++;if(f.multi){j.attr("multiple",true);}j.bind("change",function(){d.queue.selected=0;d.queue.replaced=0;d.queue.errors=0;d.queue.queued=0;var l=this.files.length;d.queue.selected=l;if((d.queue.count+l)>f.queueSizeLimit&&f.queueSizeLimit!==0){if(b.inArray("onError",f.overrideEvents)<0){alert("The maximum number of queue items has been reached ("+f.queueSizeLimit+"). Please select fewer files.");}if(typeof f.onError==="function"){f.onError.call(g,"QUEUE_LIMIT_EXCEEDED");}}else{for(var m=0;mf.queueSizeLimit&&f.queueSizeLimit!==0){if(b.inArray("onError",f.overrideEvents)<0){alert("The maximum number of queue items has been reached ("+f.queueSizeLimit+"). Please select fewer files.");}if(typeof f.onError==="function"){f.onError.call(g,"QUEUE_LIMIT_EXCEEDED");}}else{for(var o=0;o X
');d.addQueueItem=function(k){if(b.inArray("onAddQueueItem",f.overrideEvents)<0){d.removeExistingFile(k);k.queueItem=d.queueItem.clone();k.queueItem.attr("id",f.id+"-file-"+d.fileID++);k.queueItem.find(".close").bind("click",function(){a.cancel.call(g,k);return false;});var m=k.name;if(m.length>f.truncateLength&&f.truncateLength!=0){m=m.substring(0,f.truncateLength)+"...";}k.queueItem.find(".filename").html(m);k.queueItem.data("file",k);d.queueEl.append(k.queueItem);}if(typeof f.onAddQueueItem==="function"){f.onAddQueueItem.call(g,k);}if(f.fileType){if(b.isArray(f.fileType)){var j=false;for(var l=0;l-1){j=true;}}if(!j){d.error("FORBIDDEN_FILE_TYPE",k);}}else{if(k.type.indexOf(f.fileType)<0){d.error("FORBIDDEN_FILE_TYPE",k);}}}if(k.size>f.fileSizeLimit&&f.fileSizeLimit!=0){d.error("FILE_SIZE_LIMIT_EXCEEDED",k);}else{d.queue.queued++;d.queue.count++;}};d.removeQueueItem=function(m,l,k){if(!k){k=0;}var j=l?0:500;if(m.queueItem){if(m.queueItem.find(".fileinfo").html()!=" - Completed"){m.queueItem.find(".fileinfo").html(" - Cancelled");}m.queueItem.find(".progress-bar").width(0);m.queueItem.delay(k).fadeOut(j,function(){b(this).remove();});delete m.queueItem;d.queue.count--;}};d.filesToUpload=function(){var k=0;for(var j in d.inputs){input=d.inputs[j];limit=input.files.length;for(var l=0;l'+f.buttonText+"
");if(f.buttonClass){d.button.addClass(f.buttonClass);}d.button.css({height:f.height,"line-height":f.height+"px",overflow:"hidden",position:"relative","text-align":"center",width:f.width});g.before(d.button).appendTo(d.button).hide();d.createInput.call(g);d.button.mousemove(function(j){var k=d.button.offset();d.currentInput.css({left:j.pageX-k.left-g.width()+10,top:j.pageY-k.top-g.height()+10});});if(!f.queueID){f.queueID=f.id+"-queue";d.queueEl=b('
');d.button.after(d.queueEl);}else{d.queueEl=b("#"+f.queueID);}if(f.dnd){var h=f.dropTarget?b(f.dropTarget):d.queueEl.get(0);h.addEventListener("dragleave",function(j){j.preventDefault();j.stopPropagation();},false);h.addEventListener("dragenter",function(j){j.preventDefault();j.stopPropagation();},false);h.addEventListener("dragover",function(j){j.preventDefault();j.stopPropagation();},false);h.addEventListener("drop",d.drop,false);}if(!XMLHttpRequest.prototype.sendAsBinary){XMLHttpRequest.prototype.sendAsBinary=function(k){function l(n){return n.charCodeAt(0)&255;}var m=Array.prototype.map.call(k,l);var j=new Uint8Array(m);this.send(j.buffer);};}if(typeof f.onInit==="function"){f.onInit.call(g);}}else{if(typeof f.onFallback==="function"){f.onFallback.call(g);}return false;}});},debug:function(){return this.each(function(){console.log(b(this).data("uploadifive"));});},clearQueue:function(){this.each(function(){var f=b(this),c=f.data("uploadifive"),e=c.settings;for(var d in c.inputs){input=c.inputs[d];limit=input.files.length;for(i=0;i=f.simUploadLimit&&f.simUploadLimit!==0)||(e.uploads.current>=f.uploadLimit&&f.uploadLimit!==0)||(e.uploads.count>=f.uploadLimit&&f.uploadLimit!==0)){return false;}if(f.checkScript){_file.checking=true;skipFile=e.checkExists(_file);_file.checking=false;if(!skipFile){e.uploadFile(_file,true);}}else{e.uploadFile(_file,true);}});if(b("#"+f.queueID).find(".uploadifive-queue-item").not(".error, .complete").size()==0){e.queueComplete();}}else{if(e.uploads.current==0){if(b.inArray("onError",f.overrideEvents)<0){if(e.filesToUpload()>0&&f.uploadLimit!=0){alert("The maximum upload limit has been reached.");}}if(typeof f.onError==="function"){f.onError.call(h,"UPLOAD_LIMIT_EXCEEDED",e.filesToUpload());}}}}});},destroy:function(){this.each(function(){var e=b(this),c=e.data("uploadifive"),d=c.settings;a.clearQueue.call(e);if(!d.queueID){b("#"+d.queueID).remove();}e.siblings("input").remove();e.show().insertBefore(c.button);c.button.remove();if(typeof d.onDestroy==="function"){d.onDestroy.call(e);}});}};b.fn.uploadifive=function(c){if(a[c]){return a[c].apply(this,Array.prototype.slice.call(arguments,1));}else{if(typeof c==="object"||!c){return a.init.apply(this,arguments);}else{b.error("The method "+c+" does not exist in $.uploadify");}}};})(jQuery); \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index ee21c1b..cdd5f27 100644 --- a/templates/base.html +++ b/templates/base.html @@ -22,10 +22,13 @@ + + + @@ -49,7 +52,6 @@ {% include 'inc/facebook_init.html' %} {% include 'inc/ancient_browser.html' %} -
@@ -87,6 +89,7 @@ + @@ -104,6 +107,7 @@ + {% block footerscripts %} {% endblock %} diff --git a/templates/inc/_MixItemInsert.html b/templates/inc/_MixItemInsert.html index 8333fa4..a8eb7e5 100644 --- a/templates/inc/_MixItemInsert.html +++ b/templates/inc/_MixItemInsert.html @@ -1,11 +1,9 @@
- {% if model.has_image %}
mix-logo
- {% endif %}

<%= item.title %>

diff --git a/templates/inc/facebook_init.html b/templates/inc/facebook_init.html index 24c603e..ce23250 100644 --- a/templates/inc/facebook_init.html +++ b/templates/inc/facebook_init.html @@ -19,4 +19,5 @@ js.src = "//connect.facebook.net/en_US/all.js"; ref.parentNode.insertBefore(js, ref); }(document)); - \ No newline at end of file + +
\ No newline at end of file diff --git a/templates/views/UserView.html b/templates/views/UserView.html index 2c457d1..bcba7ac 100644 --- a/templates/views/UserView.html +++ b/templates/views/UserView.html @@ -1,66 +1,112 @@ -
- {% csrf_token %} -
- User details -
- +
+ +
+
+ + {% csrf_token %} +
+
+
+ -
- -
-
-
- +
+ +
+
+
+ -
- -
-
-
- +
+ +
+
+
+ -
- -
-
-
- +
+ +
+
+
+ -
- -
-
-
- +
+ +
+
+
+ -
- - - +
+ + + +
+
+
+
+ + {% csrf_token %} + + +
+
-
-
-
- + +
+
+

Share this activity

+
    +
  • +
    Likes
    + +
  • +
  • +
    Favourites
    + +
  • +
  • +
    Comments
    + +
  • +
+
+
+

On these networks

+
    +
  • +
    Facebook
    + +
  • +
  • +
    Twitter
    + +
  • +
+
+
+
+
-
-
- ‌ -
- + +
\ No newline at end of file