407 lines
12 KiB
HTML
407 lines
12 KiB
HTML
{% extends "newbase.html" %}
|
|
{% load static %}
|
|
{% load rowerfilters %}
|
|
|
|
{% block title %}Rowsandall Training Plans{% endblock %}
|
|
|
|
|
|
{% block main %}
|
|
<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">
|
|
<section class="drop-zone">
|
|
<h2>Training Steps for {{ ps.name }}</h2>
|
|
<p>
|
|
<form target="/rowers/plans/stepadder/{{ ps.id}}/?save=1" onsubmit="event.preventDefault(); saveSession();">
|
|
<input id="hidden" type="hidden" value="">
|
|
<input id="savebutton" type="submit" value="Save">
|
|
</form>
|
|
</p>
|
|
{% for step in currentsteps %}
|
|
<div id="{{ step.id }}" draggable="true" class="trainingstep {{ step.intensity }} {{ step.durationtype }}" >
|
|
<span id="{{ step.id }}" class="stepid">
|
|
({{ forloop.counter|add:-1 }})
|
|
</span>
|
|
<span id="{{ step.id }}" class="stepcontent">
|
|
{{ step.name }}
|
|
{% if step.durationtype == "RepeatUntilStepsCmplt" %}
|
|
- repeat {{ step.targetvalue }}x from block {{ step.durationvalue|floatformat }}
|
|
{% endif %}
|
|
</span>
|
|
<span id="{{ step.id }}">
|
|
<a href="/rowers/plans/step/{{ step.id }}/edit/{{ ps.id }}/">
|
|
<i class="fas fa-pencil-alt fa-fw"></i>
|
|
</a>
|
|
</span>
|
|
<span id="{{ step.id }}">
|
|
<a href="/rowers/plans/step/{{ step.id }}/delete/?id={{ ps.id }}">
|
|
<i class="fas fa-trash-alt fa-fw"></i>
|
|
</a>
|
|
</span>
|
|
</div>
|
|
{% endfor %}
|
|
</section>
|
|
<section class="allcentered">
|
|
<div class="allcenteredchild">
|
|
<h1><i class="fas fa-arrow-left fa-fw"></i></h1>
|
|
</div>
|
|
</section>
|
|
<section class="library">
|
|
<h2>Step Library</h2>
|
|
{% for step in steps %}
|
|
<div id="{{ step.id }}" draggable="true" class="trainingstep {{ step.intensity }} {{ step.durationtype}}" >
|
|
<span id="{{ step.id }}" class="stepid">
|
|
</span>
|
|
<span id="{{ step.id }}" class="stepcontent">
|
|
{{ step.name }}
|
|
{% if step.durationtype == "RepeatUntilStepsCmplt" %}
|
|
- repeat {{ step.targetvalue }}x from block {{ step.durationvalue|floatformat }}
|
|
{% endif %}
|
|
</span>
|
|
<span id="{{ step.id }}">
|
|
<a href="/rowers/plans/step/{{ step.id }}/edit/{{ ps.id }}/">
|
|
<i class="fas fa-pencil-alt fa-fw"></i>
|
|
</a>
|
|
</span>
|
|
<span id="{{ step.id }}">
|
|
<a href="/rowers/plans/step/{{ step.id }}/delete/?id={{ ps.id }}">
|
|
<i class="fas fa-trash-alt fa-fw"></i>
|
|
</a>
|
|
</span>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
<ul class="main-content">
|
|
<li class="grid_2 library">
|
|
<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>
|
|
</li>
|
|
<li class="grid_2 library">
|
|
<h2>Step Information</h2>
|
|
<div id="stepinfo">
|
|
<p>Step information</p>
|
|
</div>
|
|
</li>
|
|
<li class="grid_2">
|
|
<h2>Explanation</h2>
|
|
<table width=90% class="listtable shortpadded">
|
|
<tr>
|
|
<th>Parameter</th>
|
|
<th>Regular Step</th>
|
|
<th>Repeat Step</th>
|
|
</tr>
|
|
<tr>
|
|
<th>Duration Type</th><td>Time or Distance</td><td>Repeat</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Duration Value</th><td>Minutes / Meters</td><td>Block number to start repeat from</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Target Type</th><td>Set a target to hold</td><td>---</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Target Value</th>
|
|
<td>
|
|
<div>Power: Zone number (1-10), % of FTP (10-1000)</div>
|
|
<div>Speed: 1000x target speed in m/s</div>
|
|
<div>Heart Rate: Zone number (1-10), % of max (10-100); </div>
|
|
<div>Cadence: Strokes per Minute</div>
|
|
</td>
|
|
<td>
|
|
Number of repetitions
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Target Value Low</th>
|
|
<td>
|
|
<div>Power: % of FTP (10-1000)</div>
|
|
<div>Speed: 1000x target speed in m/s</div>
|
|
<div>Heart Rate: % of max (10-100); </div>
|
|
<div>Cadence: Strokes per Minute</div>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Target Value High</th>
|
|
<td>
|
|
<div>Power: % of FTP (10-1000)</div>
|
|
<div>Speed: 1000x target speed in m/s</div>
|
|
<div>Heart Rate: % of max (10-100); </div>
|
|
<div>Cadence: Strokes per Minute</div>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Intensity</th><td>Warming Up, Active, Rest</td><td>Set to Active</td>
|
|
</tr>
|
|
<tr>
|
|
<th>Description</th><td>Any other text</td><td></td>
|
|
</tr>
|
|
</table>
|
|
</li>
|
|
|
|
</ul>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script type='text/javascript'
|
|
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
|
</script>
|
|
<script>
|
|
let csrftoken;
|
|
let mysteps = {};
|
|
{% for step in steps %}
|
|
mysteps["{{ step.id }}"] = { 'name': '{{ step.name }}' };
|
|
{% endfor %}
|
|
let descriptions = {}
|
|
{% for key, value in stepdescriptions.items %}
|
|
descriptions["{{ key }}"] = "{{ value }}"
|
|
{% endfor %}
|
|
$(document).ready(function() {
|
|
csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
|
});
|
|
function csrfSafeMethod(method) {
|
|
// these HTTP methods do not require CSRF protection
|
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
|
}
|
|
$.ajaxSetup({
|
|
beforeSend: function(xhr, settings) {
|
|
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
|
}
|
|
}
|
|
});
|
|
|
|
let dragged;
|
|
let origcolor;
|
|
|
|
function saveSession() {
|
|
|
|
var list = [];
|
|
steps = document.querySelector('.drop-zone');
|
|
steps.childNodes.forEach(function(item) {
|
|
if (item.className && item.className.includes("trainingstep")) {
|
|
item.childNodes.forEach(function(child) {
|
|
if (child.id && child.className == 'stepcontent') {
|
|
list.push(child.id);
|
|
}
|
|
})
|
|
}
|
|
});
|
|
$.ajax({
|
|
data: JSON.stringify(list),
|
|
type: 'POST',
|
|
url: '/rowers/plans/stepadder/{{ ps.id }}/?save=1',
|
|
error: function(result) {
|
|
$("#id_waiting").replaceWith(
|
|
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
|
);
|
|
},
|
|
success: function(result) {
|
|
console.log(result)
|
|
}
|
|
})
|
|
saveState();
|
|
// reload the page
|
|
location.reload();
|
|
// window.location.reload(true);
|
|
}
|
|
|
|
function saveState() {
|
|
var cntr = 0;
|
|
var list = [];
|
|
steps = document.querySelector('.drop-zone');
|
|
steps.childNodes.forEach(function(item) {
|
|
if (item.className && item.className.includes("trainingstep")) {
|
|
item.childNodes.forEach(function(child) {
|
|
if (child.id && child.className == 'stepcontent') {
|
|
list.push(child.id);
|
|
}
|
|
if (child.className == "stepid") {
|
|
s = `(${cntr})`
|
|
child.replaceWith(s);
|
|
cntr++;
|
|
}
|
|
})
|
|
}
|
|
});
|
|
$.ajax({
|
|
data: JSON.stringify(list),
|
|
type: 'POST',
|
|
url: '/rowers/plans/stepadder/{{ ps.id }}/',
|
|
error: function(result) {
|
|
$("#id_waiting").replaceWith(
|
|
'<div id="id_failed" class="grid_12 alpha message">Your upload failed</div>'
|
|
);
|
|
},
|
|
success: function(result) {
|
|
console.log(result)
|
|
}
|
|
})
|
|
};
|
|
|
|
function handleDragStart(event) {
|
|
let target = event.target;
|
|
if (target) {
|
|
dragged = target;
|
|
origcolor = dragged.style.backgroundColor;
|
|
event.dataTransfer.setData('text', target.id);
|
|
event.dataTransfer.dropEffect = 'move';
|
|
// Make it half transparent
|
|
event.target.style.opacity = .3;
|
|
}
|
|
}
|
|
|
|
function handleDragEnd(event) {
|
|
if (event.target) {
|
|
// Reset the transparency
|
|
event.target.style.opacity = ''; // reset opacity when drag ends
|
|
items.forEach(function (item) {
|
|
item.classList.remove('over');
|
|
});
|
|
dragged = null;
|
|
origcolor = null;
|
|
}
|
|
saveState();
|
|
}
|
|
|
|
function handleMouseOver(event) {
|
|
if (event.preventDefault) {
|
|
const id = event.target.id;
|
|
if (id) {
|
|
var name = mysteps[id]['name'];
|
|
var txt = descriptions[id];
|
|
var divstring = `<p>${name}</p><p>${txt}</p>`
|
|
const div = document.getElementById("stepinfo");
|
|
div.innerHTML = divstring;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function handleMouseLeave(event) {
|
|
if (event.preventDefault) {
|
|
const div = document.getElementById("stepinfo");
|
|
div.innerHTML = '<p>Hover over a step to get details</p>'
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function handleDragOver(event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
function handleDragEnter(event) {
|
|
this.classList.add('over');
|
|
const target = event.target;
|
|
overcolor = event.target.style.backgroundColor;
|
|
|
|
if (target && dragged) {
|
|
event.preventDefault();
|
|
// Set the dropEffect to move
|
|
event.dataTransfer.dropEffect = 'move'
|
|
target.style.background = '#1f904e';
|
|
}
|
|
}
|
|
|
|
function handleDragLeave(event) {
|
|
event.target.style.backgroundColor = '';
|
|
|
|
if (dragged.parentNode.className.includes("drop-zone")) {
|
|
trash(event);
|
|
}
|
|
saveState();
|
|
}
|
|
|
|
function trash(event) {
|
|
const target = event.target;
|
|
event.target.style.backgroundColor = '';
|
|
if (target && dragged) {
|
|
event.preventDefault();
|
|
if (dragged.parentNode.className.includes("drop-zone")) {
|
|
dragged.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleDrop(event) {
|
|
const target = event.target;
|
|
if (target && dragged) {
|
|
target.style.backgroundColor = '';
|
|
event.preventDefault();
|
|
// Get the id of the target and add the moved element to the targets DOM
|
|
// dragged.parentNode.removeChild(dragged);
|
|
if (target.nodeName == "SECTION") {
|
|
dragged.style.opacity = '';
|
|
dragged.style.backgroundColor = origcolor;
|
|
var dropped = dragged.cloneNode(true);
|
|
dropped.id = 0;
|
|
target.appendChild(dropped);
|
|
}
|
|
if (target.nodeName == 'DIV') {
|
|
// insert after
|
|
dragged.style.opacity = '';
|
|
dragged.style.backgroundColor = origcolor;
|
|
var dropped = dragged.cloneNode(true);
|
|
if (target.parentNode.nodeName == 'SECTION') {
|
|
target.after(dropped);
|
|
}
|
|
if (target.parentNode.parentNode.nodeName == 'SECTION') {
|
|
target.parentNode.after(dropped);
|
|
}
|
|
}
|
|
}
|
|
saveState();
|
|
}
|
|
|
|
function noDrop(event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
|
|
let dropzone = document.querySelector('.drop-zone')
|
|
dropzone.addEventListener('dragenter', handleDragEnter);
|
|
dropzone.addEventListener('dragleave', handleDragLeave);
|
|
dropzone.addEventListener('drop', handleDrop)
|
|
dropzone.addEventListener('dragover', handleDragOver);
|
|
dropzone.addEventListener('dragstart', handleDragStart);
|
|
dropzone.addEventListener('dragend', handleDragEnd);
|
|
|
|
let items = document.querySelectorAll('.stepcontainer .trainingstep');
|
|
items.forEach(function(item) {
|
|
item.addEventListener('dragstart', handleDragStart);
|
|
item.addEventListener('dragend', handleDragEnd);
|
|
item.addEventListener('dragleave', handleDragLeave);
|
|
item.addEventListener('drop',noDrop);
|
|
item.addEventListener('dragenter',noDrop);
|
|
item.addEventListener('mouseover',handleMouseOver);
|
|
item.addEventListener('mouseleave',handleMouseLeave);
|
|
});
|
|
|
|
|
|
</script>
|
|
{% endblock %}
|
|
|
|
{% block sidebar %}
|
|
{% include 'menu_plan.html' %}
|
|
{% endblock %}
|