diff options
-rw-r--r-- | fietsboek/locale/de/LC_MESSAGES/messages.mo | bin | 10209 -> 11214 bytes | |||
-rw-r--r-- | fietsboek/locale/de/LC_MESSAGES/messages.po | 119 | ||||
-rw-r--r-- | fietsboek/locale/en/LC_MESSAGES/messages.mo | bin | 9612 -> 10549 bytes | |||
-rw-r--r-- | fietsboek/locale/en/LC_MESSAGES/messages.po | 118 | ||||
-rw-r--r-- | fietsboek/locale/fietslog.pot | 118 | ||||
-rw-r--r-- | fietsboek/static/fietsboek.js | 15 | ||||
-rw-r--r-- | fietsboek/templates/browse.jinja2 | 98 | ||||
-rw-r--r-- | fietsboek/views/browse.py | 111 |
8 files changed, 485 insertions, 94 deletions
diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.mo b/fietsboek/locale/de/LC_MESSAGES/messages.mo Binary files differindex 7d7af8d..97ee495 100644 --- a/fietsboek/locale/de/LC_MESSAGES/messages.mo +++ b/fietsboek/locale/de/LC_MESSAGES/messages.mo diff --git a/fietsboek/locale/de/LC_MESSAGES/messages.po b/fietsboek/locale/de/LC_MESSAGES/messages.po index 35a6bd4..9c93bb4 100644 --- a/fietsboek/locale/de/LC_MESSAGES/messages.po +++ b/fietsboek/locale/de/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2022-07-21 23:49+0200\n" +"POT-Creation-Date: 2022-08-02 11:57+0200\n" "PO-Revision-Date: 2022-07-02 17:35+0200\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language: de\n" @@ -18,11 +18,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.10.3\n" -#: fietsboek/util.py:273 +#: fietsboek/util.py:282 msgid "password_constraint.mismatch" msgstr "Passwörter stimmen nicht überein" -#: fietsboek/util.py:275 +#: fietsboek/util.py:284 msgid "password_constraint.length" msgstr "Passwort zu kurz" @@ -86,51 +86,108 @@ msgstr "Hinzufügen" msgid "page.browse.title" msgstr "Stöbern" -#: fietsboek/templates/browse.jinja2:19 fietsboek/templates/details.jinja2:86 +#: fietsboek/templates/browse.jinja2:11 +msgid "page.browse.filter.search_terms" +msgstr "Suchbegriffe" + +#: fietsboek/templates/browse.jinja2:20 +msgid "page.browse.filter.tags" +msgstr "Schlagwörter" + +#: fietsboek/templates/browse.jinja2:27 +msgid "page.browse.filter.tagged_person" +msgstr "Markierte Personen" + +#: fietsboek/templates/browse.jinja2:34 +msgid "page.browse.filter.length_minimum" +msgstr "Minimale Länge" + +#: fietsboek/templates/browse.jinja2:40 +msgid "page.browse.filter.length_boundaries" +msgstr "Längenbeschränkungen" + +#: fietsboek/templates/browse.jinja2:46 +msgid "page.browse.filter.length_maximum" +msgstr "Maximale Länge" + +#: fietsboek/templates/browse.jinja2:59 +msgid "page.browse.filter.date_boundaries" +msgstr "Datumsgrenzen" + +#: fietsboek/templates/browse.jinja2:77 +msgid "page.browse.filter.my_tracks.only" +msgstr "Zeige nur eigene Strecken" + +#: fietsboek/templates/browse.jinja2:78 +msgid "page.browse.filter.friends_tracks_only" +msgstr "Zeige nur Strecken von Freunden" + +#: fietsboek/templates/browse.jinja2:79 +msgid "page.browse.filter.me_tagged_only" +msgstr "Zeige nur Strecken, in denen ich markiert bin" + +#: fietsboek/templates/browse.jinja2:88 +msgid "page.browse.filters.apply" +msgstr "Filter anwenden" + +#: fietsboek/templates/browse.jinja2:92 +msgid "page.browse.filters.clear_all" +msgstr "Filter zurücksetzen" + +#: fietsboek/templates/browse.jinja2:95 +msgid "page.browse.filters.expand_advanced" +msgstr "Erweitert" + +#: fietsboek/templates/browse.jinja2:115 fietsboek/templates/details.jinja2:86 msgid "page.details.date" msgstr "Datum" -#: fietsboek/templates/browse.jinja2:21 fietsboek/templates/details.jinja2:98 +#: fietsboek/templates/browse.jinja2:117 fietsboek/templates/details.jinja2:98 msgid "page.details.length" msgstr "Länge" -#: fietsboek/templates/browse.jinja2:25 fietsboek/templates/details.jinja2:90 +#: fietsboek/templates/browse.jinja2:121 fietsboek/templates/details.jinja2:90 msgid "page.details.start_time" msgstr "Startzeit" -#: fietsboek/templates/browse.jinja2:27 fietsboek/templates/details.jinja2:94 +#: fietsboek/templates/browse.jinja2:123 fietsboek/templates/details.jinja2:94 msgid "page.details.end_time" msgstr "Endzeit" -#: fietsboek/templates/browse.jinja2:31 fietsboek/templates/details.jinja2:102 +#: fietsboek/templates/browse.jinja2:127 fietsboek/templates/details.jinja2:102 msgid "page.details.uphill" msgstr "Bergauf" -#: fietsboek/templates/browse.jinja2:33 fietsboek/templates/details.jinja2:106 +#: fietsboek/templates/browse.jinja2:129 fietsboek/templates/details.jinja2:106 msgid "page.details.downhill" msgstr "Bergab" -#: fietsboek/templates/browse.jinja2:37 fietsboek/templates/details.jinja2:110 +#: fietsboek/templates/browse.jinja2:133 fietsboek/templates/details.jinja2:110 msgid "page.details.moving_time" msgstr "Fahrzeit" -#: fietsboek/templates/browse.jinja2:39 fietsboek/templates/details.jinja2:114 +#: fietsboek/templates/browse.jinja2:135 fietsboek/templates/details.jinja2:114 msgid "page.details.stopped_time" msgstr "Haltezeit" -#: fietsboek/templates/browse.jinja2:43 fietsboek/templates/details.jinja2:118 +#: fietsboek/templates/browse.jinja2:139 fietsboek/templates/details.jinja2:118 msgid "page.details.max_speed" msgstr "maximale Geschwindigkeit" -#: fietsboek/templates/browse.jinja2:45 fietsboek/templates/details.jinja2:122 +#: fietsboek/templates/browse.jinja2:141 fietsboek/templates/details.jinja2:122 msgid "page.details.avg_speed" msgstr "durchschnittliche Geschwindigkeit" -#: fietsboek/templates/browse.jinja2:60 +#: fietsboek/templates/browse.jinja2:156 msgid "page.browse.download_multiple" msgstr "ausgewählte Herunterladen" -#: fietsboek/templates/browse.jinja2:62 +#: fietsboek/templates/browse.jinja2:158 +msgid "page.browse.no_results" +msgstr "" +"Es wurden keine Strecken gefunden, die den Filtern entsprechen." + +#: fietsboek/templates/browse.jinja2:160 msgid "page.browse.no_tracks" msgstr "" "Es wurden keine Strecken gefunden, auf die Du Zugriff hast. Versuche, " @@ -376,47 +433,47 @@ msgstr "Startseite" msgid "page.home.total" msgstr "Gesamt" -#: fietsboek/templates/layout.jinja2:31 +#: fietsboek/templates/layout.jinja2:40 msgid "page.navbar.toggle" msgstr "Navigation umschalten" -#: fietsboek/templates/layout.jinja2:37 +#: fietsboek/templates/layout.jinja2:46 msgid "page.navbar.home" msgstr "Startseite" -#: fietsboek/templates/layout.jinja2:40 +#: fietsboek/templates/layout.jinja2:49 msgid "page.navbar.browse" msgstr "Stöbern" -#: fietsboek/templates/layout.jinja2:44 +#: fietsboek/templates/layout.jinja2:53 msgid "page.navbar.upload" msgstr "Hochladen" -#: fietsboek/templates/layout.jinja2:48 +#: fietsboek/templates/layout.jinja2:57 msgid "page.navbar.user" msgstr "Nutzer" -#: fietsboek/templates/layout.jinja2:52 +#: fietsboek/templates/layout.jinja2:61 msgid "page.navbar.welcome_user" msgstr "Willkommen, {}!" -#: fietsboek/templates/layout.jinja2:55 +#: fietsboek/templates/layout.jinja2:64 msgid "page.navbar.logout" msgstr "Abmelden" -#: fietsboek/templates/layout.jinja2:58 +#: fietsboek/templates/layout.jinja2:67 msgid "page.navbar.profile" msgstr "Profil" -#: fietsboek/templates/layout.jinja2:62 +#: fietsboek/templates/layout.jinja2:71 msgid "page.navbar.admin" msgstr "Admin" -#: fietsboek/templates/layout.jinja2:68 +#: fietsboek/templates/layout.jinja2:77 msgid "page.navbar.login" msgstr "Anmelden" -#: fietsboek/templates/layout.jinja2:72 +#: fietsboek/templates/layout.jinja2:81 msgid "page.navbar.create_account" msgstr "Konto Erstellen" @@ -617,7 +674,7 @@ msgstr "E-Mail-Adresse bestätigt" msgid "flash.password_updated" msgstr "Passwort aktualisiert" -#: fietsboek/views/detail.py:88 +#: fietsboek/views/detail.py:93 msgid "flash.track_deleted" msgstr "Strecke gelöscht" @@ -641,19 +698,19 @@ msgstr "Freund hinzugefügt" msgid "flash.friend_request_sent" msgstr "Freundschaftsanfrage gesendet" -#: fietsboek/views/upload.py:51 +#: fietsboek/views/upload.py:52 msgid "flash.no_file_selected" msgstr "Keine Datei ausgewählt" -#: fietsboek/views/upload.py:61 +#: fietsboek/views/upload.py:62 msgid "flash.invalid_file" msgstr "Ungültige GPX-Datei gesendet" -#: fietsboek/views/upload.py:178 +#: fietsboek/views/upload.py:177 msgid "flash.upload_success" msgstr "Hochladen erfolgreich" -#: fietsboek/views/upload.py:194 +#: fietsboek/views/upload.py:193 msgid "flash.upload_cancelled" msgstr "Hochladen abgebrochen" diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.mo b/fietsboek/locale/en/LC_MESSAGES/messages.mo Binary files differindex 8261149..8887d3d 100644 --- a/fietsboek/locale/en/LC_MESSAGES/messages.mo +++ b/fietsboek/locale/en/LC_MESSAGES/messages.mo diff --git a/fietsboek/locale/en/LC_MESSAGES/messages.po b/fietsboek/locale/en/LC_MESSAGES/messages.po index c19184c..2ac9f98 100644 --- a/fietsboek/locale/en/LC_MESSAGES/messages.po +++ b/fietsboek/locale/en/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2022-07-21 23:49+0200\n" +"POT-Creation-Date: 2022-08-02 11:57+0200\n" "PO-Revision-Date: 2022-06-28 13:11+0200\n" "Last-Translator: \n" "Language: en\n" @@ -18,11 +18,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.10.3\n" -#: fietsboek/util.py:273 +#: fietsboek/util.py:282 msgid "password_constraint.mismatch" msgstr "Passwords don't match" -#: fietsboek/util.py:275 +#: fietsboek/util.py:284 msgid "password_constraint.length" msgstr "Password not long enough" @@ -86,51 +86,107 @@ msgstr "Add Badge" msgid "page.browse.title" msgstr "Browse" -#: fietsboek/templates/browse.jinja2:19 fietsboek/templates/details.jinja2:86 +#: fietsboek/templates/browse.jinja2:11 +msgid "page.browse.filter.search_terms" +msgstr "Search terms" + +#: fietsboek/templates/browse.jinja2:20 +msgid "page.browse.filter.tags" +msgstr "Tags" + +#: fietsboek/templates/browse.jinja2:27 +msgid "page.browse.filter.tagged_person" +msgstr "Tagged People" + +#: fietsboek/templates/browse.jinja2:34 +msgid "page.browse.filter.length_minimum" +msgstr "Minimum length" + +#: fietsboek/templates/browse.jinja2:40 +msgid "page.browse.filter.length_boundaries" +msgstr "Length limits" + +#: fietsboek/templates/browse.jinja2:46 +msgid "page.browse.filter.length_maximum" +msgstr "Maximum length" + +#: fietsboek/templates/browse.jinja2:59 +msgid "page.browse.filter.date_boundaries" +msgstr "Date limits" + +#: fietsboek/templates/browse.jinja2:77 +msgid "page.browse.filter.my_tracks.only" +msgstr "Show only my own tracks" + +#: fietsboek/templates/browse.jinja2:78 +msgid "page.browse.filter.friends_tracks_only" +msgstr "Show only tracks of my friends" + +#: fietsboek/templates/browse.jinja2:79 +msgid "page.browse.filter.me_tagged_only" +msgstr "Show only tracks in which I'm tagged" + +#: fietsboek/templates/browse.jinja2:88 +msgid "page.browse.filters.apply" +msgstr "Apply filters" + +#: fietsboek/templates/browse.jinja2:92 +msgid "page.browse.filters.clear_all" +msgstr "Remove filters" + +#: fietsboek/templates/browse.jinja2:95 +msgid "page.browse.filters.expand_advanced" +msgstr "Advanced" + +#: fietsboek/templates/browse.jinja2:115 fietsboek/templates/details.jinja2:86 msgid "page.details.date" msgstr "Date" -#: fietsboek/templates/browse.jinja2:21 fietsboek/templates/details.jinja2:98 +#: fietsboek/templates/browse.jinja2:117 fietsboek/templates/details.jinja2:98 msgid "page.details.length" msgstr "Length" -#: fietsboek/templates/browse.jinja2:25 fietsboek/templates/details.jinja2:90 +#: fietsboek/templates/browse.jinja2:121 fietsboek/templates/details.jinja2:90 msgid "page.details.start_time" msgstr "Record Start" -#: fietsboek/templates/browse.jinja2:27 fietsboek/templates/details.jinja2:94 +#: fietsboek/templates/browse.jinja2:123 fietsboek/templates/details.jinja2:94 msgid "page.details.end_time" msgstr "Record End" -#: fietsboek/templates/browse.jinja2:31 fietsboek/templates/details.jinja2:102 +#: fietsboek/templates/browse.jinja2:127 fietsboek/templates/details.jinja2:102 msgid "page.details.uphill" msgstr "Uphill" -#: fietsboek/templates/browse.jinja2:33 fietsboek/templates/details.jinja2:106 +#: fietsboek/templates/browse.jinja2:129 fietsboek/templates/details.jinja2:106 msgid "page.details.downhill" msgstr "Downhill" -#: fietsboek/templates/browse.jinja2:37 fietsboek/templates/details.jinja2:110 +#: fietsboek/templates/browse.jinja2:133 fietsboek/templates/details.jinja2:110 msgid "page.details.moving_time" msgstr "Moving Time" -#: fietsboek/templates/browse.jinja2:39 fietsboek/templates/details.jinja2:114 +#: fietsboek/templates/browse.jinja2:135 fietsboek/templates/details.jinja2:114 msgid "page.details.stopped_time" msgstr "Stopped Time" -#: fietsboek/templates/browse.jinja2:43 fietsboek/templates/details.jinja2:118 +#: fietsboek/templates/browse.jinja2:139 fietsboek/templates/details.jinja2:118 msgid "page.details.max_speed" msgstr "Max Speed" -#: fietsboek/templates/browse.jinja2:45 fietsboek/templates/details.jinja2:122 +#: fietsboek/templates/browse.jinja2:141 fietsboek/templates/details.jinja2:122 msgid "page.details.avg_speed" msgstr "Average Speed" -#: fietsboek/templates/browse.jinja2:60 +#: fietsboek/templates/browse.jinja2:156 msgid "page.browse.download_multiple" msgstr "Download selected" -#: fietsboek/templates/browse.jinja2:62 +#: fietsboek/templates/browse.jinja2:158 +msgid "page.browse.no_results" +msgstr "No results matching the filters were found." + +#: fietsboek/templates/browse.jinja2:160 msgid "page.browse.no_tracks" msgstr "You currently do not have access to any tracks. Try logging in." @@ -372,47 +428,47 @@ msgstr "Home" msgid "page.home.total" msgstr "Total" -#: fietsboek/templates/layout.jinja2:31 +#: fietsboek/templates/layout.jinja2:40 msgid "page.navbar.toggle" msgstr "Toggle navigation" -#: fietsboek/templates/layout.jinja2:37 +#: fietsboek/templates/layout.jinja2:46 msgid "page.navbar.home" msgstr "Home" -#: fietsboek/templates/layout.jinja2:40 +#: fietsboek/templates/layout.jinja2:49 msgid "page.navbar.browse" msgstr "Browse" -#: fietsboek/templates/layout.jinja2:44 +#: fietsboek/templates/layout.jinja2:53 msgid "page.navbar.upload" msgstr "Upload" -#: fietsboek/templates/layout.jinja2:48 +#: fietsboek/templates/layout.jinja2:57 msgid "page.navbar.user" msgstr "User" -#: fietsboek/templates/layout.jinja2:52 +#: fietsboek/templates/layout.jinja2:61 msgid "page.navbar.welcome_user" msgstr "Welcome, {}!" -#: fietsboek/templates/layout.jinja2:55 +#: fietsboek/templates/layout.jinja2:64 msgid "page.navbar.logout" msgstr "Logout" -#: fietsboek/templates/layout.jinja2:58 +#: fietsboek/templates/layout.jinja2:67 msgid "page.navbar.profile" msgstr "Profile" -#: fietsboek/templates/layout.jinja2:62 +#: fietsboek/templates/layout.jinja2:71 msgid "page.navbar.admin" msgstr "Admin" -#: fietsboek/templates/layout.jinja2:68 +#: fietsboek/templates/layout.jinja2:77 msgid "page.navbar.login" msgstr "Login" -#: fietsboek/templates/layout.jinja2:72 +#: fietsboek/templates/layout.jinja2:81 msgid "page.navbar.create_account" msgstr "Create Account" @@ -612,7 +668,7 @@ msgstr "Your email address has been verified" msgid "flash.password_updated" msgstr "Password has been updated" -#: fietsboek/views/detail.py:88 +#: fietsboek/views/detail.py:93 msgid "flash.track_deleted" msgstr "Track has been deleted" @@ -636,19 +692,19 @@ msgstr "Friend has been added" msgid "flash.friend_request_sent" msgstr "Friend request sent" -#: fietsboek/views/upload.py:51 +#: fietsboek/views/upload.py:52 msgid "flash.no_file_selected" msgstr "No file selected" -#: fietsboek/views/upload.py:61 +#: fietsboek/views/upload.py:62 msgid "flash.invalid_file" msgstr "Invalid GPX file selected" -#: fietsboek/views/upload.py:178 +#: fietsboek/views/upload.py:177 msgid "flash.upload_success" msgstr "Upload successful" -#: fietsboek/views/upload.py:194 +#: fietsboek/views/upload.py:193 msgid "flash.upload_cancelled" msgstr "Upload cancelled" diff --git a/fietsboek/locale/fietslog.pot b/fietsboek/locale/fietslog.pot index a30c79c..2c25251 100644 --- a/fietsboek/locale/fietslog.pot +++ b/fietsboek/locale/fietslog.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2022-07-21 23:49+0200\n" +"POT-Creation-Date: 2022-08-02 11:57+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.10.3\n" -#: fietsboek/util.py:273 +#: fietsboek/util.py:282 msgid "password_constraint.mismatch" msgstr "" -#: fietsboek/util.py:275 +#: fietsboek/util.py:284 msgid "password_constraint.length" msgstr "" @@ -85,51 +85,107 @@ msgstr "" msgid "page.browse.title" msgstr "" -#: fietsboek/templates/browse.jinja2:19 fietsboek/templates/details.jinja2:86 +#: fietsboek/templates/browse.jinja2:11 +msgid "page.browse.filter.search_terms" +msgstr "" + +#: fietsboek/templates/browse.jinja2:20 +msgid "page.browse.filter.tags" +msgstr "" + +#: fietsboek/templates/browse.jinja2:27 +msgid "page.browse.filter.tagged_person" +msgstr "" + +#: fietsboek/templates/browse.jinja2:34 +msgid "page.browse.filter.length_minimum" +msgstr "" + +#: fietsboek/templates/browse.jinja2:40 +msgid "page.browse.filter.length_boundaries" +msgstr "" + +#: fietsboek/templates/browse.jinja2:46 +msgid "page.browse.filter.length_maximum" +msgstr "" + +#: fietsboek/templates/browse.jinja2:59 +msgid "page.browse.filter.date_boundaries" +msgstr "" + +#: fietsboek/templates/browse.jinja2:77 +msgid "page.browse.filter.my_tracks.only" +msgstr "" + +#: fietsboek/templates/browse.jinja2:78 +msgid "page.browse.filter.friends_tracks_only" +msgstr "" + +#: fietsboek/templates/browse.jinja2:79 +msgid "page.browse.filter.me_tagged_only" +msgstr "" + +#: fietsboek/templates/browse.jinja2:88 +msgid "page.browse.filters.apply" +msgstr "" + +#: fietsboek/templates/browse.jinja2:92 +msgid "page.browse.filters.clear_all" +msgstr "" + +#: fietsboek/templates/browse.jinja2:95 +msgid "page.browse.filters.expand_advanced" +msgstr "" + +#: fietsboek/templates/browse.jinja2:115 fietsboek/templates/details.jinja2:86 msgid "page.details.date" msgstr "" -#: fietsboek/templates/browse.jinja2:21 fietsboek/templates/details.jinja2:98 +#: fietsboek/templates/browse.jinja2:117 fietsboek/templates/details.jinja2:98 msgid "page.details.length" msgstr "" -#: fietsboek/templates/browse.jinja2:25 fietsboek/templates/details.jinja2:90 +#: fietsboek/templates/browse.jinja2:121 fietsboek/templates/details.jinja2:90 msgid "page.details.start_time" msgstr "" -#: fietsboek/templates/browse.jinja2:27 fietsboek/templates/details.jinja2:94 +#: fietsboek/templates/browse.jinja2:123 fietsboek/templates/details.jinja2:94 msgid "page.details.end_time" msgstr "" -#: fietsboek/templates/browse.jinja2:31 fietsboek/templates/details.jinja2:102 +#: fietsboek/templates/browse.jinja2:127 fietsboek/templates/details.jinja2:102 msgid "page.details.uphill" msgstr "" -#: fietsboek/templates/browse.jinja2:33 fietsboek/templates/details.jinja2:106 +#: fietsboek/templates/browse.jinja2:129 fietsboek/templates/details.jinja2:106 msgid "page.details.downhill" msgstr "" -#: fietsboek/templates/browse.jinja2:37 fietsboek/templates/details.jinja2:110 +#: fietsboek/templates/browse.jinja2:133 fietsboek/templates/details.jinja2:110 msgid "page.details.moving_time" msgstr "" -#: fietsboek/templates/browse.jinja2:39 fietsboek/templates/details.jinja2:114 +#: fietsboek/templates/browse.jinja2:135 fietsboek/templates/details.jinja2:114 msgid "page.details.stopped_time" msgstr "" -#: fietsboek/templates/browse.jinja2:43 fietsboek/templates/details.jinja2:118 +#: fietsboek/templates/browse.jinja2:139 fietsboek/templates/details.jinja2:118 msgid "page.details.max_speed" msgstr "" -#: fietsboek/templates/browse.jinja2:45 fietsboek/templates/details.jinja2:122 +#: fietsboek/templates/browse.jinja2:141 fietsboek/templates/details.jinja2:122 msgid "page.details.avg_speed" msgstr "" -#: fietsboek/templates/browse.jinja2:60 +#: fietsboek/templates/browse.jinja2:156 msgid "page.browse.download_multiple" msgstr "" -#: fietsboek/templates/browse.jinja2:62 +#: fietsboek/templates/browse.jinja2:158 +msgid "page.browse.no_results" +msgstr "" + +#: fietsboek/templates/browse.jinja2:160 msgid "page.browse.no_tracks" msgstr "" @@ -369,47 +425,47 @@ msgstr "" msgid "page.home.total" msgstr "" -#: fietsboek/templates/layout.jinja2:31 +#: fietsboek/templates/layout.jinja2:40 msgid "page.navbar.toggle" msgstr "" -#: fietsboek/templates/layout.jinja2:37 +#: fietsboek/templates/layout.jinja2:46 msgid "page.navbar.home" msgstr "" -#: fietsboek/templates/layout.jinja2:40 +#: fietsboek/templates/layout.jinja2:49 msgid "page.navbar.browse" msgstr "" -#: fietsboek/templates/layout.jinja2:44 +#: fietsboek/templates/layout.jinja2:53 msgid "page.navbar.upload" msgstr "" -#: fietsboek/templates/layout.jinja2:48 +#: fietsboek/templates/layout.jinja2:57 msgid "page.navbar.user" msgstr "" -#: fietsboek/templates/layout.jinja2:52 +#: fietsboek/templates/layout.jinja2:61 msgid "page.navbar.welcome_user" msgstr "" -#: fietsboek/templates/layout.jinja2:55 +#: fietsboek/templates/layout.jinja2:64 msgid "page.navbar.logout" msgstr "" -#: fietsboek/templates/layout.jinja2:58 +#: fietsboek/templates/layout.jinja2:67 msgid "page.navbar.profile" msgstr "" -#: fietsboek/templates/layout.jinja2:62 +#: fietsboek/templates/layout.jinja2:71 msgid "page.navbar.admin" msgstr "" -#: fietsboek/templates/layout.jinja2:68 +#: fietsboek/templates/layout.jinja2:77 msgid "page.navbar.login" msgstr "" -#: fietsboek/templates/layout.jinja2:72 +#: fietsboek/templates/layout.jinja2:81 msgid "page.navbar.create_account" msgstr "" @@ -601,7 +657,7 @@ msgstr "" msgid "flash.password_updated" msgstr "" -#: fietsboek/views/detail.py:88 +#: fietsboek/views/detail.py:93 msgid "flash.track_deleted" msgstr "" @@ -625,19 +681,19 @@ msgstr "" msgid "flash.friend_request_sent" msgstr "" -#: fietsboek/views/upload.py:51 +#: fietsboek/views/upload.py:52 msgid "flash.no_file_selected" msgstr "" -#: fietsboek/views/upload.py:61 +#: fietsboek/views/upload.py:62 msgid "flash.invalid_file" msgstr "" -#: fietsboek/views/upload.py:178 +#: fietsboek/views/upload.py:177 msgid "flash.upload_success" msgstr "" -#: fietsboek/views/upload.py:194 +#: fietsboek/views/upload.py:193 msgid "flash.upload_cancelled" msgstr "" diff --git a/fietsboek/static/fietsboek.js b/fietsboek/static/fietsboek.js index f99a531..2e88aa3 100644 --- a/fietsboek/static/fietsboek.js +++ b/fietsboek/static/fietsboek.js @@ -311,6 +311,21 @@ addHandler(".archive-checkbox", "change", () => { document.querySelector("#archiveDownloadButton").disabled = (checked.length == 0); }); +/** + * Handler to clear the input when a .button-clear-input is pressed. + * + * The button must be in an input-group with the input. + * + * @param event - The triggering event. + */ +function clearInputButtonClicked(event) { + const input = event.target.closest(".input-group").querySelector("input"); + input.value = ""; +} + +addHandler(".button-clear-input", "click", clearInputButtonClicked); + + document.addEventListener('DOMContentLoaded', function() { window.fietsboekImageIndex = 0; diff --git a/fietsboek/templates/browse.jinja2 b/fietsboek/templates/browse.jinja2 index 2732984..0f98192 100644 --- a/fietsboek/templates/browse.jinja2 +++ b/fietsboek/templates/browse.jinja2 @@ -2,6 +2,102 @@ {% block content %} <div class="container"> <h1>{{ _("page.browse.title") }}</h1> + <div class="mb-3"> + <form id="browseFilter"> + <div class="row g-3 mb-3"> + <div class="col-12"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="search-terms" type="text" class="form-control" placeholder="{{ _("page.browse.filter.search_terms") }}" value="{{ request.params.get('search-terms', '') }}"> + </div> + </div> + </div> + + <div class="collapse row g-3 mb-3" id="advancedSearch"> + <div class="col-md-6"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="tags" type="text" class="form-control" placeholder="{{ _("page.browse.filter.tags") }}" value="{{ request.params.get('tags', '') }}"> + </div> + </div> + + <div class="col-md-6"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="tagged-person" type="text" class="form-control" placeholder="{{ _("page.browse.filter.tagged_person") }}" value="{{ request.params.get('tagged-person', '') }}"> + </div> + </div> + + <div class="col-md-4"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="min-length" type="number" class="form-control" placeholder="{{ _("page.browse.filter.length_minimum") }}" value="{{ request.params.get('min-length', '') }}"> + <span class="input-group-text">km</span> + </div> + </div> + + <div class="col-md-4 fs-5 d-flex align-items-center justify-content-center"> + {{ _("page.browse.filter.length_boundaries") }} + </div> + + <div class="col-md-4"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="max-length" type="number" class="form-control" placeholder="{{ _("page.browse.filter.length_maximum") }}" value="{{ request.params.get('max-length', '') }}"> + <span class="input-group-text">km</span> + </div> + </div> + + <div class="col-md-4"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="min-date" type="date" class="form-control" value="{{ request.params.get('min-date', '') }}"> + </div> + </div> + + <div class="col-md-4 fs-5 d-flex align-items-center justify-content-center"> + {{ _("page.browse.filter.date_boundaries") }} + </div> + + <div class="col-md-4"> + <div class="input-group"> + <button type="button" class="btn btn-outline-secondary button-clear-input"><i class="bi bi-eraser-fill"></i></button> + <input name="max-date" type="date" class="form-control" value="{{ request.params.get('max-date', '') }}"> + </div> + </div> + + {% if request.identity %} + <div class="col-12"> + {% macro render_switch(id, name, value, text) %} + <div class="form-check form-switch"> + <input class="form-check-input" type="checkbox" role="switch" id="{{ id }}" name="{{ name }}" value="{{ value }}" {% if value in request.params.getall(name) %}checked{% endif %}> + <label class="form-check-label" for="{{ id }}">{{ text }}</label> + </div> + {% endmacro %} + {{ render_switch("switchOnlyMyTracks", "show-only[]", "mine", _("page.browse.filter.my_tracks.only")) }} + {{ render_switch("switchOnlyFriendsTracks", "show-only[]", "friends", _("page.browse.filter.friends_tracks_only")) }} + {{ render_switch("switchOnlyMeTagged", "user-tagged", "on", _("page.browse.filter.me_tagged_only")) }} + </div> + {% endif %} + </div> + + <div class="row g-3 mb-3"> + <div class="col"> + <button type="submit" class="btn btn-primary"> + <i class="bi bi-funnel-fill"></i> + {{ _("page.browse.filters.apply") }} + </button> + <a class="btn btn-info" href="{{ request.route_path('browse') }}"> + <i class="bi bi-x-octagon"></i> + {{ _("page.browse.filters.clear_all") }} + </a> + <button class="btn btn-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSearch" aria-expanded="false" aria-controls="advancedSearch"> + {{ _("page.browse.filters.expand_advanced") }} + </button> + </div> + </div> + </form> + </div> {% if tracks %} {% for track in tracks %} <div class="card mb-3"> @@ -58,6 +154,8 @@ </div> {% endfor %} <button type="button" class="btn btn-primary" id="archiveDownloadButton" disabled><i class="bi bi-file-earmark-zip"></i> {{ _("page.browse.download_multiple") }}</button> + {% elif used_filters %} + <p>{{ _("page.browse.no_results") }}</p> {% else %} <p>{{ _("page.browse.no_tracks") }}</p> {% endif %} diff --git a/fietsboek/views/browse.py b/fietsboek/views/browse.py index 17dd45a..7120b0d 100644 --- a/fietsboek/views/browse.py +++ b/fietsboek/views/browse.py @@ -1,9 +1,10 @@ """Views for browsing all tracks.""" +import datetime from io import RawIOBase from zipfile import ZipFile, ZIP_DEFLATED from pyramid.view import view_config -from pyramid.httpexceptions import HTTPForbidden, HTTPNotFound +from pyramid.httpexceptions import HTTPForbidden, HTTPNotFound, HTTPBadRequest from pyramid.response import Response from sqlalchemy import select @@ -32,6 +33,111 @@ class Stream(RawIOBase): return b"".join(buf) +def _get_int(request, name): + try: + return int(request.params.get(name)) + except ValueError as exc: + raise HTTPBadRequest(f'Invalid integer in {name!r}') from exc + + +def _get_date(request, name): + try: + return datetime.date.fromisoformat(request.params.get(name)) + except ValueError as exc: + raise HTTPBadRequest(f'Invalid date in {name!r}') from exc + + +class TrackFilters: + """A filter that applies user-given filters to a track.""" + # pylint: disable=fixme + # TODO: We should also do some of those in SQL, if possible. + + def __init__(self, filters): + self._filters = filters + + def __bool__(self): + return bool(self._filters) + + def apply(self, track): + """Apply the filters to the track. + + :param track: The track. + :type track: fietsboek.models.track.Track + :return: Whether the track matches the filters. + :rtype: bool + """ + return all(f(track) for f in self._filters) + + @classmethod + def parse(cls, request): + """Parse the filters from the given request. + + :raises HTTPBadRequest: If the filters are malformed. + :param request: The request. + :type request: pyramid.request.Request + :return: The parsed filter. + :rtype: TrackFilters + """ + filters = [] + if request.params.get('search-terms'): + term = request.params.get('search-terms').strip() + filters.append(lambda track: term.lower() in track.title.lower()) + + if request.params.get('tags'): + tags = [tag.strip() for tag in request.params.get('tags').split('&&')] + tags = list(filter(bool, tags)) + + def has_tags(track): + lower_tags = {tag.lower() for tag in track.text_tags()} + return all(tag.lower() in lower_tags for tag in tags) + + filters.append(has_tags) + + if request.params.get('tagged-person'): + names = [name.strip() for name in request.params.get('tagged-person').split('&&')] + names = list(filter(bool, names)) + + def has_people(track): + peoples_names = [person.name for person in track.tagged_people] + peoples_names.append(track.owner.name) + peoples_names = set(map(str.lower, peoples_names)) + print(peoples_names) + return all(name.lower() in peoples_names for name in names) + + filters.append(has_people) + + if request.params.get('min-length'): + # Value is given in km, so convert it to m + min_length = _get_int(request, "min-length") * 1000 + filters.append(lambda track: track.length >= min_length) + + if request.params.get('max-length'): + max_length = _get_int(request, "max-length") * 1000 + filters.append(lambda track: track.length <= max_length) + + if request.params.get('min-date'): + min_date = _get_date(request, "min-date") + filters.append(lambda track: track.date.date() >= min_date) + + if request.params.get('max-date'): + max_date = _get_date(request, "max-date") + filters.append(lambda track: track.date.date() <= max_date) + + if "mine" in request.params.getall('show-only[]'): + filters.append(lambda track: track.owner == request.identity) + + if "friends" in request.params.getall('show-only[]'): + filters.append(lambda track: request.identity and + track.owner in request.identity.get_friends()) + + if request.params.get('user-tagged'): + filters.append(lambda track: request.identity and + (track.owner == request.identity or + request.identity in track.tagged_people)) + + return TrackFilters(filters) + + def visible_tracks(dbsession, user): """Returns all visible tracks for the given user. @@ -64,10 +170,13 @@ def browse(request): :return: The HTTP response. :rtype: pyramid.response.Response """ + filters = TrackFilters.parse(request) tracks = visible_tracks(request.dbsession, request.identity) + tracks = [track for track in tracks if filters.apply(track)] return { 'tracks': tracks, 'mps_to_kph': util.mps_to_kph, + 'used_filters': bool(filters), } |