После рефакторинга

This commit is contained in:
2025-11-18 14:44:32 +03:00
parent 55759ec705
commit c8bcd1adf0
56 changed files with 204454 additions and 683 deletions

View File

@@ -0,0 +1,148 @@
# Sorting Functionality Documentation
## Overview
This document describes the centralized sorting functionality implemented for table columns across the Django application.
## Files Created/Modified
### Created Files:
1. **`dbapp/mainapp/static/js/sorting.js`** - Main sorting JavaScript library
2. **`dbapp/mainapp/static/js/sorting-test.html`** - Test page for manual verification
### Modified Files:
1. **`dbapp/mainapp/templates/mainapp/base.html`** - Added sorting.js script include
2. **`dbapp/mainapp/templates/mainapp/components/_sort_header.html`** - Removed inline script, added data attributes
## Features
### 1. Sort Toggle Logic
- **First click**: Sort ascending (field)
- **Second click**: Sort descending (-field)
- **Third click**: Sort ascending again (cycles back)
### 2. URL Parameter Management
- Preserves all existing GET parameters (search, filters, etc.)
- Automatically resets page number to 1 when sorting changes
- Updates the `sort` parameter in the URL
### 3. Visual Indicators
- Shows up arrow (↑) for ascending sort
- Shows down arrow (↓) for descending sort
- Automatically initializes indicators on page load
- Adds `sort-active` class to currently sorted column
## Usage
### In Templates
Use the `_sort_header.html` component in your table headers:
```django
<thead class="table-dark sticky-top">
<tr>
<th>{% include 'mainapp/components/_sort_header.html' with field='id' label='ID' current_sort=sort %}</th>
<th>{% include 'mainapp/components/_sort_header.html' with field='name' label='Название' current_sort=sort %}</th>
<th>{% include 'mainapp/components/_sort_header.html' with field='created_at' label='Дата создания' current_sort=sort %}</th>
</tr>
</thead>
```
### In Views
Pass the current sort parameter to the template context:
```python
def get(self, request):
sort = request.GET.get('sort', '-id') # Default sort
# Validate allowed sorts
allowed_sorts = ['id', '-id', 'name', '-name', 'created_at', '-created_at']
if sort not in allowed_sorts:
sort = '-id'
# Apply sorting
queryset = Model.objects.all().order_by(sort)
context = {
'sort': sort,
'objects': queryset,
# ... other context
}
return render(request, 'template.html', context)
```
## JavaScript API
### Functions
#### `updateSort(field)`
Updates the sort parameter and reloads the page.
**Parameters:**
- `field` (string): The field name to sort by
**Example:**
```javascript
updateSort('created_at'); // Sort by created_at ascending
```
#### `getCurrentSort()`
Gets the current sort field and direction from URL.
**Returns:**
- Object with `field` and `direction` properties
- `direction` can be 'asc', 'desc', or null
**Example:**
```javascript
const sort = getCurrentSort();
console.log(sort.field); // 'created_at'
console.log(sort.direction); // 'asc' or 'desc'
```
#### `initializeSortIndicators()`
Automatically called on page load to show current sort state.
## Requirements Satisfied
This implementation satisfies the following requirements from the specification:
- **5.1**: Supports ascending and descending order for sortable columns
- **5.2**: Toggles between ascending, descending when clicking column headers
- **5.3**: Displays visual indicators (arrow icons) showing sort direction
- **5.5**: Preserves sort state in URL parameters during navigation
- **5.6**: Preserves other active filters and resets pagination when sorting
## Testing
### Manual Testing
1. Open `dbapp/mainapp/static/js/sorting-test.html` in a browser
2. Click column headers to test sorting
3. Verify URL updates correctly
4. Add query parameters (e.g., ?page=5&search=test) and verify they're preserved
### Integration Testing
Test in actual Django views:
1. Navigate to any list view (sources, objitems, transponders)
2. Click column headers to sort
3. Verify data is sorted correctly
4. Apply filters and verify they're preserved when sorting
5. Navigate to page 2+, then sort - verify it resets to page 1
## Browser Compatibility
- Modern browsers supporting ES6 (URLSearchParams)
- Chrome 49+
- Firefox 44+
- Safari 10.1+
- Edge 17+
## Notes
- The sorting.js file is loaded with `defer` attribute for better performance
- All GET parameters are preserved except `page` which is reset to 1
- The function is globally available and can be called from any template
- Sort indicators are automatically initialized on page load

View File

@@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sorting Test</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1>Sorting Functionality Test</h1>
<div class="alert alert-info">
<strong>Current URL:</strong> <span id="currentUrl"></span>
</div>
<table class="table table-striped">
<thead class="table-dark">
<tr>
<th>
<a href="javascript:void(0)"
onclick="updateSort('id')"
class="text-white text-decoration-none"
data-sort-field="id">
ID
<i class="bi bi-arrow-up sort-icon" style="display: none;"></i>
</a>
</th>
<th>
<a href="javascript:void(0)"
onclick="updateSort('name')"
class="text-white text-decoration-none"
data-sort-field="name">
Name
<i class="bi bi-arrow-up sort-icon" style="display: none;"></i>
</a>
</th>
<th>
<a href="javascript:void(0)"
onclick="updateSort('created_at')"
class="text-white text-decoration-none"
data-sort-field="created_at">
Created At
<i class="bi bi-arrow-up sort-icon" style="display: none;"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Test Item 1</td>
<td>2024-01-01</td>
</tr>
<tr>
<td>2</td>
<td>Test Item 2</td>
<td>2024-01-02</td>
</tr>
</tbody>
</table>
<div class="card">
<div class="card-body">
<h5>Test Instructions:</h5>
<ol>
<li>Click on any column header (ID, Name, or Created At)</li>
<li>The URL should update with ?sort=field_name</li>
<li>Click again to toggle to descending (?sort=-field_name)</li>
<li>Click a third time to toggle back to ascending</li>
<li>Add ?page=5 to the URL and click a header - page should reset to 1</li>
<li>Add ?search=test to the URL and click a header - search should be preserved</li>
</ol>
</div>
</div>
</div>
<script src="sorting.js"></script>
<script>
// Display current URL
function updateUrlDisplay() {
document.getElementById('currentUrl').textContent = window.location.href;
}
updateUrlDisplay();
// Update URL display on page load
window.addEventListener('load', updateUrlDisplay);
</script>
</body>
</html>

View File

@@ -0,0 +1,106 @@
/**
* Sorting functionality for table columns
* Handles toggling between ascending, descending, and no sort
* Preserves other GET parameters and resets pagination
*/
/**
* Updates the sort parameter in the URL and reloads the page
* @param {string} field - The field name to sort by
*/
function updateSort(field) {
// Get current URL parameters
const urlParams = new URLSearchParams(window.location.search);
const currentSort = urlParams.get('sort');
let newSort;
// Toggle sort direction logic:
// 1. If not sorted by this field -> sort ascending (field)
// 2. If sorted ascending -> sort descending (-field)
// 3. If sorted descending -> sort ascending (field)
if (currentSort === field) {
// Currently ascending, switch to descending
newSort = '-' + field;
} else if (currentSort === '-' + field) {
// Currently descending, switch to ascending
newSort = field;
} else {
// Not sorted by this field, start with ascending
newSort = field;
}
// Update sort parameter
urlParams.set('sort', newSort);
// Reset to first page when sorting changes
urlParams.delete('page');
// Reload page with new parameters
window.location.search = urlParams.toString();
}
/**
* Gets the current sort field and direction
* @returns {Object} Object with field and direction properties
*/
function getCurrentSort() {
const urlParams = new URLSearchParams(window.location.search);
const sort = urlParams.get('sort');
if (!sort) {
return { field: null, direction: null };
}
if (sort.startsWith('-')) {
return {
field: sort.substring(1),
direction: 'desc'
};
}
return {
field: sort,
direction: 'asc'
};
}
/**
* Initializes sort indicators on page load
* Adds visual indicators to show current sort state
*/
function initializeSortIndicators() {
const currentSort = getCurrentSort();
if (!currentSort.field) {
return;
}
// Find all sort headers and update their indicators
const sortHeaders = document.querySelectorAll('[data-sort-field]');
sortHeaders.forEach(header => {
const field = header.getAttribute('data-sort-field');
if (field === currentSort.field) {
// Add active class or update icon
header.classList.add('sort-active');
// Update icon if present
const icon = header.querySelector('.sort-icon');
if (icon) {
if (currentSort.direction === 'asc') {
icon.className = 'bi bi-arrow-up sort-icon';
} else {
icon.className = 'bi bi-arrow-down sort-icon';
}
}
}
});
}
// Initialize sort indicators when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeSortIndicators);
} else {
initializeSortIndicators();
}