demo of drag/drop and JS to capture the new order
This commit is contained in:
@@ -2425,7 +2425,7 @@ class PlannedSessionStep(models.Model):
|
|||||||
intensity = models.TextField(default='',max_length=200, blank=True, null=True,
|
intensity = models.TextField(default='',max_length=200, blank=True, null=True,
|
||||||
choices=intensitytypes)
|
choices=intensitytypes)
|
||||||
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='gray',max_length=200)
|
color = models.TextField(default='#ddd',max_length=200)
|
||||||
|
|
||||||
|
|
||||||
class PlannedSession(models.Model):
|
class PlannedSession(models.Model):
|
||||||
|
|||||||
95
rowers/templates/stepeditor.html
Normal file
95
rowers/templates/stepeditor.html
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}Rowsandall Training Plans{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<h2>Plan Training Steps</h2>
|
||||||
|
|
||||||
|
<div class="stepcontainer" id="list">
|
||||||
|
{% for step in steps %}
|
||||||
|
<div draggable="true" class="trainingstep" style="background-color: {{ step.color }}">
|
||||||
|
<div id="{{ forloop.counter }}" class="stepcontent">
|
||||||
|
{{ step.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script type='text/javascript'
|
||||||
|
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
var list = document.getElementById('list')
|
||||||
|
|
||||||
|
function handleDragStart(e) {
|
||||||
|
this.style.opacity = '0.4';
|
||||||
|
dragSrcEl = this;
|
||||||
|
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
e.dataTransfer.setData('text/html', this.innerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnd(e) {
|
||||||
|
this.style.opacity = '1';
|
||||||
|
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.classList.remove('over');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(e) {
|
||||||
|
if (e.preventDefault) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnter(e) {
|
||||||
|
this.classList.add('over');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(e) {
|
||||||
|
this.classList.remove('over');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (dragSrcEl !== this) {
|
||||||
|
dragSrcEl.innerHTML = this.innerHTML;
|
||||||
|
this.innerHTML = e.dataTransfer.getData('text/html');
|
||||||
|
var steps = []
|
||||||
|
var nl = document.querySelectorAll(".stepcontainer .trainingstep .stepcontent");
|
||||||
|
nl.forEach((s) => {
|
||||||
|
console.log(s.id);
|
||||||
|
steps.push(s.id)
|
||||||
|
})
|
||||||
|
console.log(steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = document.querySelectorAll('.stepcontainer .trainingstep');
|
||||||
|
items.forEach(function(item) {
|
||||||
|
item.addEventListener('dragstart', handleDragStart);
|
||||||
|
item.addEventListener('dragover', handleDragOver);
|
||||||
|
item.addEventListener('dragenter', handleDragEnter);
|
||||||
|
item.addEventListener('dragleave', handleDragLeave);
|
||||||
|
item.addEventListener('dragend', handleDragEnd);
|
||||||
|
item.addEventListener('drop', handleDrop);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_plan.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -875,6 +875,8 @@ urlpatterns = [
|
|||||||
views.rower_create_trainingplan, name='rower_create_trainingplan'),
|
views.rower_create_trainingplan, name='rower_create_trainingplan'),
|
||||||
re_path(r'^plans/$', views.rower_select_instantplan,
|
re_path(r'^plans/$', views.rower_select_instantplan,
|
||||||
name='rower_select_instantplan'),
|
name='rower_select_instantplan'),
|
||||||
|
re_path(r'^plans/stepeditor/$',
|
||||||
|
views.stepeditor, name='stepeditor'),
|
||||||
re_path(r'^plans/(?P<id>[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})/$',
|
re_path(r'^plans/(?P<id>[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})/$',
|
||||||
views.rower_view_instantplan, name='rower_view_instantplan'),
|
views.rower_view_instantplan, name='rower_view_instantplan'),
|
||||||
re_path(r'^buyplan/(?P<id>\d+)/$', views.buy_trainingplan_view,
|
re_path(r'^buyplan/(?P<id>\d+)/$', views.buy_trainingplan_view,
|
||||||
|
|||||||
@@ -2959,6 +2959,40 @@ def rower_create_trainingplan(request, id=0):
|
|||||||
'old_targets': old_targets,
|
'old_targets': old_targets,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@user_passes_test(can_plan, login_url="/rowers/paidplans",
|
||||||
|
message="This functionality requires a Coach or Self-Coach plan",
|
||||||
|
redirect_field_name=None)
|
||||||
|
def stepeditor(request, id=0):
|
||||||
|
step1 = PlannedSessionStep(
|
||||||
|
manager = request.user,
|
||||||
|
name = "Warming Up",
|
||||||
|
intensity = "Warmup",
|
||||||
|
durationtype = "Time",
|
||||||
|
durationvalue = 60000,
|
||||||
|
)
|
||||||
|
|
||||||
|
step2 = PlannedSessionStep(
|
||||||
|
manager = request.user,
|
||||||
|
name = "Steady",
|
||||||
|
intensity = "Active",
|
||||||
|
durationtype = "Time",
|
||||||
|
durationvalue = 180000,
|
||||||
|
)
|
||||||
|
|
||||||
|
step3 = PlannedSessionStep(
|
||||||
|
manager = request.user,
|
||||||
|
name = "Cooling Down",
|
||||||
|
intensity = "Cooldown",
|
||||||
|
durationtype = "Time",
|
||||||
|
durationvalue = 60000,
|
||||||
|
)
|
||||||
|
|
||||||
|
steps = [step1,step2,step3]
|
||||||
|
|
||||||
|
return render(request, 'stepeditor.html',
|
||||||
|
{
|
||||||
|
'steps':steps,
|
||||||
|
})
|
||||||
|
|
||||||
@user_passes_test(can_plan, login_url="/rowers/paidplans",
|
@user_passes_test(can_plan, login_url="/rowers/paidplans",
|
||||||
message="This functionality requires a Coach or Self-Coach plan",
|
message="This functionality requires a Coach or Self-Coach plan",
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ from rowers.models import (
|
|||||||
PlannedSessionComment, CoachRequest, CoachOffer,
|
PlannedSessionComment, CoachRequest, CoachOffer,
|
||||||
VideoAnalysis, ShareKey,
|
VideoAnalysis, ShareKey,
|
||||||
StandardCollection, CourseStandard,
|
StandardCollection, CourseStandard,
|
||||||
VirtualRaceFollower, TombStone, InstantPlan
|
VirtualRaceFollower, TombStone, InstantPlan,
|
||||||
|
PlannedSessionStep,
|
||||||
)
|
)
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
RowerPowerForm, RowerHRZonesForm, RowerForm, RowerCPForm, GraphImage, AdvancedWorkoutForm,
|
RowerPowerForm, RowerHRZonesForm, RowerForm, RowerCPForm, GraphImage, AdvancedWorkoutForm,
|
||||||
|
|||||||
@@ -322,6 +322,25 @@ th.rotate > div > span {
|
|||||||
margin: 2px;
|
margin: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.stepcontainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainingstep {
|
||||||
|
border: 3px solid #666;
|
||||||
|
background-color: #ddd;
|
||||||
|
border-radius: .5em;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainingstep.over {
|
||||||
|
border: 3px dotted #666;
|
||||||
|
}
|
||||||
|
|
||||||
.divlines {
|
.divlines {
|
||||||
display: block;
|
display: block;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user