mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-19 04:40:32 -05:00
1ebfbf39de
Performance: - Fix N+1 queries in reports.py with joinedload for TimeEntry.project, TimeEntry.user, TimeEntry.task, and Project.client across 6 query locations - Replace per-task time_entries loops with batch UPDATE queries in tasks.py - Use efficient subquery for favorite project IDs in projects.py Architecture: - Add get_by_id() and get_by_name() methods to ProjectService and ClientService - Route project/client lookups through service layer in timer.py, projects.py, and clients.py instead of direct Model.query calls Security: - Add sanitize_input() with length limits to form inputs in clients.py, projects.py, timer.py, issues.py, and auth.py - Add email format validation for client creation - Warn at startup when SECRET_KEY uses the default value or is too short in ProductionConfig - Replace 7 bare except: pass clauses with specific exception types (OSError, IOError, TypeError, ValueError) in admin.py, settings.py, and invoice.py Authorization: - Migrate all @admin_required decorators to @admin_or_permission_required() with granular permissions (manage_roles, manage_kanban, manage_webhooks, manage_api_tokens, manage_integrations, access_admin) across permissions.py, kanban.py, webhooks.py, and admin.py (28 routes total) Frontend: - Remove 40+ console.log debug statements across 18 JS files - Replace 42 inline onclick/onchange handlers in base.html with delegated event listeners using data-dropdown and data-no-propagation attributes - Migrate 6 inline handlers in time_entries_overview.html to addEventListener - Extract shared typing detection into typing-utils.js, eliminating 5 duplicate isTyping() implementations across keyboard shortcut files - Add missing aria-label attributes to icon-only buttons Dependencies: - Migrate from pytz to stdlib zoneinfo (Python 3.9+) across all 6 files that used pytz; replace pytz with tzdata in requirements.txt - Separate dev/test dependencies into requirements-dev.txt - Configure RotatingFileHandler (10MB, 5 backups) for app and JSON logs Co-authored-by: Cursor <cursoragent@cursor.com>
61 lines
1.7 KiB
JavaScript
61 lines
1.7 KiB
JavaScript
/**
|
|
* Shared typing detection utility.
|
|
*
|
|
* Determines whether the user is currently focused on an input element
|
|
* (input, textarea, select, contenteditable, or rich text editor) so that
|
|
* keyboard shortcuts can be suppressed while the user is typing.
|
|
*
|
|
* Usage:
|
|
* if (window.TimeTracker.isTyping(event)) return;
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var EDITOR_SELECTORS = [
|
|
'.toastui-editor',
|
|
'.toastui-editor-contents',
|
|
'.ProseMirror',
|
|
'.CodeMirror',
|
|
'.ql-editor',
|
|
'.tox-edit-area',
|
|
'.note-editable',
|
|
'[contenteditable="true"]',
|
|
'.toastui-editor-ww-container',
|
|
'.toastui-editor-md-container',
|
|
'.gjs-frame' // GrapesJS editor
|
|
];
|
|
|
|
/**
|
|
* Check whether the event target is an input-like element.
|
|
*
|
|
* @param {Event|KeyboardEvent} ev - The DOM event to inspect.
|
|
* @returns {boolean} true if the user is typing in a form field or editor.
|
|
*/
|
|
function isTyping(ev) {
|
|
var target = ev && ev.target;
|
|
if (!target) return false;
|
|
|
|
var tag = (target.tagName || '').toLowerCase();
|
|
|
|
// Standard form fields
|
|
if (tag === 'input' || tag === 'textarea' || tag === 'select' || target.isContentEditable) {
|
|
return true;
|
|
}
|
|
|
|
// Rich text / code editors
|
|
if (target.closest) {
|
|
for (var i = 0; i < EDITOR_SELECTORS.length; i++) {
|
|
if (target.closest(EDITOR_SELECTORS[i])) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Expose on a shared namespace
|
|
window.TimeTracker = window.TimeTracker || {};
|
|
window.TimeTracker.isTyping = isTyping;
|
|
})();
|