diff --git a/rowers/admin.py b/rowers/admin.py
index e814d391..ea7a79ce 100644
--- a/rowers/admin.py
+++ b/rowers/admin.py
@@ -4,7 +4,8 @@ from django.contrib.auth.models import User
from .models import (
Rower, Workout,GraphImage,FavoriteChart,SiteAnnouncement,
- Team,TeamInvite,TeamRequest
+ Team,TeamInvite,TeamRequest,
+ WorkoutComment,
)
# Register your models here so you can use them in the Admin module
@@ -36,6 +37,9 @@ class TeamInviteAdmin(admin.ModelAdmin):
class TeamRequestAdmin(admin.ModelAdmin):
list_display = ('issuedate','team','user','code')
+
+class WorkoutCommentAdmin(admin.ModelAdmin):
+ list_display = ('created','user','workout')
admin.site.unregister(User)
admin.site.register(User,UserAdmin)
@@ -46,3 +50,4 @@ admin.site.register(FavoriteChart,FavoriteChartAdmin)
admin.site.register(SiteAnnouncement,SiteAnnouncementAdmin)
admin.site.register(TeamInvite,TeamInviteAdmin)
admin.site.register(TeamRequest,TeamRequestAdmin)
+admin.site.register(WorkoutComment,WorkoutCommentAdmin)
diff --git a/rowers/models.py b/rowers/models.py
index af9aa4ff..c1dd3bbb 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -855,21 +855,6 @@ class RowerForm(ModelForm):
if an>=max:
raise forms.ValidationError("AN should be lower than Max")
-# A comment by a user on a training
-class WorkoutComment(models.Model):
- created = models.DateField(default=timezone.now)
- comment = models.TextField(max_length=300)
- read = models.BooleanField(default=False)
- user = models.ForeignKey(User)
- workout = models.ForeignKey(Workout)
-
-class WorkoutCommentForm(ModelForm):
- class Meta:
- model = WorkoutComment
- fields = ['comment']
- widgets = {
- 'comment': forms.Textarea,
- }
# An announcement that goes to the right of the workouts list
# optionally sends a tweet to our twitter account
@@ -894,3 +879,28 @@ class SiteAnnouncement(models.Model):
except:
pass
return super(SiteAnnouncement,self).save(*args, **kwargs)
+
+# A comment by a user on a training
+class WorkoutComment(models.Model):
+ comment = models.TextField(max_length=300)
+ created = models.DateTimeField(default=timezone.now)
+ read = models.BooleanField(default=False)
+ user = models.ForeignKey(User)
+ workout = models.ForeignKey(Workout)
+
+ def __unicode__(self):
+ return u'Comment to: {w} by {u1} {u2}'.format(
+ w=self.workout.name,
+ u1 = self.user.first_name,
+ u2 = self.user.last_name,
+ )
+
+
+class WorkoutCommentForm(ModelForm):
+ class Meta:
+ model = WorkoutComment
+ fields = ['comment',]
+ widgets = {
+ 'comment': forms.Textarea,
+ }
+
diff --git a/rowers/templates/list_workouts.html b/rowers/templates/list_workouts.html
index 7a1d58ea..891e596b 100644
--- a/rowers/templates/list_workouts.html
+++ b/rowers/templates/list_workouts.html
@@ -5,6 +5,12 @@
{% block title %}Workouts{% endblock %}
{% block content %}
+
+
+
+
Select start and end date for a date range:
@@ -27,7 +33,7 @@
-
+
{% if team %}
{{ team.name }} Team Workouts
{% else %}
diff --git a/rowers/templates/workout_comments.html b/rowers/templates/workout_comments.html
index d87b5cf2..fec9ab39 100644
--- a/rowers/templates/workout_comments.html
+++ b/rowers/templates/workout_comments.html
@@ -6,172 +6,167 @@
{% block title %}Change Workout {% endblock %}
{% block content %}
-
+
- {% if form.errors %}
-
- Please correct the error{{ form.errors|pluralize }} below.
-
- {% endif %}
-
-
Comments {{ workout.name }}
-
-{% localtime on %}
-
-
- | Rower: | {{ first_name }} {{ last_name }} |
-
- | Date/Time: | {{ workout.startdatetime }} |
-
- | Distance: | {{ workout.distance }}m |
-
- | Duration: | {{ workout.duration |durationprint:"%H:%M:%S.%f" }} |
-
- | Public link to this workout |
-
- https://rowsandall.com/rowers/workout/{{ workout.id }}
- |
- |
- | Public link to interactive chart |
-
+
+
+ {% if form.errors %}
+
+ Please correct the error{{ form.errors|pluralize }} below.
+
+ {% endif %}
+
+ Comments {{ workout.name }}
+
+ {% localtime on %}
+
-{% endlocaltime %}
-
-
-
- Images linked to this workout
-
-
-
-
-
-
-
-
- Generating images takes roughly 1 second per minute
- of your workout's duration. Please reload after a minute or so.
-
+
+ | |
+
+ {% endlocaltime %}
+
+ {% for c in comments %}
+
+
+ {{ c.created }}
+ {{ c.user.first_name }} {{ c.user.last_name }}
+
+
+
+ {% endfor %}
- {% for graph in graphs1 %}
- {% if forloop.counter == 1 %}
-
-
- 
-
- {% elif forloop.counter == 3 %}
-
-
- 
-
-
- {% else %}
-
-
- 
-
- {% endif %}
- {% endfor %}
-
-
- {% for graph in graphs2 %}
- {% if forloop.counter == 1 %}
-
-
- 
-
- {% elif forloop.counter == 3 %}
-
-
- 
-
-
- {% else %}
-
-
- 
-
- {% endif %}
- {% endfor %}
-
-
-
-
- {% else %}
-
No graphs found
- {% endif %}
+
+
-
+
+
Images linked to this workout
+
+ {% if graphs1 %}
+
+ {% for graph in graphs1 %}
+ {% if forloop.counter == 1 %}
+
+
+ 
+
+ {% elif forloop.counter == 3 %}
+
+
+ 
+
+
+ {% else %}
+
+
+ 
+
+ {% endif %}
+ {% endfor %}
+
+
+ {% for graph in graphs2 %}
+ {% if forloop.counter == 1 %}
+
+
+ 
+
+ {% elif forloop.counter == 3 %}
+
+
+ 
+
+
+ {% else %}
+
+
+ 
+
+ {% endif %}
+ {% endfor %}
+
+
+
+
+ {% else %}
+
No graphs found
+ {% endif %}
+
+
+
-
Workout Summary
-
-
-
-{{ workout.summary }}
-
-
-
-
+
Workout Summary
+
+
+
+ {{ workout.summary }}
+
+
+
-
-
+
-
- {{ gmscript |safe }}
-
-
-
- {{ gmdiv|safe }}
-
+
+
+ {{ gmdiv|safe }}
+
{% endblock %}
diff --git a/rowers/views.py b/rowers/views.py
index 43cfea8b..ae25f132 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -3327,12 +3327,23 @@ def workout_comment_view(request,id=0):
return HttpResponseForbidden("Permission error")
# ok we're permitted
- comments = WorkoutComment.objects.filter(workout=w)
+ if request.method == 'POST':
+ form = WorkoutCommentForm(request.POST)
+ if form.is_valid():
+ cd = form.cleaned_data
+ comment = cd['comment']
+ c = WorkoutComment(workout=w,user=request.user,comment=comment)
+ c.save()
+
+ comments = WorkoutComment.objects.filter(workout=w).order_by("created")
+ form = WorkoutCommentForm()
+
return render(request,
'workout_comments.html',
{'workout':w,
'comments':comments,
+ 'form':form,
})
# The basic edit page
diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css
index 253f5e5d..09e1f881 100644
--- a/static/css/rowsandall.css
+++ b/static/css/rowsandall.css
@@ -554,3 +554,257 @@ a.wh:hover {
.bk-canvas-map {
overflow: hidden;
}
+
+
+/* container */
+.container {
+ padding: 5% 5%;
+}
+
+/* CSS talk bubble */
+.talk-bubble {
+ margin: 40px;
+ display: inline-block;
+ position: relative;
+ width: 200px;
+ height: auto;
+ background-color: lightyellow;
+}
+.border{
+ border: 8px solid #666;
+}
+.round{
+ border-radius: 30px;
+ -webkit-border-radius: 30px;
+ -moz-border-radius: 30px;
+
+}
+
+/* Right triangle placed top left flush. */
+.tri-right.border.left-top:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: -40px;
+ right: auto;
+ top: -8px;
+ bottom: auto;
+ border: 32px solid;
+ border-color: #666 transparent transparent transparent;
+}
+.tri-right.left-top:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: -20px;
+ right: auto;
+ top: 0px;
+ bottom: auto;
+ border: 22px solid;
+ border-color: lightyellow transparent transparent transparent;
+}
+
+/* Right triangle, left side slightly down */
+.tri-right.border.left-in:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: -40px;
+ right: auto;
+ top: 30px;
+ bottom: auto;
+ border: 20px solid;
+ border-color: #666 #666 transparent transparent;
+}
+.tri-right.left-in:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: -20px;
+ right: auto;
+ top: 38px;
+ bottom: auto;
+ border: 12px solid;
+ border-color: lightyellow lightyellow transparent transparent;
+}
+
+/*Right triangle, placed bottom left side slightly in*/
+.tri-right.border.btm-left:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: -8px;
+ right: auto;
+ top: auto;
+ bottom: -40px;
+ border: 32px solid;
+ border-color: transparent transparent transparent #666;
+}
+.tri-right.btm-left:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: 0px;
+ right: auto;
+ top: auto;
+ bottom: -20px;
+ border: 22px solid;
+ border-color: transparent transparent transparent lightyellow;
+}
+
+/*Right triangle, placed bottom left side slightly in*/
+.tri-right.border.btm-left-in:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: 30px;
+ right: auto;
+ top: auto;
+ bottom: -40px;
+ border: 20px solid;
+ border-color: #666 transparent transparent #666;
+}
+.tri-right.btm-left-in:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: 38px;
+ right: auto;
+ top: auto;
+ bottom: -20px;
+ border: 12px solid;
+ border-color: lightyellow transparent transparent lightyellow;
+}
+
+/*Right triangle, placed bottom right side slightly in*/
+.tri-right.border.btm-right-in:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: 30px;
+ bottom: -40px;
+ border: 20px solid;
+ border-color: #666 #666 transparent transparent;
+}
+.tri-right.btm-right-in:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: 38px;
+ bottom: -20px;
+ border: 12px solid;
+ border-color: lightyellow lightyellow transparent transparent;
+}
+/*
+ left: -8px;
+ right: auto;
+ top: auto;
+ bottom: -40px;
+ border: 32px solid;
+ border-color: transparent transparent transparent #666;
+ left: 0px;
+ right: auto;
+ top: auto;
+ bottom: -20px;
+ border: 22px solid;
+ border-color: transparent transparent transparent lightyellow;
+
+/*Right triangle, placed bottom right side slightly in*/
+.tri-right.border.btm-right:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: -8px;
+ bottom: -40px;
+ border: 20px solid;
+ border-color: #666 #666 transparent transparent;
+}
+.tri-right.btm-right:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: 0px;
+ bottom: -20px;
+ border: 12px solid;
+ border-color: lightyellow lightyellow transparent transparent;
+}
+
+/* Right triangle, right side slightly down*/
+.tri-right.border.right-in:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: -40px;
+ top: 30px;
+ bottom: auto;
+ border: 20px solid;
+ border-color: #666 transparent transparent #666;
+}
+.tri-right.right-in:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: -20px;
+ top: 38px;
+ bottom: auto;
+ border: 12px solid;
+ border-color: lightyellow transparent transparent lightyellow;
+}
+
+/* Right triangle placed top right flush. */
+.tri-right.border.right-top:before {
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: -40px;
+ top: -8px;
+ bottom: auto;
+ border: 32px solid;
+ border-color: #666 transparent transparent transparent;
+}
+.tri-right.right-top:after{
+ content: ' ';
+ position: absolute;
+ width: 0;
+ height: 0;
+ left: auto;
+ right: -20px;
+ top: 0px;
+ bottom: auto;
+ border: 20px solid;
+ border-color: lightyellow transparent transparent transparent;
+}
+
+/* talk bubble contents */
+.talktext{
+ padding: 1em;
+ text-align: left;
+ line-height: 1.5em;
+}
+.talktext p{
+ /* remove webkit p margins */
+ -webkit-margin-before: 0em;
+ -webkit-margin-after: 0em;
+}