diff --git a/README.md b/README.md index 0f31b09..35c619d 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ All templates can be overridden by setting these config values to your own templ | `WIKI_NOT_FOUND_TEMPLATE` | `'wiki/404.html'` | | `WIKI_FORBIDDEN_TEMPLATE` | `'wiki/403.html'` | | `WIKI_ICON_TEMPLATE` | `'wiki/icons/bootstrap.html'` | +| `WIKI_TOAST_TEMPLATE` | `'wiki/toast.html'` | ### Front-end assets @@ -151,6 +152,56 @@ instead of a CDN, which is what makes the wiki work without internet access: app.config["BOOTSTRAP_SERVE_LOCAL"] = True ``` +#### Page layout + +Every page — article, editor, file listing, search results, error — is laid out +by the same three class names, which an application overriding one of the page +templates has to keep: + +| Class | Role | +|-------|------| +| `wiki-page` | the grid: one column on a narrow screen, article plus outline from 768px up | +| `wiki-toc` | the table of contents, first in the source, placed on the right on a wide screen | +| `wiki-content` | the main column: article, editor form or listing, with its header | + +The TOC precedes the article in the source so a narrow screen shows it +first, and the grid moves it to the right-hand column on a wide one. It is +pinned with `position: sticky` and scrolls on its own once it outgrows the +viewport. A page without headings renders no `wiki-toc` at all, and the grid +falls back to a single centered column. + +#### Feedback + +Feedback shares one channel: the messages flashed by the server and the ones the +browser raises on its own are all toasts, stacked in a `wiki-toasts` container +fixed to the top right. Their markup comes from the `toast` macro of +`WIKI_TOAST_TEMPLATE`, and the toasts the wiki raises by itself live in +`wiki/toasts.html`. + +An application overriding `WIKI_BASE_TEMPLATE` renders its own stack. It +includes `wiki/toasts.html` in it, so it never has to know the ids `wiki.js` +reveals nor repeat their messages, and it renders the flashed messages itself if +nothing else in the application already does: + +```jinja +{% raw %}
+ {% for category, message in get_flashed_messages(with_categories=True) %} + {{ toast(message, category, autoshow=True) }} + {% endfor %} + {%- include "wiki/toasts.html" %} +
{% endraw %} +``` + +To render those toasts as the rest of the application does, point +`WIKI_TOAST_TEMPLATE` at a template of its own supplying a macro with the same +signature — `toast(message, category='message', id=None, autoshow=False)`, where +`id` marks a toast kept hidden until a script reveals it, and `autoshow` one +`wiki.js` reveals as soon as the page is ready: + +```python +app.config["WIKI_TOAST_TEMPLATE"] = "myapp/macros/toast.html" +``` + #### Icons Templates never name a glyph directly. They ask for an *intent* — `search`, diff --git a/flask_wiki/config.py b/flask_wiki/config.py index c7579c5..07aedd3 100644 --- a/flask_wiki/config.py +++ b/flask_wiki/config.py @@ -16,6 +16,8 @@ WIKI_PAGE_TEMPLATE = "wiki/page.html" # Supplies the icon() macro; swap for wiki/icons/fontawesome.html or your own WIKI_ICON_TEMPLATE = "wiki/icons/bootstrap.html" +# Supplies the toast() macro; swap for the one of the embedding application +WIKI_TOAST_TEMPLATE = "wiki/toast.html" # MISCS diff --git a/flask_wiki/static/css/wiki.css b/flask_wiki/static/css/wiki.css index bde8bb5..5237f17 100644 --- a/flask_wiki/static/css/wiki.css +++ b/flask_wiki/static/css/wiki.css @@ -47,12 +47,50 @@ h1 { color: #6c757d; } -.wiki-page .toc ul { +/* Article and table of contents: one column on a small screen, two on a wide + one. */ +.wiki-page { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 1rem 2.5rem; + max-width: 75rem; + margin-inline: auto; +} + +/* Anchors land a little under the top of the viewport, not flush against it. */ +.content h1, .content h2, .content h3, +.content h4, .content h5, .content h6 { + scroll-margin-top: 1rem; +} + +/* The TOC comes first in the source, so it comes first on a narrow screen, + where it must not push the article out of sight. */ +.wiki-toc { + max-height: 30vh; + overflow-y: auto; +} + +.wiki-toc ul { padding-left: 1rem; } -.wiki-page .toc { - z-index: 1000; +@media (min-width: 768px) { + /* The second column exists only on a page that has an outline. */ + .wiki-page:has(.wiki-toc) { + grid-template-columns: minmax(0, 1fr) 15rem; + } + + .wiki-content { + grid-area: 1 / 1; + } + + .wiki-toc { + grid-area: 1 / 2; + align-self: start; /* a stretched item has no room to stick */ + position: sticky; + top: 1rem; + max-height: calc(100vh - 2rem); + } } .wiki-editor textarea { @@ -61,8 +99,8 @@ h1 { .wiki-toasts { position: fixed; - top: 50px; - left: 15px; + top: 1rem; + right: 1rem; z-index: 1090; } diff --git a/flask_wiki/static/js/wiki.js b/flask_wiki/static/js/wiki.js index 5834d01..ed69277 100644 --- a/flask_wiki/static/js/wiki.js +++ b/flask_wiki/static/js/wiki.js @@ -2,20 +2,20 @@ // SPDX-License-Identifier: BSD-3-Clause $(document).ready(function () { + // reveal the messages flashed by the server + $('.toast[data-autoshow]').toast('show'); + // ask the backend for the preview and render it - $('.wiki-editor #preview-tab').on('click', function () { - var url = $(this).data('preview-url'); - var $form = $('form'); - var $inputs = $form.find('input, textarea, button'); - var $pre = $('#preview'); - var bodycontent = 'title: preview\n\n' + $form.find('textarea').val(); + $('#preview-tab').on('click', function () { + const $tab = $(this); + const $form = $tab.closest('form'); + const $inputs = $form.find('input, textarea, button'); + const $pre = $('#preview'); + const bodycontent = 'title: preview\n\n' + $form.find('textarea').val(); $inputs.prop('disabled', true); - $pre - .removeClass('alert') - .removeClass('alert-error') - .html('Loading...'); + $pre.removeClass('alert alert-danger').text($tab.data('loading-text')); $.ajax({ - url: url, + url: $tab.data('preview-url'), type: 'POST', data: { body: bodycontent }, success: function (msg) { @@ -23,8 +23,7 @@ $(document).ready(function () { }, error: function (e) { console.log('error: ', e); - $pre.addClass('alert').addClass('alert-error'); - $pre.html('There was a problem with the preview.'); + $pre.addClass('alert alert-danger').text($tab.data('error-text')); }, complete: function () { $inputs.prop('disabled', false); @@ -32,38 +31,37 @@ $(document).ready(function () { }); }); - // Add the following code if you want the name of the file appear on select + // selecting a file uploads it, no further click needed $('.wiki-files .custom-file-input').on('change', function () { - var form = $('form'); - form.submit(); + $(this).closest('form').submit(); }); - // copy the markdown code in the clip board + // copy the markdown code of a file to the clipboard $('.wiki-files .copy-md-code').on('click', function () { - // function copy(name, link) { - var name = $(this).data('name'); - var link = $(this).data('link');; + const name = $(this).data('name'); + const link = $(this).data('link'); copyToClipboard(`![${name}](${link} "${name}")`); }); - // copy the url code in the clip board + // copy the link of a page to the clipboard $('.copy-file-code').on('click', function () { - // function copy(name, link) { - var name = $(this).data('name'); - var link = $(this).data('link'); + const name = $(this).data('name'); + const link = $(this).data('link'); copyToClipboard(`[${name}](${link})`); }); - // Change the target modal when an element is clicked - $('.delete-file').on('click', function (e) { - var file = e.currentTarget.id; - var confirm = document.getElementById("confirm"); - var url = confirm.href.concat(file); - document.getElementById("confirm").href=url; + // point the confirmation button at the file the reader asked to delete + $('.delete-file').on('click', function () { + $('#confirm').attr('href', $(this).data('delete-url')); }); }); function copyToClipboard(text) { + // the clipboard API is missing outside a secure context + if (!navigator.clipboard) { + $('#copy-error').toast('show'); + return; + } navigator.clipboard.writeText(text).then( () => { $('#copy-success').toast('show'); diff --git a/flask_wiki/templates/wiki/403.html b/flask_wiki/templates/wiki/403.html index bfccddf..936ae21 100644 --- a/flask_wiki/templates/wiki/403.html +++ b/flask_wiki/templates/wiki/403.html @@ -10,8 +10,8 @@ {% endblock %} {% block content %} -
-
+
+

{{ _('Forbidden') }}

{{ _('You are not allowed to see this page.') }}

diff --git a/flask_wiki/templates/wiki/404.html b/flask_wiki/templates/wiki/404.html index 4b02cde..3a48c7d 100644 --- a/flask_wiki/templates/wiki/404.html +++ b/flask_wiki/templates/wiki/404.html @@ -10,8 +10,8 @@ {% endblock %} {% block content %} -
-
+
+

{{ _('Page does not exist.') }}

{{ _('You did not create any content for this page yet.') }}

diff --git a/flask_wiki/templates/wiki/base.html b/flask_wiki/templates/wiki/base.html index 4cbd8bd..acfb954 100644 --- a/flask_wiki/templates/wiki/base.html +++ b/flask_wiki/templates/wiki/base.html @@ -1,7 +1,7 @@ {# SPDX-FileCopyrightText: Fondation RERO+ #} {# SPDX-License-Identifier: BSD-3-Clause #} -{% from 'bootstrap4/utils.html' import render_messages %} +{% from config.get('WIKI_TOAST_TEMPLATE') import toast %} @@ -27,29 +27,16 @@ {{ _('Flask-Wiki') }} -

- {{ render_messages(dismissible=True, dismiss_animate=True) }} +
+ {% for category, message in get_flashed_messages(with_categories=True) %} + {{ toast(message, category, autoshow=True) }} + {% endfor %} + {%- include "wiki/toasts.html" %} +
+ +
{% block navigation %} {%- include "wiki/navigation.html" %} {% endblock %} - {% block content %} -
-
-
- Markdown -
-
- {{ _('Link copied to your clipboard') }} -
-
-
-
- Markdown -
-
- {{ _('Failed to copy link to your clipboard') }} -
-
-
- {% endblock %} + {% block content %}{% endblock %}
diff --git a/flask_wiki/templates/wiki/editor.html b/flask_wiki/templates/wiki/editor.html index 3738b1c..905059a 100644 --- a/flask_wiki/templates/wiki/editor.html +++ b/flask_wiki/templates/wiki/editor.html @@ -9,8 +9,8 @@ {% set active_page = "editor" %} {% block content %} -
-
+
+
diff --git a/flask_wiki/templates/wiki/page.html b/flask_wiki/templates/wiki/page.html index cd6fdb8..4186bd6 100644 --- a/flask_wiki/templates/wiki/page.html +++ b/flask_wiki/templates/wiki/page.html @@ -7,9 +7,14 @@ {% set active_page = "page" %} {% block content %} -{{ super() }} -
-
+
+ {% if page.toc %} + + {% endif %} +

{{page.title}}

@@ -49,13 +54,5 @@

{{page.title}}

{{ page }}
-
{% endblock %} diff --git a/flask_wiki/templates/wiki/search.html b/flask_wiki/templates/wiki/search.html index 9c79b51..23749d8 100644 --- a/flask_wiki/templates/wiki/search.html +++ b/flask_wiki/templates/wiki/search.html @@ -3,15 +3,12 @@ {% from config.get('WIKI_ICON_TEMPLATE') import icon %} -{% from 'bootstrap4/form.html' import render_form_row %} - {% extends config.get('WIKI_BASE_TEMPLATE') %} {% set active_page = "search" %} {% block content %} -{{ super() }} -
-
+
+
{{ results | length }} {{ ngettext('result', 'results', results | length) }} diff --git a/flask_wiki/templates/wiki/toast.html b/flask_wiki/templates/wiki/toast.html new file mode 100644 index 0000000..305ad16 --- /dev/null +++ b/flask_wiki/templates/wiki/toast.html @@ -0,0 +1,19 @@ +{# SPDX-FileCopyrightText: Fondation RERO+ #} +{# SPDX-License-Identifier: BSD-3-Clause #} + +{# Feedback toast, used both for the messages flashed by the server and for the + ones the browser raises on its own. `autoshow` marks a toast that wiki.js + reveals as soon as the page is ready; the others are revealed by their id. #} +{% macro toast(message, category='message', id=None, autoshow=False) %} +{% set colors = {'success': 'text-success', 'error': 'text-danger', 'danger': 'text-danger'} %} + +{% endmacro %} diff --git a/flask_wiki/templates/wiki/toasts.html b/flask_wiki/templates/wiki/toasts.html new file mode 100644 index 0000000..4e3b2b8 --- /dev/null +++ b/flask_wiki/templates/wiki/toasts.html @@ -0,0 +1,11 @@ +{# SPDX-FileCopyrightText: Fondation RERO+ #} +{# SPDX-License-Identifier: BSD-3-Clause #} + +{# The toasts the wiki raises from the browser, which wiki.js reveals through + their id. An application rendering its own toast stack includes this file + inside it, and never has to know these ids nor repeat their messages. #} + +{% from config.get('WIKI_TOAST_TEMPLATE') import toast %} + +{{ toast(_('Link copied to your clipboard'), 'success', id='copy-success') }} +{{ toast(_('Failed to copy link to your clipboard'), 'error', id='copy-error') }} diff --git a/flask_wiki/translations/de/LC_MESSAGES/messages.mo b/flask_wiki/translations/de/LC_MESSAGES/messages.mo index b0a8958..9d88960 100644 Binary files a/flask_wiki/translations/de/LC_MESSAGES/messages.mo and b/flask_wiki/translations/de/LC_MESSAGES/messages.mo differ diff --git a/flask_wiki/translations/de/LC_MESSAGES/messages.po b/flask_wiki/translations/de/LC_MESSAGES/messages.po index 14a8aa7..25b455a 100644 --- a/flask_wiki/translations/de/LC_MESSAGES/messages.po +++ b/flask_wiki/translations/de/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Admin VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: 2020-01-30 11:47+0100\n" "Last-Translator: FULL NAME \n" "Language: de\n" @@ -50,7 +50,9 @@ msgstr "Datei gelöscht" #: flask_wiki/views.py:206 #, python-brace-format msgid "Something went wrong. Could not delete file. Error: {e}" -msgstr "Ein Fehler ist aufgetreten. Die Datei konnte nicht gelöscht werden. Fehler: {e}" +msgstr "" +"Ein Fehler ist aufgetreten. Die Datei konnte nicht gelöscht werden. " +"Fehler: {e}" #: flask_wiki/views.py:219 msgid "No file part" @@ -93,56 +95,65 @@ msgstr "Eine neue Seite erstellen" msgid "Flask-Wiki" msgstr "Flask-Wiki" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "Link in die Zwischenablage kopiert" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "Link konnte nicht in Ihre Zwischenablage kopiert werden" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "Bereitgestellt von" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "Bearbeiten" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "Wird geladen…" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "Die Vorschau konnte nicht erstellt werden." + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "Vorschau" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "Bearbeitung auf %(language)s" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "Löschen" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "Bearbeiten auf" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "Speichern" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "Seite löschen" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "Schliessen" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." @@ -150,26 +161,26 @@ msgstr "" "Sind Sie sicher, dass Sie diese Seite löschen möchten? Seien Sie gewarnt," " dass Links, die auf zu dieser Seite wird nicht mehr funktionieren." -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "Zurück" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "Liste der hochgeladenen Dateien" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" msgstr "Eine Datei hochladen" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "Markdown-Code kopieren" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "Datei löschen" @@ -199,16 +210,20 @@ msgstr "Dateien" msgid "Search" msgstr "Suche" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "Inhaltsverzeichnis" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "Link kopieren" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "Letzte Änderung:" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " @@ -217,11 +232,7 @@ msgstr "" "Diese Seite gibt es noch nicht in Ihrer Sprache. Sie wird auf " "%(language)s angezeigt." -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "Inhaltsverzeichnis" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "Ergebnis" diff --git a/flask_wiki/translations/en/LC_MESSAGES/messages.mo b/flask_wiki/translations/en/LC_MESSAGES/messages.mo index 9f13361..e25e492 100644 Binary files a/flask_wiki/translations/en/LC_MESSAGES/messages.mo and b/flask_wiki/translations/en/LC_MESSAGES/messages.mo differ diff --git a/flask_wiki/translations/en/LC_MESSAGES/messages.po b/flask_wiki/translations/en/LC_MESSAGES/messages.po index 70df6da..a3c9117 100644 --- a/flask_wiki/translations/en/LC_MESSAGES/messages.po +++ b/flask_wiki/translations/en/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Admin VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: 2020-01-30 11:47+0100\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -93,81 +93,90 @@ msgstr "" msgid "Flask-Wiki" msgstr "" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "" + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." msgstr "" -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" msgstr "" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "" @@ -195,27 +204,27 @@ msgstr "" msgid "Search" msgstr "" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " "%(language)s." msgstr "" -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "" diff --git a/flask_wiki/translations/fr/LC_MESSAGES/messages.mo b/flask_wiki/translations/fr/LC_MESSAGES/messages.mo index 10bcbc8..4169c1f 100644 Binary files a/flask_wiki/translations/fr/LC_MESSAGES/messages.mo and b/flask_wiki/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/flask_wiki/translations/fr/LC_MESSAGES/messages.po b/flask_wiki/translations/fr/LC_MESSAGES/messages.po index ef8d084..a1df898 100644 --- a/flask_wiki/translations/fr/LC_MESSAGES/messages.po +++ b/flask_wiki/translations/fr/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Admin VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: 2020-01-30 11:47+0100\n" "Last-Translator: FULL NAME \n" "Language: fr\n" @@ -93,56 +93,65 @@ msgstr "Créer une nouvelle page" msgid "Flask-Wiki" msgstr "Flask-Wiki" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "Lien copié dans le presse-papier" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "Impossible de copier le lien dans le presse-papier" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "Propulsé par" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "Modifier" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "Chargement…" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "L'aperçu n'a pas pu être généré." + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "Aperçu" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "Édition en %(language)s" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "Supprimer" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "Modifier en" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "Enregistrer" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "Supprimer la page" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "Fermer" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." @@ -150,26 +159,26 @@ msgstr "" "Voulez-vous vraiment supprimer cette page ? Les liens pointant vers cette" " page cesseront de fonctionner" -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "Retour" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "Liste des fichiers téléchargés" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" -msgstr "Télécharger un fichier" +msgstr "Téléverser un fichier" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "Copier le code Markdown" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "Supprimer le fichier" @@ -199,16 +208,20 @@ msgstr "Fichiers" msgid "Search" msgstr "Recherche" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "Table des matières" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "Copier le lien" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "Dernière modification :" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " @@ -217,11 +230,7 @@ msgstr "" "Cette page n'existe pas encore dans votre langue. Elle est affichée en " "%(language)s." -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "Table des matières" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "résulat" diff --git a/flask_wiki/translations/hu/LC_MESSAGES/messages.mo b/flask_wiki/translations/hu/LC_MESSAGES/messages.mo index f41c1b0..f7c5bc1 100644 Binary files a/flask_wiki/translations/hu/LC_MESSAGES/messages.mo and b/flask_wiki/translations/hu/LC_MESSAGES/messages.mo differ diff --git a/flask_wiki/translations/hu/LC_MESSAGES/messages.po b/flask_wiki/translations/hu/LC_MESSAGES/messages.po index 04fd506..5591c68 100644 --- a/flask_wiki/translations/hu/LC_MESSAGES/messages.po +++ b/flask_wiki/translations/hu/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Wiki VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: 2022-07-12 10:52+0200\n" "Last-Translator: FULL NAME \n" "Language: hu\n" @@ -92,56 +92,65 @@ msgstr "Új oldal létrehozása" msgid "Flask-Wiki" msgstr "Flask-Wiki" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "Vágólapra másolva" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "Nem sikerült a vágólapra másolni" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "Működteti" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "Szerkesztés" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "Betöltés…" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "Az előnézet nem hozható létre." + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "Előnézet" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "Szerkesztés %(language)s nyelven" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "Törlés" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "Szerkesztés a következővel" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "Mentés" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "Oldal törlése" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "Bezárás" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." @@ -149,26 +158,26 @@ msgstr "" "Biztosan törlöd az oldalt? Ne felejtsd el, hogy az erre az oldalra mutató" " linkek ezután nem fognak működni." -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "Vissza" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "Feltöltött fájlok listája" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" msgstr "Fájl feltöltése" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "Markdown-kód másolása" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "Fájl törlése" @@ -198,16 +207,20 @@ msgstr "Fájlok" msgid "Search" msgstr "Keresés" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "Tartalomjegyzék" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "Link másolása" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "Utoljára módosítva:" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " @@ -216,11 +229,7 @@ msgstr "" "Ez az oldal még nem érhető el a nyelveden. %(language)s nyelven jelenik " "meg." -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "Tartalomjegyzék" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "találat" diff --git a/flask_wiki/translations/it/LC_MESSAGES/messages.mo b/flask_wiki/translations/it/LC_MESSAGES/messages.mo index d7100f6..b11f6f8 100644 Binary files a/flask_wiki/translations/it/LC_MESSAGES/messages.mo and b/flask_wiki/translations/it/LC_MESSAGES/messages.mo differ diff --git a/flask_wiki/translations/it/LC_MESSAGES/messages.po b/flask_wiki/translations/it/LC_MESSAGES/messages.po index 8250e51..42bdb0f 100644 --- a/flask_wiki/translations/it/LC_MESSAGES/messages.po +++ b/flask_wiki/translations/it/LC_MESSAGES/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Admin VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: 2020-01-30 11:47+0100\n" "Last-Translator: FULL NAME \n" "Language: it\n" @@ -93,56 +93,65 @@ msgstr "Creare una nuova pagina" msgid "Flask-Wiki" msgstr "Flask-Wiki" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "Link copiato negli appunti" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "Impossibile copiare il link negli appunti" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "Realizzato con" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "Modificare" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "Caricamento…" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "Impossibile generare l'anteprima." + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "Anteprima" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "Modifica in %(language)s" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "Cancellare" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "Modificare in" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "Salvare" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "Cancellare la pagina" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "Chiudere" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." @@ -150,26 +159,26 @@ msgstr "" "Sei sicuro di voler cancellare questa pagina? Attenzione, i link che " "puntano a questa pagina smetterà di funzionare." -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "Indietro" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "Elenco dei file caricati" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" msgstr "Caricare un file" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "Copiare il codice Markdown" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "Cancellare il file" @@ -199,16 +208,20 @@ msgstr "File" msgid "Search" msgstr "Ricerca" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "Indice dei contenuti" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "Copiare il link" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "Ultima modifica:" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " @@ -217,11 +230,7 @@ msgstr "" "Questa pagina non esiste ancora nella tua lingua. È visualizzata in " "%(language)s." -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "Indice dei contenuti" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "risultato" diff --git a/flask_wiki/translations/messages.pot b/flask_wiki/translations/messages.pot index 0bc8092..4232c26 100644 --- a/flask_wiki/translations/messages.pot +++ b/flask_wiki/translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Flask-Wiki VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-28 09:51+0200\n" +"POT-Creation-Date: 2026-09-03 14:25+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -91,81 +91,90 @@ msgstr "" msgid "Flask-Wiki" msgstr "" -#: flask_wiki/templates/wiki/base.html:39 +#: flask_wiki/templates/wiki/base.html:34 msgid "Link copied to your clipboard" msgstr "" -#: flask_wiki/templates/wiki/base.html:47 +#: flask_wiki/templates/wiki/base.html:35 msgid "Failed to copy link to your clipboard" msgstr "" -#: flask_wiki/templates/wiki/base.html:56 +#: flask_wiki/templates/wiki/base.html:46 msgid "Powered by" msgstr "" #: flask_wiki/templates/wiki/editor.html:17 -#: flask_wiki/templates/wiki/page.html:25 -#: flask_wiki/templates/wiki/search.html:52 +#: flask_wiki/templates/wiki/page.html:30 +#: flask_wiki/templates/wiki/search.html:49 msgid "Edit" msgstr "" #: flask_wiki/templates/wiki/editor.html:22 +msgid "Loading..." +msgstr "" + +#: flask_wiki/templates/wiki/editor.html:23 +msgid "There was a problem with the preview." +msgstr "" + +#: flask_wiki/templates/wiki/editor.html:24 msgid "Preview" msgstr "" -#: flask_wiki/templates/wiki/editor.html:27 +#: flask_wiki/templates/wiki/editor.html:29 #, python-format msgid "Editing in %(language)s" msgstr "" -#: flask_wiki/templates/wiki/editor.html:33 +#: flask_wiki/templates/wiki/editor.html:35 msgid "Delete" msgstr "" -#: flask_wiki/templates/wiki/editor.html:39 +#: flask_wiki/templates/wiki/editor.html:41 msgid "Edit in" msgstr "" -#: flask_wiki/templates/wiki/editor.html:50 +#: flask_wiki/templates/wiki/editor.html:52 msgid "Save" msgstr "" -#: flask_wiki/templates/wiki/editor.html:73 -#: flask_wiki/templates/wiki/editor.html:82 +#: flask_wiki/templates/wiki/editor.html:75 +#: flask_wiki/templates/wiki/editor.html:84 msgid "Delete page" msgstr "" -#: flask_wiki/templates/wiki/editor.html:74 +#: flask_wiki/templates/wiki/editor.html:76 #: flask_wiki/templates/wiki/files.html:54 +#: flask_wiki/templates/wiki/toast.html:14 msgid "Close" msgstr "" -#: flask_wiki/templates/wiki/editor.html:79 +#: flask_wiki/templates/wiki/editor.html:81 msgid "" "Are you sure you want to delete this page? Be warned that links pointing " "to this page will stop working." msgstr "" -#: flask_wiki/templates/wiki/editor.html:83 -#: flask_wiki/templates/wiki/files.html:64 +#: flask_wiki/templates/wiki/editor.html:85 +#: flask_wiki/templates/wiki/files.html:63 msgid "Back" msgstr "" -#: flask_wiki/templates/wiki/files.html:14 +#: flask_wiki/templates/wiki/files.html:13 msgid "List of Uploaded Files" msgstr "" -#: flask_wiki/templates/wiki/files.html:18 +#: flask_wiki/templates/wiki/files.html:17 msgid "Upload a file" msgstr "" -#: flask_wiki/templates/wiki/files.html:33 +#: flask_wiki/templates/wiki/files.html:32 msgid "Copy Markdown code" msgstr "" #: flask_wiki/templates/wiki/files.html:37 #: flask_wiki/templates/wiki/files.html:53 -#: flask_wiki/templates/wiki/files.html:63 +#: flask_wiki/templates/wiki/files.html:62 msgid "Delete file" msgstr "" @@ -193,27 +202,27 @@ msgstr "" msgid "Search" msgstr "" -#: flask_wiki/templates/wiki/page.html:21 -#: flask_wiki/templates/wiki/search.html:48 +#: flask_wiki/templates/wiki/page.html:13 +msgid "Table of contents" +msgstr "" + +#: flask_wiki/templates/wiki/page.html:26 +#: flask_wiki/templates/wiki/search.html:45 msgid "Copy link" msgstr "" -#: flask_wiki/templates/wiki/page.html:39 +#: flask_wiki/templates/wiki/page.html:44 msgid "Last updated:" msgstr "" -#: flask_wiki/templates/wiki/page.html:45 +#: flask_wiki/templates/wiki/page.html:50 #, python-format msgid "" "This page does not exist yet in your language. It is displayed in " "%(language)s." msgstr "" -#: flask_wiki/templates/wiki/page.html:55 -msgid "Table of contents" -msgstr "" - -#: flask_wiki/templates/wiki/search.html:17 +#: flask_wiki/templates/wiki/search.html:14 msgid "result" msgid_plural "results" msgstr[0] "" diff --git a/tests/data/plain_en.md b/tests/data/plain_en.md new file mode 100644 index 0000000..d0c3a16 --- /dev/null +++ b/tests/data/plain_en.md @@ -0,0 +1,4 @@ +title: Plain Page +tags: test + +A page without any heading, and therefore without a table of contents. diff --git a/tests/templates/custom_toast.html b/tests/templates/custom_toast.html new file mode 100644 index 0000000..0d2c1d8 --- /dev/null +++ b/tests/templates/custom_toast.html @@ -0,0 +1,9 @@ +{# SPDX-FileCopyrightText: Fondation RERO+ #} +{# SPDX-License-Identifier: BSD-3-Clause #} + +{# The toast markup an embedding application would supply of its own. #} + +{% macro toast(message, category='message', id=None, autoshow=False) %} +
{{ message }}
+{% endmacro %} diff --git a/tests/test_views.py b/tests/test_views.py index 9d5b343..cbf5190 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -53,6 +53,21 @@ def test_page_display(client): assert b"Home" in res.data +def test_page_outline_precedes_the_article(client): + """Test that the outline is rendered before the article, and only when it has entries. + + The two are placed side by side on a wide screen, so the source order is the one a + narrow screen gets: the outline first, where it is of some use. + """ + html = client.get("/help/sample/").data.decode() + assert html.index('class="wiki-toc"') < html.index('class="wiki-content"') + + # a page without headings gets no outline at all, hence no empty column + html = client.get("/help/plain/").data.decode() + assert 'class="wiki-toc"' not in html + assert 'class="wiki-content"' in html + + def test_page_not_found(client): """Test that a missing page returns 404.""" res = client.get("/help/nonexistent/") @@ -225,6 +240,31 @@ def test_file_upload_and_delete(client, app): assert not os.path.isfile(upload_path) +def test_delete_button_carries_the_url_of_its_own_file(client, app): + """Test that each delete button names the file it deletes. + + The confirmation link used to be completed in JavaScript from a shared base URL, + which appended a second name when the reader opened the dialog twice in a row. + """ + data = {"file": (io.BytesIO(TINY_PNG), "delete_target.png")} + upload_path = os.path.join(app.config["WIKI_UPLOAD_FOLDER"], "delete_target.png") + try: + client.post("/help/files", data=data, content_type="multipart/form-data", follow_redirects=True) + html = client.get("/help/files").data.decode() + assert 'data-delete-url="/help/file/delete/delete_target.png"' in html + assert 'id="confirm" href="#"' in html + finally: + if os.path.isfile(upload_path): + os.remove(upload_path) + + +def test_preview_tab_carries_its_own_messages(client): + """Test that the preview feedback is translated by the server, not hard-coded in JS.""" + html = client.get("/help/edit/home/").data.decode() + assert 'data-loading-text="Loading..."' in html + assert 'data-error-text="There was a problem with the preview."' in html + + def test_file_upload_invalid_extension(client, app): """Test that uploading a disallowed file type is rejected.""" data = {"file": (io.BytesIO(b"not a real exe"), "malware.exe")} @@ -269,6 +309,26 @@ def test_pages_do_not_reference_external_assets(client): assert not asset.startswith(("http://", "https://", "//")), f"{url}: {asset}" +def test_flashed_message_joins_the_toast_stack(client, app): + """Test that a message flashed by the server is rendered as a toast. + + Server feedback then looks like clipboard feedback, and no full-width banner sits + between the navigation and the top of the application. + """ + path = os.path.join(app.config["WIKI_CONTENT_DIR"], "flashed_en.md") + try: + html = client.post( + "/help/edit/flashed/", + data={"title": "Flashed", "body": "# Flashed\n\nContent.", "tags": "test"}, + follow_redirects=True, + ).data.decode() + assert "alert-success" not in html + assert html.index("data-autoshow") < html.index("Saved") < html.index("copy-success") + finally: + if os.path.isfile(path): + os.remove(path) + + def test_toasts_are_placed_by_their_own_wrapper(client, app): """Test that the toasts are positioned by a wiki class instead of `.toast`. @@ -311,6 +371,30 @@ def test_icon_template_can_be_swapped(app): app.config["WIKI_ICON_TEMPLATE"] = "wiki/icons/bootstrap.html" +def test_toasts_are_rendered_for_the_browser_to_reveal(client): + """Test that a page carries the toasts wiki.js reveals through their id.""" + html = client.get("/help/home/").data.decode() + assert 'id="copy-success"' in html + assert 'id="copy-error"' in html + + +def test_toast_template_can_be_swapped(app): + """Test that WIKI_TOAST_TEMPLATE selects the markup used for every toast.""" + try: + app.config["WIKI_TOAST_TEMPLATE"] = "custom_toast.html" + with app.test_client() as c: + with c.session_transaction() as session: + session["_flashes"] = [("success", "a flashed message")] + html = c.get("/help/home/").data.decode() + # the toasts of the wiki are rendered by the macro of the application + assert '
a flashed message' in html + finally: + app.config["WIKI_TOAST_TEMPLATE"] = "wiki/toast.html" + + def test_icon_only_buttons_have_an_accessible_name(client, app): """Test that buttons rendered as a bare icon carry an aria-label.""" assert 'aria-label="Search"' in client.get("/help/home/").data.decode()