[chronojump-server] - Now javascript code is integrated directly in the templates to avoid cache future problems - In ta



commit f7e93c1864b556a3711c3c1873e9f6122e8b7862
Author: Marcos Venteo García <mventeo gmail com>
Date:   Sat Sep 16 16:15:47 2017 +0200

    - Now javascript code is integrated directly in the templates to avoid cache future problems
    - In task creation, the user has now the possibility to select percent max velocity if the player has 
previous results for the same exercise, station, resistance and laterality.

 chronojumpserver/api.py                       |   29 ++-
 chronojumpserver/forms.py                     |    4 +-
 chronojumpserver/js/players.js                |   60 +++
 chronojumpserver/js/results.js                |    3 +-
 chronojumpserver/templates/airport.html       |   55 +++-
 chronojumpserver/templates/player_detail.html |   44 +++-
 chronojumpserver/templates/player_list.html   |  486 ++++++++++++++++++++++++-
 chronojumpserver/templates/results.html       |  359 ++++++++++++++++++-
 chronojumpserver/templates/sprints.html       |  279 ++++++++++++++-
 chronojumpserver/templates/station_list.html  |  321 ++++++++++++++++-
 10 files changed, 1624 insertions(+), 16 deletions(-)
---
diff --git a/chronojumpserver/api.py b/chronojumpserver/api.py
index b2e2278..e2509d6 100755
--- a/chronojumpserver/api.py
+++ b/chronojumpserver/api.py
@@ -10,6 +10,7 @@ from chronojumpserver.models import ResultSprint, Exercise, RFIDHistory
 from flask import jsonify, request
 from flask_login import login_required
 from sqlalchemy.exc import IntegrityError, InvalidRequestError, OperationalError
+from sqlalchemy import func
 from time import sleep
 import os
 import subprocess
@@ -239,12 +240,10 @@ def add_modify_delete_exercises():
     status_code = 200
     msg = "Success"
     if request.method == "PUT":
-        print "ddede"
         exerciseId = int(request.form['id'])
         stationId = int(request.form['stationId'])
         name = request.form['name']
         percentBodyMassDisplaced = request.form['percentBodyMassDisplaced']
-        print "HOLA"
         if exerciseId == -1:
             # New Exercise
             e = Exercise(name=name, stationId=stationId,
@@ -313,3 +312,29 @@ def remove_results():
             db_session.commit()
 
     return jsonify(msg="Done")
+
+@app.route('/api/v1/get_max_velocity')
+def get_max_velocity():
+    stationId = request.args.get('station_id', 0)
+    personId = request.args.get('personId', 0)
+    exerciseId = request.args.get('exerciseId', 0)
+    resistance = request.args.get('resistance', 0)
+    laterality = request.args.get('laterality', '')
+
+    sql = "select max(vmaxBySpeed) from resultEncoder where "
+    sql += "stationId = %d AND " % int(stationId)
+    sql += "exerciseId = %d AND " % int(exerciseId)
+    sql += "personId = %d AND " % int(personId)
+    sql += "format(resistance,2) = format(%f,2) AND " % float(resistance)
+    sql += "laterality = '%s'" % laterality
+    print sql
+    result = db_session.execute(sql)
+    max_velocity = 0
+    for row in result:
+        if row[0] == None:
+            max_velocity = 0
+        else:
+            max_velocity = row[0]
+        break
+    print max_velocity
+    return jsonify(max_velocity=max_velocity)
diff --git a/chronojumpserver/forms.py b/chronojumpserver/forms.py
index e116e94..ebb8bdb 100755
--- a/chronojumpserver/forms.py
+++ b/chronojumpserver/forms.py
@@ -8,8 +8,8 @@ from wtforms.validators import DataRequired, Length
 
 class PersonForm(FlaskForm):
     fullname = StringField('Nom Complet', validators=[DataRequired('El nom complet és 
obligatori!'.decode('utf-8'))])
-    height=FloatField('Alçada'.decode('utf-8'), validators=[DataRequired('El camp açada és 
obligatori.'.decode('utf-8'))])
-    weight=FloatField('Pes', validators=[DataRequired('El camp pes és obligatori.'.decode('utf-8'))])
+    height=FloatField('Alçada (cm.)'.decode('utf-8'), validators=[DataRequired('El camp açada és 
obligatori.'.decode('utf-8'))])
+    weight=FloatField('Pes (Kg.)', validators=[DataRequired('El camp pes és obligatori.'.decode('utf-8'))])
     photo=FileField('Foto del Jugador')
     rfid = StringField('RFID', [DataRequired('S\'ha de registrar un RFID per jugador.'.decode('utf-8')), 
validators.Length(max=23)])
 
diff --git a/chronojumpserver/js/players.js b/chronojumpserver/js/players.js
index 0db4bb9..6a3a058 100755
--- a/chronojumpserver/js/players.js
+++ b/chronojumpserver/js/players.js
@@ -327,8 +327,15 @@ $(document).ready(function() {
         // Show the exercises of this station
         refreshExercises(null);
 
+        // get max_velocity
+        get_max_velocity();
+
     });
 
+    $('#exerciseSelect').on('change', function() {
+        get_max_velocity();
+    })
+
     /* Show or Hide Parameters based on Station Type */
     function showHideParameters() {
       var optSelected = $('#stationSelect').find(':selected').attr('data-station-type');
@@ -384,4 +391,57 @@ $(document).ready(function() {
     // Refresh Exercises at the begining
     refreshExercises(null);
 
+    $('#taskLoad').change(function() {
+        get_max_velocity()
+    });
+
+    $('#taskLaterality').change(function()) {
+        get_max_velocity();
+    }
+
+    /* Get max velocity when user selects station, exercice and resistance */
+    function get_max_velocity() {
+        var resistance = $('#taskLoad').val();
+        var stationId = $('#stationSelect').val();
+        var personId = $('#playerId').val();
+        var exerciseId = $('#exerciseSelect').val();
+        var laterailty = $('#taskLaterality').val();
+        console.log("Check velocity max");
+        console.log("Resistance: " + resistance);
+        console.log("Station Id: " + stationId);
+        console.log("Exercise Id: " + exerciseId);
+        console.log("Person Id: " + personId);
+        console.log("Laterality:" + Laterality);
+        if (resistance) {
+            $.ajax({
+                url: '/api/v1/get_max_velocity',
+                method: "GET",
+                data: {
+                    station_id: stationId,
+                    exerciseId: exerciseId,
+                    personId: personId,
+                    resistance: resistance
+                    laterailty: laterailty
+                }
+            }).done(function(data) {
+                // Ok, add options in exercise Select
+                // First remove previous options
+
+                if (data.max_velocity > 0 ) {
+                    console.log("Enable taskPercentMaxSpeed");
+                    $('#taskSpeed').prop('disabled', false);
+                    $('#taskpercentMaxSpeed').prop('disabled', false);
+                } else {
+                    // No velocity max, means disable velocityMAx control
+                    console.log("Disable taskPercentMaxSpeed");
+                    $('#taskSpeed').prop('disabled', false);
+                    $('#taskpercentMaxSpeed').prop('disabled', true);
+                }
+        });
+    } else {
+        // Wait until user enters resistance
+    }
+    }
+
+
 });
diff --git a/chronojumpserver/js/results.js b/chronojumpserver/js/results.js
index 984eac0..50f3981 100755
--- a/chronojumpserver/js/results.js
+++ b/chronojumpserver/js/results.js
@@ -322,11 +322,12 @@ $(document).ready(function() {
       // Called every time a delete checkbox is changed
       $('.deleteCheckbox').on('change', function() {
           var totalChecked = $('.deleteCheckbox:checked').length;
+          //console.log(totalChecked);
           if (totalChecked > 0) {
             // Disable the refresh interval
             if (refreshIntervalId != -1) {
               clearInterval(refreshIntervalId);
-              console.log("Interval refresh is disabled");
+              //console.log("Interval refresh is disabled");
               refreshIntervalId = -1;
               $('.btnDeleteResults').removeClass('disabled');
             }
diff --git a/chronojumpserver/templates/airport.html b/chronojumpserver/templates/airport.html
index b685906..f3cce25 100644
--- a/chronojumpserver/templates/airport.html
+++ b/chronojumpserver/templates/airport.html
@@ -74,5 +74,58 @@
 {% block script %} {{ super() }}
 <script src="{{ url_for('assets', filename='DataTables/media/js/jquery.dataTables.min.js') }}"></script>
 <script src="{{ url_for('assets', filename='DataTables/media/js/dataTables.bootstrap.min.js') }}"></script>
-<script src="{{ url_for('js', filename='airport.js') }}"></script>
+<script>
+/*!
+ * Airport javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+$(document).ready(function() {
+
+    var num = $("table#airportTable tr:first-child > td").length;
+    var width = (100 / num) + "%";
+    //$("td").css("width", width);​
+    $('td').css('width', width);
+
+    $.ajax({
+        url: '/api/v1/station/active_tasks_player'
+    }).done(function(data) {
+        //console.log(data.players_stations);
+        $.each(data.players_stations, function(i, item) {
+            //console.log('Stations of player ' + item.id);
+            var playerId = item.id;
+            $.each(item.stations, function(i, stationId) {
+                //console.log('Has tasks in station ' + item);
+                $('#cell_'+stationId+'_'+playerId).addClass('playerWithActiveTasks');
+            })
+
+        })
+    }).fail(function(xhr, status, error){
+        var err = eval("(" + xhr.responseText + ")");
+        alert(err.msg);
+    });
+
+    setInterval(function() {
+       /* Set the interval for refresh */
+       window.location.href = "/home";
+    }, 15000);
+
+});
+
+</script>
 {% endblock %}
diff --git a/chronojumpserver/templates/player_detail.html b/chronojumpserver/templates/player_detail.html
index f2ebcc0..e0ba293 100755
--- a/chronojumpserver/templates/player_detail.html
+++ b/chronojumpserver/templates/player_detail.html
@@ -41,5 +41,47 @@
 
 {% block script %}
 {{ super() }}
-<script src="{{ url_for('js', filename='player_detail.js') }}"></script>
+<script>
+/*!
+ * Player Detail javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+$('#registerRFID').on('click', function () {
+    var $btn = $(this).button('loading')
+    // CAll by AJAX the method to read the RFID
+    $.ajax({
+      url: '/api/v1/rfid/register',
+      method: 'GET'
+    }).done(function(data) {
+        console.log('RFID readed is ' + data.rfid);
+        $("#rfid").val(data.rfid);
+    }).fail(function(xhr, status, error){
+        var err = eval("(" + xhr.responseText + ")");
+        alert(err.msg);
+    }).always(function(){
+        $btn.button('reset');
+    });
+
+
+
+});
+
+</script>
 {% endblock %}
diff --git a/chronojumpserver/templates/player_list.html b/chronojumpserver/templates/player_list.html
index 0ae0998..4457cbe 100755
--- a/chronojumpserver/templates/player_list.html
+++ b/chronojumpserver/templates/player_list.html
@@ -56,23 +56,28 @@
                                                                <div class="col-sm-2">
                                                                        <input id="numSets" name="numSets" 
type="number" class="form-control taskParameter" value="1" min="1"></input>
                                                                </div>
-                                                               <label for="numReps" class="col-sm-offset-4 
col-sm-2 control-label"># Repeticions:</label>
+                                                               <label for="numReps" class="col-sm-2 
control-label"># Repeticions:</label>
                                                                <div class="col-sm-2">
                                                                        <input id="numReps" name="numReps" 
type="number" class="form-control" value="1" min="1"></input>
                                                                </div>
-                                                       </div>
-                                                       <div class="form-group taskParameter">
                                                                <label for="taskLoad" class="col-sm-2 
control-label">Carrega:</label>
                                                                <div class="col-sm-2">
                                                                        <input id="taskLoad" name="taskLoad" 
type="number" class="form-control"  ></input>
                                                                </div>
+                                                       </div>
+                                                       <div class="form-group taskParameter">
+
                                                                <label for="taskSpeed" class="col-sm-2 
control-label">Velocitat:</label>
                                                                <div class="col-sm-2">
-                                                                       <input id="taskSpeed" 
name="taskSpeed" type="number" class="form-control" min="-1" step="0.1" ></input>
+                                                                       <input id="taskSpeed" 
name="taskSpeed" type="number" class="form-control" min="-1" step="0.1" disabled></input>
                                                                </div>
                                                                <label for="taskpercentMax" class="col-sm-2 
control-label">Vel. Max:</label>
                                                                <div class="col-sm-2">
-                                                                       <input id="taskpercentMaxSpeed" 
name="taskpercentMaxSpeed" type="number" class="form-control" ></input>
+                                                                       <input id="taskMaxSpeed" 
name="taskMaxSpeed" type="number" class="form-control" disabled readonly></input>
+                                                               </div>
+                                                               <label for="taskpercentMax" class="col-sm-2 
control-label">Vel. Max %:</label>
+                                                               <div class="col-sm-2">
+                                                                       <input id="taskpercentMaxSpeed" 
name="taskpercentMaxSpeed" type="number" class="form-control" disabled></input>
                                                                </div>
                                                        </div>
                                                        <div class="form-group taskParameter">
@@ -116,5 +121,474 @@
 {% block script %} {{ super() }}
 <script src="{{ url_for('assets', filename='DataTables/media/js/jquery.dataTables.min.js') }}"></script>
 <script src="{{ url_for('assets', filename='DataTables/media/js/dataTables.bootstrap.min.js') }}"></script>
-<script src="{{ url_for('js', filename='players.js') }}"></script>
+<script>
+/*!
+ * Player javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Function to add/Modify or delete a task called from Task Modal Form. */
+function addModifyDeleteTask(action) {
+    /*
+        action could be : 0 - Add
+                          1 - Modify
+                          2 - delete
+    */
+    /* Function to add or modify the task */
+    var playerId = $('#playerId').val();
+    var description = $('#taskComment').val();
+    var taskId = $('#taskId').val();
+    if ($('#paramTask').hasClass('active')) {
+        var taskType = 'P';
+    } else {
+        var taskType = 'F';
+    }
+    var stationId = $('#stationSelect').val();
+    var exerciseId = $('#exerciseSelect').val();
+    var sets = $('#numSets').val();
+    if (sets == '') sets=-1;
+    var reps = $('#numReps').val();
+    if (reps == '') reps=-1;
+    var load = $('#taskLoad').val();
+    if (load == '') load=-1;
+    var speed = $('#taskSpeed').val();
+    if (speed == '') speed=-1;
+    var percentMaxSpeed = $('#taskpercentMaxSpeed').val();
+    if (percentMaxSpeed == '') percentMaxSpeed = -1;
+    var laterality = $('#taskLaterality').val();
+
+    // Set the method
+    if (action == 2) {
+        method = 'DELETE';
+    } else {
+        // For both Add or Modify we'll use PUT method
+        method = 'PUT';
+    }
+    $('#taskModalForm').modal('hide');
+    $.ajax({
+        url: '/api/v1/tasks',
+        method: method,
+        data: {
+            playerId: playerId,
+            description: description,
+            taskId: taskId,
+            type: taskType,
+            stationId: stationId,
+            exerciseId: exerciseId,
+            sets: sets,
+            reps: reps,
+            load: load,
+            speed: speed,
+            percentMaxSpeed: percentMaxSpeed,
+            laterality: laterality
+        }
+    }).done(function(data) {
+        var table = $('#players').DataTable();
+        table.ajax.reload(null, false);
+    }).fail(function(xhr, status, error){
+        var err = eval("(" + xhr.responseText + ")");
+        alert(err.msg);
+    });
+
+}
+
+
+/*
+  Load Players and tasks
+*/
+$(document).ready(function() {
+
+    var table = $('#players').DataTable({
+        "columns": [{
+                type: "num",
+                title: "id",
+                data: 'id',
+                visible: false
+            },
+            {
+                type: "html",
+                title: "",
+                data: 'imageName',
+                orderable: false,
+                render: function(value, type, row) {
+                    // If player has a photo saved, used it
+                    var href = '/player/' + row.id;
+                    if (value) {
+                        var src = '/static/images/photos/' + value;
+                    } else {
+                        // Otherwise show the no_image icon
+                        var src = '/static/images/no_image.png';
+                    }
+                    var html = '<a href="' + href + '" class="player-link"><img src="' + src + '" 
class="img-circle" height="32"></a>';
+                    return html;
+                }
+            },
+            {
+                type: "html",
+                data: "name",
+                title: "Nom",
+                render: function(data, type, row) {
+                    return '<a href="/player/' + row.id + '">' + data + '</a>';
+                }
+            },
+            {
+                type: "num",
+                data: 'weight',
+                title: "Pes",
+                render: $.fn.dataTable.render.number('', ',', 2)
+            },
+            {
+                type: "num",
+                data: "height",
+                title: "Alçada",
+                render: $.fn.dataTable.render.number('', ',', 2)
+            },
+            /*{
+              type: "html",
+              data: "rfid",
+              title: "RFID"
+            },*/
+            {
+                type: "html",
+                title: "Tasques",
+                data: "tasks",
+                orderable: false,
+                render: function(value) {
+                    if (value.length > 0) {
+                        var html = "<ol>";
+                        $.each(value, function(index, task) {
+                            if (task.type == 'F') {
+                                var _desc = task.description;
+                            } else {
+                                // Compose the description based on values
+
+                                var _desc = task.station + ":";
+                                _desc += task.exercise + " ";
+                                if (task.sets > 1) {
+                                    _desc += task.sets + "x" + task.nreps + ' repeticions';
+                                } else {
+                                    _desc += task.nreps + ' repeticions';
+                                }
+                                if (task.speed > 0 || task.load > 0){
+                                    _desc += " (";
+                                    if (task.load > 0) {
+                                      _desc += "pes: " + task.load + " kg ";
+                                    }
+                                    if (task.speed >0) {
+                                      _desc += "vel: " + task.speed + " m/s";
+                                    }
+                                    _desc += ")";
+                                }
+                            }
+                            html += "<li><a class='task-link' "
+                            html += "data-task-id='" + task.id + "' "
+                            html += "data-task-type='" + task.type + "' "
+                            html += "data-task-station-id='" + task.stationId + "' "
+                            html += "data-task-exercise-id='" + task.exerciseId + "' "
+                            html += "data-task-sets='" + task.sets + "' "
+                            html += "data-task-nreps='" + task.nreps + "' "
+                            html += "data-task-load='" + task.load + "' "
+                            html += "data-task-speed='" + task.speed + "' "
+                            html += "data-task-percent-max-speed='" + task.percentMaxSpeed + "' "
+                            html += "data-task-laterality='" + task.laterality + "' "
+                            html += "data-task-comment='" + task.description + "'"
+                            html += ">" + _desc + "</a></li>";
+                        });
+                        html += "</ol>";
+                        return html;
+                    } else {
+                        return '<ol></ol>';
+                    }
+                }
+            },
+            {
+                type: "html",
+                data: null,
+                title: "",
+                orderable: false,
+                className: 'colAlignRight',
+                  render: function(val) {
+                    return "<button class='btn btn-primary'>Afegeix</button>"
+                }
+            }
+        ],
+        "dom": '<"toolbar">frtip',
+        "pageLength": 10,
+        "order": [ 
+            [2, 'asc']
+        ],
+        "ajax": "/api/v1/players",
+        "processing": true,
+        "severSide": true,
+        "language": {
+            "lengthMenu": "Mostrant _MENU_ jugadors per pàgina",
+            "zeroRecords": "No hi han jugadors per mostrar",
+            "info": "Mostrant els jugadors _START_ a _END_ d'un total de _TOTAL_",
+            "infoEmpty": "La busqueda no ha retornat resultats",
+            "infoFiltered": "(filtrat de _MAX_ jugadors)",
+            "decimal": ",",
+            "thousands": ".",
+            "paginate": {
+                "first": '<i class="fa fa-fast-backward"></i>',
+                "last": '<i class="fa fa-fast-forward"></i>',
+                "next": '<i class="fa fa-forward"></i>',
+                "previous": '<i class="fa fa-backward"></i>'
+            },
+            "search": "Cerca:"
+        }
+    });
+
+    /* Button to add players inside the datatable */
+    $('div.toolbar').html('<a class="btn btn-primary pull-left" href="/player/add">Nou Jugador</a>');
+
+    /* To show the modal form to add the tasks */
+    $('#players').on('click', 'button', function() {
+        var player = table.row($(this).parents('tr')).data();
+
+        $('#modal-title').text('Afegir nova tasca per ' + player.name);
+        $('#taskModalForm').modal();
+        $('#playerId').val(player.id);
+        $('#taskId').val('-1');
+        //refreshExercises(null);
+        // Modal is empty
+        /*$("#stationSelect").val($("#stationSelect option:first").val());
+
+        $('#numSets').val(-1);
+        $('#numReps').val(-1);
+        $('#taskLoad').val(-1);
+        $('#taskSpeed').val(-1);
+        $('#taskpercentMaxSpeed').val(-1);
+        $('#taskLaterality').val($("#taskLaterality option:first").val());
+        $('#taskComment').val('');*/
+        $('#taskParamSelector').removeClass('active');
+        $('#taskFreeSelector').removeClass('active');
+        $('#paramTask').removeClass('active');
+        $('#paramFree').removeClass('active');
+        $('#taskParamSelector').addClass('active');
+        $('#paramTask').addClass('active');
+        $('#btnDeleteTask').removeClass('show').addClass('hidden');
+        $('#btnUpdateTask').removeClass('show').addClass('hidden');
+        $('#btnAddTask').removeClass('hidden').addClass('show');
+               get_max_velocity();
+    });
+
+    /* To show the model to modify the task */
+    $('#players').on('click', 'a.task-link', function() {
+        var player = table.row($(this).parents('tr')).data();
+
+        $('#modal-title').text('Modificar tasca #' + $(this).attr('data-task-id') + ' per ' + player.name);
+        var taskType = $(this).attr('data-task-type');
+        var taskSets = $(this).attr('data-task-sets');
+        var taskReps = $(this).attr('data-task-nreps');
+        var taskLoad = $(this).attr('data-task-load');
+        var taskSpeed = $(this).attr('data-task-speed');
+        var taskPercentMaxSpeed = $(this).attr('data-task-percent-max-speed');
+        var taskLaterality = $(this).attr('data-task-laterality');
+        var stationId = $(this).attr('data-task-station-id');
+        var exerciseId = $(this).attr('data-task-exercise-id');
+        var taskComment = $(this).attr('data-task-comment');
+
+        $('#taskParamSelector').removeClass('active');
+        $('#taskFreeSelector').removeClass('active');
+        $('#paramTask').removeClass('active');
+        $('#paramFree').removeClass('active');
+        if (taskType == 'P') {
+            // Show panel for parametrized tasks
+            $('#taskParamSelector').addClass('active');
+            $('#paramTask').addClass('active');
+
+        } else {
+            // Show the panel for free tasks
+            $('#taskFreeSelector').addClass('active');
+            $('#freeTask').addClass('active');
+
+        }
+
+        // Fill the modal
+        $('#playerId').val(player.id);
+        $('#taskId').val($(this).attr('data-task-id'));
+        $('#stationSelect').val(stationId);
+        showHideParameters();
+        refreshExercises(exerciseId);
+        $('#numSets').val(taskSets);
+        $('#numReps').val(taskReps);
+        $('#taskLoad').val(taskLoad);
+        $('#taskSpeed').val(taskSpeed);
+               $('#taskpercentMaxSpeed').val(taskPercentMaxSpeed);
+        $('#taskLaterality').val(taskLaterality);
+        $('#taskComment').val(taskComment);
+
+        // Hide and show the buttons
+        $('#btnDeleteTask').removeClass('hidden').addClass('show');
+        $('#btnUpdateTask').removeClass('hidden').addClass('show');
+        $('#btnAddTask').removeClass('show').addClass('hidden');
+        $('#taskModalForm').modal();
+               get_max_velocity();
+               if (taskLoad > 0) {
+                       $('#taskSpeed').prop('disabled', false);
+               }
+               if (taskpercentMaxSpeed > 0){
+                       $('#taskpercentMaxSpeed').prop('disabled', false);
+               }
+
+    });
+
+    /* Each time the user selects a station, the exercise from this station is
+       refreshed. */
+    $('#stationSelect').on('change', function() {
+        //Ajax call to retrieve all the exercises. Call the function below.
+
+        // Hide Show parameters based on station type
+        showHideParameters();
+        // Show the exercises of this station
+        refreshExercises(null);
+
+        // get max_velocity
+        get_max_velocity();
+
+    });
+
+    $('#exerciseSelect').on('change', function() {
+        get_max_velocity();
+    });
+
+    /* Show or Hide Parameters based on Station Type */
+    function showHideParameters() {
+      var optSelected = $('#stationSelect').find(':selected').attr('data-station-type');
+      // Show or hide some of the elememts of the task depending of station type
+      if (optSelected != 'S') {
+        $('.taskParameter').show();
+        $('label[for="numReps"]').removeClass('col-sm-offset-6');
+      } else {
+        $('.taskParameter').hide();
+        $('label[for="numReps"]').removeClass('col-sm-offset-4').addClass('col-sm-offset-6');
+      }
+    }
+
+    /* Refresh the exercises based on the value selected in station */
+    function refreshExercises(exerciseId) {
+        var stationId = $('#stationSelect').val();
+
+        $('#exerciseSelect').find('option').remove().end();
+        $('#exerciseSelect').attr('disabled', true);
+        if (stationId != '') {
+            // AJAX Call to get the exercises of station selected
+            $.ajax({
+                url: '/api/v1/exercises',
+                method: "GET",
+                data: {
+                    station_id: stationId
+                }
+            }).done(function(data) {
+                // Ok, add options in exercise Select
+                // First remove previous options
+
+                // Add all the exercises of the station
+                var count = 0;
+                $.each(data.data, function(i, item) {
+                    count ++;
+                    $('#exerciseSelect').append($('<option>', {
+                        value: item.id,
+                        text: item.name
+                    }));
+
+                })
+                // If exerciseId is not Null, set the values
+                if (exerciseId) {
+                    $('#exerciseSelect').val(exerciseId);
+                }
+                if (count > 0) {
+                    $('#exerciseSelect').removeAttr('disabled');
+                }
+            });
+        }
+    }
+
+    // Refresh Exercises at the begining
+    refreshExercises(null);
+
+    $('#taskLoad').change(function() {
+        get_max_velocity()
+    });
+
+    $('#taskLaterality').change(function() {
+        get_max_velocity();
+    });
+
+    /* Get max velocity when user selects station, exercice and resistance */
+    function get_max_velocity() {
+        var resistance = $('#taskLoad').val();
+        var stationId = $('#stationSelect').val();
+        var personId = $('#playerId').val();
+        var exerciseId = $('#exerciseSelect').val();
+        var laterality = $('#taskLaterality').val();
+        console.log("Check velocity max");
+        console.log("Resistance: " + resistance);
+        console.log("Station Id: " + stationId);
+        console.log("Exercise Id: " + exerciseId);
+        console.log("Person Id: " + personId);
+        console.log("Laterality:" + laterality);
+        if (resistance) {
+            $.ajax({
+                url: '/api/v1/get_max_velocity',
+                method: "GET",
+                data: {
+                    station_id: stationId,
+                    exerciseId: exerciseId,
+                    personId: personId,
+                    resistance: resistance,
+                    laterality: laterality
+                }
+            }).done(function(data) {
+                // Ok, add options in exercise Select
+                // First remove previous options
+
+                if (data.max_velocity > 0 ) {
+                    console.log("Enable taskPercentMaxSpeed");
+                    $('#taskSpeed').prop('disabled', false);
+                                       $('#taskMaxSpeed').val(data.max_velocity.toFixed(2));
+                                       $('#taskMaxSpeed').prop('disabled', false);
+                    $('#taskpercentMaxSpeed').prop('disabled', false);
+                } else {
+                    // No velocity max, means disable velocityMAx control
+                    console.log("Disable taskPercentMaxSpeed");
+                    $('#taskSpeed').prop('disabled', false);
+                                       $('#taskMaxSpeed').val('');
+                                       $('#taskMaxSpeed').prop('disabled', true);
+                    $('#taskpercentMaxSpeed').prop('disabled', true);
+                }
+        });
+    } else {
+        // Wait until user enters resistance
+       }
+    }
+
+
+});
+
+$('#taskpercentMaxSpeed').change(function(){
+       // Calculate the max velocity
+       var maxVelocity = $('#taskMaxSpeed').val();
+       var percent = $(this).val();
+       var calculateVelocity = (percent * maxVelocity) / 100;
+       $('#taskSpeed').val(calculateVelocity.toFixed(2));
+});
+
+
+</script>
 {% endblock %}
diff --git a/chronojumpserver/templates/results.html b/chronojumpserver/templates/results.html
index edeb9d3..3b07219 100755
--- a/chronojumpserver/templates/results.html
+++ b/chronojumpserver/templates/results.html
@@ -65,5 +65,362 @@
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/dataTables.buttons.min.js') 
}}"></script>
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/buttons.bootstrap.min.js') 
}}"></script>
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/buttons.html5.min.js') 
}}"></script>
-<script src="{{ url_for('js', filename='results.js') }}"></script>
+<script>
+/*!
+ * Results javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * Copyright (C) 2017  Xavier de Blas <xaviblas gmail com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+ function formatDateNumber(val) {
+        if (val < 10) {
+                return '0' + val;
+        } else {
+                return val;
+        }
+ }
+
+$(document).ready(function() {
+
+  var refreshIntervalId;
+
+  var COLUMN_PLAYER = 4;
+  var COLUMN_STATION = 5;
+  var COLUMN_EXERCISE = 6;
+
+  // Initialize datatable with results
+  $("input[name='filterByDayOptions']").on('click', function() {
+       var table = $('#results').DataTable();
+       table.draw();
+  });
+
+  $.fn.dataTable.ext.search.push(
+       function(settings, data, dataIndex) {
+         var filter = $("input[name='filterByDayOptions']:checked").val();
+         var date = Date.parse(data[1]); // use data for the age column
+         var d = new Date();
+         if (filter != "all") {
+               d.setDate(d.getDate() - filter - 1);
+               if (date >= d) {
+                 return true;
+               }
+               return false;
+         } else {
+               return true;
+         }
+
+
+       }
+  );
+  /* Create the table for results with Datatables */
+  var table = $('#results').DataTable({
+       "columns": [{
+               type: "num",
+               title: "id",
+               data: "id",
+               visible: false
+         },
+         {
+               type: "date",
+               data: "dt",
+               visible: false
+         },
+         {
+               type: "html",
+               orderable:false,
+               render: function(value, type, row) {
+                 return '<input class="deleteCheckbox" type="checkbox" data-result-id="' + row.id + '"/>';
+               }
+         },
+         {
+               type: "customdate",
+               title: "Data",
+               data: "dt",
+               render: function(value) {
+
+                 // Compare with today
+                 today = new Date();
+                 // To adjust the hour
+                 var _offsetHours = today.getTimezoneOffset()/60;
+                 var dd = today.getDate();
+                 var mm = today.getMonth();
+                 var yy = today.getFullYear();
+
+                 var dt = new Date(value);
+                 dt.setHours(dt.getHours() + _offsetHours);
+                 var dd2 = dt.getDate();
+                 var mm2 = dt.getMonth();
+                 var yy2 = dt.getFullYear();
+                 var hh = dt.getHours();
+                 var MM = dt.getMinutes();
+                 if (dd == dd2 && mm == mm2 && yy == yy2) {
+                       // Today, show the result hours and minute
+                       return formatDateNumber(hh) + ':' + formatDateNumber(MM);
+                 } else if (yy == yy2) {
+                       // Same year
+                       return dd2 + "/" + (mm2 + 1) + " " + formatDateNumber(hh) + ":" + 
formatDateNumber(MM);
+                 } else {
+                       return dd2 + "/" + (mm2 + 1) + "/" + yy2 + " " + formatDateNumber(hh) + ":" + 
formatDateNumber(MM);
+                 }
+
+               }
+         },
+         {
+               type: "html",
+               data: "personName",
+               title: "Jugador"
+         },
+         {
+               type: "html",
+               data: "stationName",
+               title: "Estació"
+         },
+         {
+               type: "html",
+               data: "exerciseName",
+               title: "Exercici"
+         },
+         {
+               type: "html",
+               data: "laterality",
+               title: "RL"
+         },
+         {
+               type: "num",
+               title: "Càrrega",
+               data: "resistance",
+               render: $.fn.dataTable.render.number('', ',', 2)
+         },
+         {
+               type: "num",
+               data: "repetitions",
+               title: "n"
+         },
+         {
+               type: "num",
+               data: "lossBySpeed",
+               title: "Pèrdua"
+         },
+         {
+               type: "num",
+               data: "numBySpeed",
+               title: "rep",
+               className: 'colResult'
+         },
+         {
+               type: "num",
+               data: "rangeBySpeed",
+               title: "rang",
+               className: 'colResult',
+               render: $.fn.dataTable.render.number('', ',', 2)
+         },
+         {
+               type: "num",
+               title: "Vm",
+               data: "vmeanBySpeed",
+               className: 'colResult',
+               render: $.fn.dataTable.render.number('', ',', 2)
+         },
+         {
+               type: "num",
+               title: "VM",
+               data: "vmaxBySpeed",
+               className: 'colResult',
+               render: $.fn.dataTable.render.number('', ',', 2)
+         },
+         {
+               type: "num",
+               title: "Pm",
+               data: "pmeanBySpeed",
+               className: 'colResult',
+               render: $.fn.dataTable.render.number('', ',', 2)
+         },
+         {
+               type: "num",
+               title: "PM",
+               data: "pmaxBySpeed",
+               className: 'colResult',
+               render: $.fn.dataTable.render.number('', ',', 2)
+         }
+       ],
+       "dom": "<'row'<'resultsFilter'>><'row'<'col-sm-6'B><'col-sm-6'f>>rtip",
+       buttons: [
+                       { extend: 'csv', text: 'Exportar Resultats', className: "btn btn-primary", 
fieldSeparator: "&nbsp;"},
+                       { text: 'Eliminar registres',
+                         className: "btn btn-danger btnDeleteResults",
+                         enabled: false,
+                         action: function(e, dt, node, config) {
+                               // Ask for confirmation
+                               var total =  $('.deleteCheckbox:checked').length;
+                               if (total == 1) {
+                                 var r = confirm("Estàs segur de que vols esborrar aquest resultat?");
+                               } else {
+                                 var r = confirm("Estàs segur de que vols esborrar aquests resultats?");
+                               }
+                               if (r == true) {
+                                 var results = [];
+                                 $.each($('.deleteCheckbox:checked'), function(index, value) {
+                                       var v = $(value);
+                                       console.log(index + ":" + v.attr('data-result-id'));
+                                       results.push(v.attr('data-result-id'));
+
+                                 });
+                                 var url = '/api/v1/results/delete';
+                                 $.ajax({
+                                       url: url,
+                                       type: "POST",
+                                       contentType: 'application/json;charset=UTF-8',
+                                       data: JSON.stringify(results)
+                                 }).done(function(msg){
+                                       // Results have been deleted. Refresh table and enable again the 
interval
+                                       console.log(msg);
+                                       $('.btnDeleteResults').addClass('disabled');
+                                       table.ajax.reload(null, false);
+                                       refreshIntervalId = refreshIntervalTrigger();
+                                       console.log("Interval refresh is enabled with id " + 
refreshIntervalId);
+                                 })
+                               }
+                         }}
+               ],
+       "pageLength": 15,
+       "order": [ 
+         [0, 'desc']
+       ],
+       "ajax": "/api/v1/results",
+       "processing": true,
+       "severSide": true,
+       "language": {
+         "lengthMenu": "Mostrant _MENU_ resultats per pàgina",
+         "zeroRecords": "No hi han resultats per mostrar",
+         "info": "Mostrant els resultats _START_ a _END_ d'un total de _TOTAL_",
+         "infoEmpty": "La busqueda no ha retornat resultats",
+         "infoFiltered": "(filtrat de _MAX_ resultats)",
+         "decimal": ",",
+         "thousands": ".",
+         "paginate": {
+               "first": '<i class="fa fa-fast-backward"></i>',
+               "last": '<i class="fa fa-fast-forward"></i>',
+               "next": '<i class="fa fa-forward"></i>',
+               "previous": '<i class="fa fa-backward"></i>'
+         },
+         "search": "Cerca:"
+       },
+       initComplete: function() {
+         /*
+                 The following functions are to create the filters for results view,
+                 by player, exercice and station.
+         */
+         this.api().columns().every(function() {
+
+               var column = this;
+               var idx = column.index();
+               if (idx == COLUMN_PLAYER) {
+                 var select = $('<select class="form-control"><option value="">Tots els 
jugadors</option></select>')
+                       .appendTo($('#filterByPlayer'))
+                       .on('change', function() {
+                         // Player selected
+                         var val = $.fn.dataTable.util.escapeRegex(
+                               $(this).val()
+                         );
+
+                         column
+                               .search(val ? '^' + val + '$' : '', true, false)
+                               .draw();
+                         // Hide column if is a selected Player
+                         //console.log(val);
+                         column.visible(val == '');
+                       });
+
+                 column.data().unique().sort().each(function(d, j) {
+                       select.append('<option value="' + d + '">' + d + '</option>')
+                 });
+               } else if (idx == COLUMN_STATION) {
+                 var select = $('<select class="form-control"><option value="">Totes les 
estacions</option></select>')
+                       .appendTo($('#filterByStation'))
+                       .on('change', function() {
+                         var val = $.fn.dataTable.util.escapeRegex(
+                               $(this).val()
+                         );
+
+                         column
+                               .search(val ? '^' + val + '$' : '', true, false)
+                               .draw();
+                         column.visible(val == '');
+                       });
+
+                 column.data().unique().sort().each(function(d, j) {
+                       select.append('<option value="' + d + '">' + d + '</option>')
+                 });
+               } else if (idx == COLUMN_EXERCISE) {
+                 var select = $('<select class="form-control"><option value="">Tots els 
exercicis</option></select>')
+                       .appendTo($('#filterByExercice'))
+                       .on('change', function() {
+                         var val = $.fn.dataTable.util.escapeRegex(
+                               $(this).val()
+                         );
+
+                         column
+                               .search(val ? '^' + val + '$' : '', true, false)
+                               .draw();
+                         column.visible(val == '');
+                       });
+
+                 column.data().unique().sort().each(function(d, j) {
+                       select.append('<option value="' + d + '">' + d + '</option>')
+                 });
+               }
+         });
+
+         // Called every time a delete checkbox is changed
+         $('.deleteCheckbox').on('change', function() {
+                 var totalChecked = $('.deleteCheckbox:checked').length;
+                 //console.log(totalChecked);
+                 if (totalChecked > 0) {
+                       // Disable the refresh interval
+                       if (refreshIntervalId != -1) {
+                         clearInterval(refreshIntervalId);
+                         //console.log("Interval refresh is disabled");
+                         refreshIntervalId = -1;
+                         $('.btnDeleteResults').removeClass('disabled');
+                       }
+                 } else {
+                       // Enable again the refresh interval
+                       $('.btnDeleteResults').addClass('disabled');
+                       refreshIntervalId = refreshIntervalTrigger();
+                       console.log("Interval refresh is enabled with id " + refreshIntervalId);
+                 }
+         });
+
+       }
+  });
+
+
+  function refreshIntervalTrigger() {
+       return setInterval(function() {
+          /* Set the interval for refresh */
+          table.ajax.reload(null, false);
+        }, 15000);
+   };
+
+   refreshIntervalId = refreshIntervalTrigger();
+   console.log("Interval refresh is enabled with id " + refreshIntervalId);
+});
+</script>
+
 {% endblock %}
diff --git a/chronojumpserver/templates/sprints.html b/chronojumpserver/templates/sprints.html
index 89ec5e5..186516f 100755
--- a/chronojumpserver/templates/sprints.html
+++ b/chronojumpserver/templates/sprints.html
@@ -50,5 +50,282 @@
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/dataTables.buttons.min.js') 
}}"></script>
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/buttons.bootstrap.min.js') 
}}"></script>
 <script src="{{ url_for('assets', filename='DataTables/extensions/Buttons/js/buttons.html5.min.js') 
}}"></script>
-<script src="{{ url_for('js', filename='sprints.js') }}"></script>
+<script>
+/*!
+ * ResultSprints javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+function formatDateNumber(val) {
+    if (val < 10) {
+        return '0' + val;
+    } else {
+        return val;
+    }
+}
+
+$(document).ready(function() {
+
+  // Initialize datatable with results
+  $("input[name='filterByDayOptions']").on('click', function() {
+    var table = $('#results').DataTable();
+    table.draw();
+  });
+
+  $.fn.dataTable.ext.search.push(
+    function(settings, data, dataIndex) {
+      var filter = $("input[name='filterByDayOptions']:checked").val();
+      var date = Date.parse(data[1]); // use data for the age column
+      var d = new Date();
+      if (filter != "all") {
+        d.setDate(d.getDate() - filter - 1);
+        if (date >= d) {
+          return true;
+        }
+        return false;
+      } else {
+        return true;
+      }
+
+
+    }
+  );
+
+  var table = $('#sprints').DataTable({
+    "columns": [{
+        type: "num",
+        title: "id",
+        data: "id",
+        visible: false
+      },
+      {
+        type: "date",
+        data: "dt",
+        visible: false
+      },
+      {
+        type: "customdate",
+        title: "Data",
+        data: "dt",
+        render: function(value) {
+          // Compare with today
+          today = new Date();
+          // To adjust the hour
+          var _offsetHours = today.getTimezoneOffset()/60;
+          var dd = today.getDate();
+          var mm = today.getMonth();
+          var yy = today.getFullYear();
+
+          var dt = new Date(value);
+          dt.setHours(dt.getHours() + _offsetHours);
+          var dd2 = dt.getDate();
+          var mm2 = dt.getMonth();
+          var yy2 = dt.getFullYear();
+          var hh = dt.getHours();
+          var MM = dt.getMinutes();
+          if (dd == dd2 && mm == mm2 && yy == yy2) {
+            // Today, show the result hours and minute
+            return formatDateNumber(hh) + ':' + formatDateNumber(MM);
+          } else if (yy == yy2) {
+            // Same year
+            return dd2 + "/" + (mm2 + 1) + " " + formatDateNumber(hh) + ":" + formatDateNumber(MM);
+          } else {
+            return dd2 + "/" + (mm2 + 1) + "/" + yy2 + " " + formatDateNumber(hh) + ":" + 
formatDateNumber(MM);
+          }
+
+        }
+      },
+      {
+        type: "html",
+        data: "personName",
+        title: "Jugador"
+      },
+      {
+        type: "html",
+        title: "Distancia",
+        data: "distances"
+      },
+      {
+        type: "num",
+        title: "t1",
+        data: "t1",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "t2",
+        data: "t2",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "t3",
+        data: "t4",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "t4",
+        data: "t4",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        data: "k",
+        title: "k",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "VMax",
+        data: "vmax",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "AMax",
+        data: "amax",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "FMax",
+        data: "fmax",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      },
+      {
+        type: "num",
+        title: "PMax",
+        data: "pmax",
+        className: 'colResult',
+        render: $.fn.dataTable.render.number('', ',', 2)
+      }
+    ],
+    "dom": "<'row'<'resultsFilter'>><'row'<'col-sm-6'B><'col-sm-6'f>>rtip",
+    buttons: [
+            { extend: 'csv', text: 'Exportar Sprints', className: "btn btn-primary", fieldSeparator: ";"}
+        ],
+    "pageLength": 15,
+    "order": [ 
+      [0, 'desc']
+    ],
+    "ajax": "/api/v1/sprints",
+    "processing": true,
+    "severSide": true,
+    "language": {
+      "lengthMenu": "Mostrant _MENU_ resultats per pàgina",
+      "zeroRecords": "No hi han resultats per mostrar",
+      "info": "Mostrant els resultats _START_ a _END_ d'un total de _TOTAL_",
+      "infoEmpty": "La busqueda no ha retornat resultats",
+      "infoFiltered": "(filtrat de _MAX_ resultats)",
+      "decimal": ",",
+      "thousands": ".",
+      "paginate": {
+        "first": '<i class="fa fa-fast-backward"></i>',
+        "last": '<i class="fa fa-fast-forward"></i>',
+        "next": '<i class="fa fa-forward"></i>',
+        "previous": '<i class="fa fa-backward"></i>'
+      },
+      "search": "Cerca:"
+    },
+    initComplete: function() {
+      /*
+          The following functions are to create the filters for results view,
+          by player, exercice and station.
+      */
+      this.api().columns().every(function() {
+
+        var column = this;
+        var idx = column.index();
+        if (idx == 3) {
+          var select = $('<select class="form-control"><option value="">Tots els jugadors</option></select>')
+            .appendTo($('#filterByPlayer'))
+            .on('change', function() {
+              // Player selected
+              var val = $.fn.dataTable.util.escapeRegex(
+                $(this).val()
+              );
+
+              column
+                .search(val ? '^' + val + '$' : '', true, false)
+                .draw();
+              // Hide column if is a selected Player
+              //console.log(val);
+              column.visible(val == '');
+            });
+
+          column.data().unique().sort().each(function(d, j) {
+            select.append('<option value="' + d + '">' + d + '</option>')
+          });
+        } else if (idx == 4) {
+          var select = $('<select class="form-control"><option value="">Totes les 
estacions</option></select>')
+            .appendTo($('#filterByStation'))
+            .on('change', function() {
+              var val = $.fn.dataTable.util.escapeRegex(
+                $(this).val()
+              );
+
+              column
+                .search(val ? '^' + val + '$' : '', true, false)
+                .draw();
+              column.visible(val == '');
+            });
+
+          column.data().unique().sort().each(function(d, j) {
+            select.append('<option value="' + d + '">' + d + '</option>')
+          });
+        } else if (idx == 5) {
+          var select = $('<select class="form-control"><option value="">Tots els 
exercicis</option></select>')
+            .appendTo($('#filterByExercice'))
+            .on('change', function() {
+              var val = $.fn.dataTable.util.escapeRegex(
+                $(this).val()
+              );
+
+              column
+                .search(val ? '^' + val + '$' : '', true, false)
+                .draw();
+              column.visible(val == '');
+            });
+
+          column.data().unique().sort().each(function(d, j) {
+            select.append('<option value="' + d + '">' + d + '</option>')
+          });
+        }
+      });
+    }
+  });
+
+
+  setInterval(function() {
+    /* Set the interval for refresh */
+    table.ajax.reload(null, false);
+  }, 15000);
+
+});
+
+</script>
 {% endblock %}
diff --git a/chronojumpserver/templates/station_list.html b/chronojumpserver/templates/station_list.html
index e02979a..1fe128a 100644
--- a/chronojumpserver/templates/station_list.html
+++ b/chronojumpserver/templates/station_list.html
@@ -94,5 +94,324 @@
 {{ super() }}
 <script src="{{ url_for('assets', filename='DataTables/media/js/jquery.dataTables.min.js') }}"></script>
 <script src="{{ url_for('assets', filename='DataTables/media/js/dataTables.bootstrap.min.js') }}"></script>
-<script src="{{ url_for('js', filename='stations.js') }}"></script>
+<script>
+/*!
+ * Station javascript functions for Chronojump Server
+ * Author: Marcos Venteo <mventeo gmail com>
+ * version: 1.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/* Show stationModalForm to create a new station */
+$('#btnShowStationModalForm').on('click', function()
+{
+  $('stationId').val('-1');
+  $('#stationName').val('');
+  $('#stationType').val('G');
+  $('#btnAddModifyStation').text('Afegir');
+  $('#btnDeleteStation').addClass('hide');
+  $('#stationModalForm').modal();
+});
+
+
+
+/* Add or Modify stations */
+$('#btnAddModifyStation').on('click', function() {
+  var stationId = $('#stationId').val();
+  var stationName = $('#stationName').val();
+  var stationType = $('#stationType').val();
+  // Hide the modal form
+
+  $.ajax({
+      url: '/api/v1/station',
+      method: 'PUT',
+      data: {
+          stationId: stationId,
+          stationName: stationName,
+          stationType: stationType
+      }
+  }).done(function(data) {
+      //alert(data.stationId);
+      $('#stationModalForm').modal('hide');
+      var table = $('#stations').DataTable();
+      var stationId = data.stationId;
+      var stationsCount = table.data().count();
+      //alert(stationsCount);
+      table.ajax.reload(function(){
+          // Select the station just created
+          table.$('tr.selected').removeClass('selected');
+
+          table.rows().every( function ( rowIdx, tableLoop, rowLoop ) {
+                var d = this.data();
+                if (d.id == stationId) {
+                    $(this.node()).addClass('selected');
+                    if ( stationsCount > 0 ) {
+                        $('#exercises').DataTable().destroy();
+                    }
+                    loadExercises();
+                }
+            } );
+      }, false);
+
+  }).fail(function(xhr, status, error){
+      var err = eval("(" + xhr.responseText + ")");
+      alert(err.msg);
+  });
+});
+
+/* Delete the station via Ajax .*/
+$('#btnDeleteStation').on('click', function() {
+    /* TODO: Implement Confirmation */
+    var stationId = $('#stationId').val();
+    $.ajax({
+        url: '/api/v1/station',
+        method: 'DELETE',
+        data: {
+            stationId: stationId
+        }
+    }).done(function(data) {
+        $('#stationModalForm').modal('hide');
+        var table = $('#stations').DataTable();
+        table.ajax.reload(null, false);
+    }).fail(function(xhr, status, error){
+        var err = eval("(" + xhr.responseText + ")");
+        alert(err.msg);
+    });
+});
+
+
+/* Show execiseModalForm to create a new exercise */
+$('#btnShowExerciseModalForm').on('click', function()
+{
+   $('#exerciseId').val('-1');
+   $('#exerciseName').val('');
+   $('#exercisePercentBodyMassDisplaced').val('0');
+   $('#btnAddModifyExercise').text('Afegir');
+   $('#btnDeleteExercise').addClass('hide');
+   $('#exerciseModalForm').modal();
+});
+
+
+/* Add / Modify or Delete exercises */
+$('#btnAddModifyExercise').on('click', function() {
+
+  var exerciseId = $('#exerciseId').val();
+  var name = $('#exerciseName').val();
+  var percentBodyMassDisplaced = $('#exercisePercentBodyMassDisplaced').val();
+  // Hide the modal form
+  var stationId = $('#selectedStationId').val();
+  console.log('The selected station is ' + stationId);
+  $.ajax({
+      url: '/api/v1/exercise',
+      method: 'PUT',
+      data: {
+          id: exerciseId,
+          stationId: stationId,
+          name: name,
+          percentBodyMassDisplaced: percentBodyMassDisplaced
+      }
+  }).done(function(data) {
+
+      $('#exerciseModalForm').modal('hide');
+      // Reload the table
+      var table = $('#exercises').DataTable();
+      table.ajax.reload(null, false);
+  }).fail(function(xhr, status, error){
+      var err = eval("(" + xhr.responseText + ")");
+      alert(err.msg);
+  });
+});
+
+/* Delete the exercise via Ajax .*/
+$('#btnDeleteExercise').on('click', function() {
+    /* TODO: Implement Confirmation */
+    var exerciseId = $('#exerciseId').val();
+    $.ajax({
+        url: '/api/v1/exercise',
+        method: 'DELETE',
+        data: {
+            exerciseId: exerciseId
+        }
+    }).done(function(data) {
+        $('#exerciseModalForm').modal('hide');
+        var table = $('#exercises').DataTable();
+        table.ajax.reload(null, false);
+    }).fail(function(xhr, status, error){
+        var err = eval("(" + xhr.responseText + ")");
+        alert(err.msg);
+    });
+});
+
+/* Load exercises from the station selected creating a datatable and loading
+   the exercises via Ajax */
+function loadExercises(station_id) {
+    var stationTable = $('#stations').DataTable();
+    var station = stationTable.row('.selected').data();
+
+    $('#selectedStationName').text(station.name);
+    $('#selectedStationId').val(station.id);
+    var table = $('#exercises').DataTable({
+        "columns": [
+            {
+                type: "num",
+                title: "id",
+                data: 'id',
+                visible: false
+            },
+            {
+                type: "html",
+                data: "name",
+                title: "Nom"
+            },
+            {
+                type: "num",
+                data: 'percentBodyMassDisplaced',
+                title: "% Masa de cos desplaçada",
+                render: $.fn.dataTable.render.number('', ',', 2)
+            },
+            {
+                type: "html",
+                data: null,
+                title: "",
+                orderable: false,
+                render: function(val, row) {
+                    return "<button class='btn btn-primary'>Editar</button>"
+                }
+            }
+        ],
+        "dom" : "",
+        "pageLength": 20,
+        "ajax": {
+            'url': "/api/v1/exercises",
+            'method': 'GET',
+            'data': {
+                station_id: station.id
+            }
+        },
+        "language": {
+            "zeroRecords": "No hi han exercicis per mostrar",
+        },
+    });
+
+
+
+}
+
+/*
+  Load Players and tasks
+*/
+$(document).ready(function() {
+
+    var stationTable = $('#stations').DataTable({
+        "columns": [
+            {
+                type: "num",
+                title: "id",
+                data: 'id',
+                visible: false
+            },
+            {
+                type: "html",
+                data: "name",
+                title: "Nom",
+                className: 'stationName'
+            },
+            {
+                type: "html",
+                data: "type",
+                title: "Tipus",
+                render: function(val) {
+                    if (val == 'I') {
+                        return 'Inercial';
+                    }else if (val == 'G') {
+                        return 'Gravitatori';
+                    } else {
+                        return 'Sprint';
+                    }
+                }
+            },
+            {
+                type: "html",
+                data: null,
+                title: "",
+                orderable: false,
+                render: function(val, row) {
+                    return "<button class='btn btn-primary'>Editar</button>"
+                }
+            }
+        ],
+        "ajax": {
+            'url': "/api/v1/stations",
+            'method': 'GET'
+        },
+        "dom" : "",
+        "pageLength": 20,
+        "language": {
+            "zeroRecords": "No hi han estacions per mostrar",
+        },
+        "initComplete": function(){
+            // set the first station as selected
+            $('#stations tbody').find('tr:first').addClass('selected');
+            // Load the exercises from this station
+            loadExercises();
+        }
+    });
+
+    $('#stations tbody').on( 'click', 'td.stationName', function () {
+        var tr = $(this).parent();
+        if ( !$(tr).hasClass('selected') ) {
+            stationTable.$('tr.selected').removeClass('selected');
+            $(tr).addClass('selected');
+            // Destroy the previous exercise table
+            $('#exercises').DataTable().destroy();
+            // Call load exercise function
+            loadExercises();
+        }
+
+
+    } );
+
+    $('#stations').on('click', 'button', function() {
+        var station = stationTable.row($(this).parents('tr')).data();
+        $('#stationId').val(station.id);
+        $('#stationName').val(station.name);
+        $('#stationType').val(station.type);
+        $('#btnAddModifyStation').text('Modificar');
+        $('#btnDeleteStation').removeClass('hide');
+        $('#stationModalForm').modal();
+    });
+
+
+    $('#exercises').on('click', 'button', function() {
+        var table = $('#exercises').DataTable();
+        var exercise = table.row($(this).parents('tr')).data();
+        $('#exerciseId').val(exercise.id);
+        $('#exerciseName').val(exercise.name);
+        $('#exercisePercentBodyMassDisplaced').val(exercise.percentBodyMassDisplaced);
+        $('#btnAddModifyExercise').text('Modificar');
+        $('#btnDeleteExercise').removeClass('hide');
+        $('#exerciseModalForm').modal();
+    });
+
+
+
+
+
+});
+
+</script>
 {% endblock %}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]