saveState not working yet
This commit is contained in:
@@ -2427,6 +2427,31 @@ class PlannedSessionStep(models.Model):
|
|||||||
notes = models.TextField(default='',max_length=200, blank=True, null=True)
|
notes = models.TextField(default='',max_length=200, blank=True, null=True)
|
||||||
color = models.TextField(default='#ddd',max_length=200)
|
color = models.TextField(default='#ddd',max_length=200)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self.intensity == "Warmup":
|
||||||
|
self.color = "#ffcccb"
|
||||||
|
elif self.intensity == "Cooldown":
|
||||||
|
self.color = '#90ee90'
|
||||||
|
elif self.intensity == "Rest":
|
||||||
|
self.color = 'add8e6'
|
||||||
|
|
||||||
|
super(PlannedSessionStep, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
class StepEditorForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = PlannedSessionStep
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
#'type',
|
||||||
|
'durationtype',
|
||||||
|
'durationvalue',
|
||||||
|
'intensity',
|
||||||
|
]
|
||||||
|
|
||||||
|
widgets = {
|
||||||
|
'name': forms.Textarea(attrs={'rows':1, 'cols':50}),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PlannedSession(models.Model):
|
class PlannedSession(models.Model):
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,15 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<h2>Plan Training Steps</h2>
|
<h2>Plan Training Steps</h2>
|
||||||
|
<p>
|
||||||
|
WARNING: This is experimental functionality which may not behave as you
|
||||||
|
expect. Does not work on smartphones.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Drag from Library to Training to add a step to the end.
|
||||||
|
Drag on top of a training step to insert after it.
|
||||||
|
Drag out of Training to remove a step.
|
||||||
|
</p>
|
||||||
<div class="stepcontainer" id="list">
|
<div class="stepcontainer" id="list">
|
||||||
<section class="drop-zone">
|
<section class="drop-zone">
|
||||||
<h2>Training</h2>
|
<h2>Training</h2>
|
||||||
@@ -14,7 +23,7 @@
|
|||||||
<section class="library">
|
<section class="library">
|
||||||
<h2>Library</h2>
|
<h2>Library</h2>
|
||||||
{% for step in steps %}
|
{% for step in steps %}
|
||||||
<div draggable="true" class="trainingstep" style="background-color: {{ step.color }}">
|
<div draggable="true" class="trainingstep {{ step.intensity }}" >
|
||||||
<div id="{{ forloop.counter }}" class="stepcontent">
|
<div id="{{ forloop.counter }}" class="stepcontent">
|
||||||
{{ step.name }}
|
{{ step.name }}
|
||||||
</div>
|
</div>
|
||||||
@@ -22,8 +31,15 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="trash-can">
|
<section>
|
||||||
<h2>Remove</h2>
|
<h2>Add new step</h2>
|
||||||
|
<form enctype="multipart/multipart/form-data" method="post">
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<input name="newstep" type="submit" value="Add to Library">
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -33,11 +49,25 @@
|
|||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
let dragged;
|
let dragged;
|
||||||
|
let origcolor;
|
||||||
|
|
||||||
|
function saveState() {
|
||||||
|
var list = [];
|
||||||
|
steps = document.querySelector('.drop-zone');
|
||||||
|
steps.childNodes.forEach(function(item) {
|
||||||
|
if (item.className && item.className.includes("trainingstep")) {
|
||||||
|
console.log(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleDragStart(event) {
|
function handleDragStart(event) {
|
||||||
let target = event.target;
|
let target = event.target;
|
||||||
if (target) {
|
if (target) {
|
||||||
dragged = target;
|
dragged = target;
|
||||||
|
origcolor = dragged.style.backgroundColor;
|
||||||
event.dataTransfer.setData('text', target.id);
|
event.dataTransfer.setData('text', target.id);
|
||||||
event.dataTransfer.dropEffect = 'move';
|
event.dataTransfer.dropEffect = 'move';
|
||||||
// Make it half transparent
|
// Make it half transparent
|
||||||
@@ -49,7 +79,11 @@
|
|||||||
if (event.target) {
|
if (event.target) {
|
||||||
// Reset the transparency
|
// Reset the transparency
|
||||||
event.target.style.opacity = ''; // reset opacity when drag ends
|
event.target.style.opacity = ''; // reset opacity when drag ends
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.classList.remove('over');
|
||||||
|
});
|
||||||
dragged = null;
|
dragged = null;
|
||||||
|
origcolor = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +96,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleDragEnter(event) {
|
function handleDragEnter(event) {
|
||||||
|
this.classList.add('over');
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
|
overcolor = event.target.style.backgroundColor;
|
||||||
|
|
||||||
if (target && dragged) {
|
if (target && dragged) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
// Set the dropEffect to move
|
// Set the dropEffect to move
|
||||||
@@ -72,19 +109,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleDragLeave(event) {
|
function handleDragLeave(event) {
|
||||||
console.log(event.target.nodeName);
|
event.target.style.backgroundColor = '';
|
||||||
event.target.style.background = '';
|
|
||||||
|
if (dragged.parentNode.className.includes("drop-zone")) {
|
||||||
|
console.log("trashing");
|
||||||
|
trash(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trash(event) {
|
function trash(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
console.log("trash", target)
|
event.target.style.backgroundColor = '';
|
||||||
target.style.backgroundColor = '';
|
|
||||||
if (target && dragged) {
|
if (target && dragged) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
console.log(dragged.parentNode.className);
|
if (dragged.parentNode.className.includes("drop-zone")) {
|
||||||
if (dragged.parentNode.className == "drop-zone") {
|
|
||||||
dragged.remove();
|
dragged.remove();
|
||||||
|
saveState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,18 +138,24 @@
|
|||||||
// dragged.parentNode.removeChild(dragged);
|
// dragged.parentNode.removeChild(dragged);
|
||||||
if (target.nodeName == "SECTION") {
|
if (target.nodeName == "SECTION") {
|
||||||
dragged.style.opacity = '';
|
dragged.style.opacity = '';
|
||||||
|
dragged.style.backgroundColor = origcolor;
|
||||||
var dropped = dragged.cloneNode(true);
|
var dropped = dragged.cloneNode(true);
|
||||||
target.appendChild(dropped);
|
target.appendChild(dropped);
|
||||||
}
|
}
|
||||||
if (target.nodeName == 'DIV') {
|
if (target.nodeName == 'DIV') {
|
||||||
// insert after
|
// insert after
|
||||||
dragged.style.opacity = '';
|
dragged.style.opacity = '';
|
||||||
|
dragged.style.backgroundColor = origcolor;
|
||||||
var dropped = dragged.cloneNode(true);
|
var dropped = dragged.cloneNode(true);
|
||||||
if (target.parentNode.nodeName == 'SECTION') {
|
if (target.parentNode.nodeName == 'SECTION') {
|
||||||
target.after(dropped);
|
target.after(dropped);
|
||||||
}
|
}
|
||||||
|
if (target.parentNode.parentNode.nodeName == 'SECTION') {
|
||||||
|
target.parentNode.after(dropped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function noDrop(event) {
|
function noDrop(event) {
|
||||||
@@ -124,15 +170,12 @@
|
|||||||
dropzone.addEventListener('dragover', handleDragOver);
|
dropzone.addEventListener('dragover', handleDragOver);
|
||||||
dropzone.addEventListener('dragstart', handleDragStart);
|
dropzone.addEventListener('dragstart', handleDragStart);
|
||||||
dropzone.addEventListener('dragend', handleDragEnd);
|
dropzone.addEventListener('dragend', handleDragEnd);
|
||||||
let trashcan = document.querySelector('.trash-can');
|
|
||||||
trashcan.addEventListener('drop', trash)
|
|
||||||
trashcan.addEventListener('dragenter', handleDragEnter);
|
|
||||||
trashcan.addEventListener('dragleave', handleDragLeave);
|
|
||||||
trashcan.addEventListener('dragover', handleDragOver);
|
|
||||||
let items = document.querySelectorAll('.stepcontainer .trainingstep');
|
let items = document.querySelectorAll('.stepcontainer .trainingstep');
|
||||||
items.forEach(function(item) {
|
items.forEach(function(item) {
|
||||||
item.addEventListener('dragstart', handleDragStart);
|
item.addEventListener('dragstart', handleDragStart);
|
||||||
item.addEventListener('dragend', handleDragEnd);
|
item.addEventListener('dragend', handleDragEnd);
|
||||||
|
item.addEventListener('dragleave', handleDragLeave);
|
||||||
item.addEventListener('drop',noDrop);
|
item.addEventListener('drop',noDrop);
|
||||||
item.addEventListener('dragenter',noDrop);
|
item.addEventListener('dragenter',noDrop);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2963,35 +2963,23 @@ def rower_create_trainingplan(request, id=0):
|
|||||||
message="This functionality requires a Coach or Self-Coach plan",
|
message="This functionality requires a Coach or Self-Coach plan",
|
||||||
redirect_field_name=None)
|
redirect_field_name=None)
|
||||||
def stepeditor(request, id=0):
|
def stepeditor(request, id=0):
|
||||||
step1 = PlannedSessionStep(
|
|
||||||
manager = request.user,
|
|
||||||
name = "Warming Up",
|
|
||||||
intensity = "Warmup",
|
|
||||||
durationtype = "Time",
|
|
||||||
durationvalue = 60000,
|
|
||||||
)
|
|
||||||
|
|
||||||
step2 = PlannedSessionStep(
|
form = StepEditorForm()
|
||||||
manager = request.user,
|
|
||||||
name = "Steady",
|
|
||||||
intensity = "Active",
|
|
||||||
durationtype = "Time",
|
|
||||||
durationvalue = 180000,
|
|
||||||
)
|
|
||||||
|
|
||||||
step3 = PlannedSessionStep(
|
if request.method == 'POST':
|
||||||
manager = request.user,
|
form = StepEditorForm(request.POST)
|
||||||
name = "Cooling Down",
|
if form.is_valid():
|
||||||
intensity = "Cooldown",
|
step = form.save(commit=False)
|
||||||
durationtype = "Time",
|
step.manager = request.user
|
||||||
durationvalue = 60000,
|
step.save()
|
||||||
)
|
|
||||||
|
|
||||||
steps = [step1,step2,step3]
|
|
||||||
|
steps = PlannedSessionStep.objects.filter(manager=request.user)
|
||||||
|
|
||||||
return render(request, 'stepeditor.html',
|
return render(request, 'stepeditor.html',
|
||||||
{
|
{
|
||||||
'steps':steps,
|
'steps':steps,
|
||||||
|
'form':form,
|
||||||
})
|
})
|
||||||
|
|
||||||
@user_passes_test(can_plan, login_url="/rowers/paidplans",
|
@user_passes_test(can_plan, login_url="/rowers/paidplans",
|
||||||
|
|||||||
@@ -167,7 +167,8 @@ from rowers.models import (
|
|||||||
IndoorVirtualRaceResultForm, IndoorVirtualRaceResult,
|
IndoorVirtualRaceResultForm, IndoorVirtualRaceResult,
|
||||||
IndoorVirtualRaceForm, PlannedSessionCommentForm,
|
IndoorVirtualRaceForm, PlannedSessionCommentForm,
|
||||||
Alert, Condition, StaticChartRowerForm,
|
Alert, Condition, StaticChartRowerForm,
|
||||||
FollowerForm, VirtualRaceAthleteForm, InstantPlanForm, DataRowerForm
|
FollowerForm, VirtualRaceAthleteForm, InstantPlanForm, DataRowerForm,
|
||||||
|
StepEditorForm,
|
||||||
)
|
)
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet,
|
FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet,
|
||||||
|
|||||||
@@ -341,20 +341,25 @@ th.rotate > div > span {
|
|||||||
border: 3px dotted #666;
|
border: 3px dotted #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.trainingstep.Warmup {
|
||||||
|
background-color: #ffcccb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainingstep.Cooldown {
|
||||||
|
background-color: #90ee90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainingstep.Rest {
|
||||||
|
background-color: #add8e6;
|
||||||
|
}
|
||||||
|
|
||||||
.drop-zone {
|
.drop-zone {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #878787;
|
background: #878787;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
padding-bottom: 40px;
|
||||||
|
|
||||||
.trash-can {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
background: red;
|
|
||||||
color: white;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.divlines {
|
.divlines {
|
||||||
|
|||||||
Reference in New Issue
Block a user