/** * Main JavaScript file for Fitness Parser * Uses jQuery for DOM manipulation */ $(document).ready(function() { console.log('Fitness Parser JS loaded'); // Simple example functionality $('.card').on('click', function() { $(this).toggleClass('bg-light'); }); // Bootstrap tooltips (explanations of the metrics) document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach( (element) => new bootstrap.Tooltip(element) ); // Exercise search: open the history right after a suggestion is picked from the list. // Typing, pasting and deleting have their own inputType, so a half-typed name that // equals a shorter exercise name doesn't submit early; Enter/button always work. const $exerciseInput = $('#exercise-input'); if ($exerciseInput.length) { const exerciseNames = new Set( $('#exercise-names option').map((_, option) => option.value).get() ); $exerciseInput.on('input', function(event) { const inputType = event.originalEvent && event.originalEvent.inputType; const picked = !inputType || inputType === 'insertReplacementText'; if (picked && exerciseNames.has(this.value)) { this.form.submit(); } }); } // Exercise progress chart (Chart.js): two series over time, each on its own y axis. // Points are [UTC timestamp in ms, value]; the x axis is linear so gaps between // trainings are proportional to the real time. const chartDataElement = document.getElementById('progress-chart-data'); if (chartDataElement && window.Chart) { const series = JSON.parse(chartDataElement.textContent).series; const colors = ['#0d6efd', '#fd7e14']; const formatDate = (timestamp, options) => new Date(timestamp).toLocaleDateString('ru-RU', { ...options, timeZone: 'UTC' }); const scales = { x: { type: 'linear', ticks: { maxTicksLimit: 8, callback: (value) => formatDate(value, { month: 'short', year: 'numeric' }), }, }, }; series.forEach((item, index) => { scales['y' + index] = { position: index === 0 ? 'left' : 'right', grid: { drawOnChartArea: index === 0 }, title: { display: true, text: item.label, color: colors[index] }, }; }); new Chart(document.getElementById('progress-chart'), { type: 'line', data: { datasets: series.map((item, index) => ({ label: item.label, data: item.points.map(([x, y]) => ({ x, y })), yAxisID: 'y' + index, borderColor: colors[index], backgroundColor: colors[index], borderWidth: 2, pointRadius: 3, tension: 0.2, })), }, options: { maintainAspectRatio: false, interaction: { mode: 'nearest', axis: 'x', intersect: false }, scales, plugins: { tooltip: { callbacks: { title: (items) => formatDate(items[0].parsed.x, {}), }, }, }, }, }); } // Tables with search, sorting and paging by DataTables const tableOptions = { pageLength: 50, lengthMenu: [25, 50, 100, 200], order: [], // keep the order from the server: newest training first language: { url: document.body.dataset.datatablesLang }, }; // All trainings: date, trainer, exercise, approaches $('#trainings-table').DataTable({ ...tableOptions, columnDefs: [{ targets: 3, orderable: false }], // approaches }); // History of one exercise: date, trainer, approaches, max weight $('#exercise-history-table').DataTable({ ...tableOptions, columnDefs: [{ targets: 2, orderable: false }], // approaches }); });