您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

97 行
3.5 KiB

  1. // assets/scripts/duration.js
  2. // Zentrale Logik für Zeiteingabe – wird von entries.js importiert
  3. // ── Konfiguration ─────────────────────────────────────────────────────────────
  4. // Auf false setzen um Viertelstunden-Runden zu deaktivieren
  5. export const DURATION_CONFIG = {
  6. roundToQuarter: true,
  7. };
  8. // ── Parser ────────────────────────────────────────────────────────────────────
  9. /**
  10. * Parst Zeiteingaben in Minuten.
  11. *
  12. * Unterstützte Formate:
  13. * "1:30" → 90 (Stunden:Minuten)
  14. * "8 12" → 240 (von 8 bis 12 Uhr)
  15. * "1,75" → 105 (Dezimalstunden mit Komma)
  16. * "1.75" → 105 (Dezimalstunden mit Punkt)
  17. * "2" → 120 (nur Stunden als ganze Zahl)
  18. * "0:00" → 0 (Stopp/Reset)
  19. */
  20. export function parseDuration(input) {
  21. input = String(input).trim();
  22. if (!input || input === '0' || input === '0:00') return 0;
  23. // "8 12" → von 8 bis 12 Uhr
  24. if (/^\d+\s+\d+$/.test(input)) {
  25. const parts = input.split(/\s+/).map(Number);
  26. const minutes = (parts[1] - parts[0]) * 60;
  27. return Math.max(0, minutes);
  28. }
  29. // "1:30" → Stunden:Minuten
  30. if (input.includes(':')) {
  31. const [h, m] = input.split(':').map(s => parseInt(s) || 0);
  32. return h * 60 + m;
  33. }
  34. // "1,75" oder "1.75" → Dezimalstunden
  35. if (input.includes(',') || input.includes('.')) {
  36. const hours = parseFloat(input.replace(',', '.'));
  37. return isNaN(hours) ? 0 : Math.round(hours * 60);
  38. }
  39. // "2" → 2 Stunden
  40. const hours = parseInt(input);
  41. return isNaN(hours) ? 0 : hours * 60;
  42. }
  43. // ── Rounding ──────────────────────────────────────────────────────────────────
  44. /**
  45. * Rundet Minuten auf die nächste Viertelstunde auf.
  46. * 0 bleibt 0 (Stopp).
  47. */
  48. export function roundToQuarter(minutes) {
  49. if (!DURATION_CONFIG.roundToQuarter) return minutes;
  50. if (minutes === 0) return 0;
  51. const interval = window.TT?.trackingInterval ?? 15;
  52. return Math.ceil(minutes / interval) * interval;
  53. }
  54. // ── Formatter ─────────────────────────────────────────────────────────────────
  55. export function formatMinutes(minutes) {
  56. const h = Math.floor(minutes / 60);
  57. const m = minutes % 60;
  58. return `${h}:${String(m).padStart(2, '0')}`;
  59. }
  60. // ── Blur-Handler (global, per Event Delegation) ───────────────────────────────
  61. // Reagiert auf blur an allen Dauer-Inputs, egal ob server-gerendert oder JS-erstellt
  62. export function initDurationBlurHandler() {
  63. document.addEventListener('blur', e => {
  64. if (!(e.target instanceof Element)) return;
  65. if (!e.target.matches('#create-duration, .edit-duration')) return;
  66. const raw = e.target.value;
  67. const minutes = roundToQuarter(parseDuration(raw));
  68. e.target.value = formatMinutes(minutes);
  69. }, true); // capture=true, weil blur nicht bubbled
  70. }
  71. /**
  72. * Validiert eine Dauer in Minuten.
  73. * > 1440 (24h) → error
  74. * > 480 (8h) → warn
  75. */
  76. export function validateDuration(minutes) {
  77. if (minutes > 1440) return { status: 'error' };
  78. if (minutes > 480) return { status: 'warn' };
  79. return { status: 'ok' };
  80. }