зеркало из https://github.com/nextcloud/cookbook.git
Merge remote-tracking branch 'upstream/master' into document-development-environment
Signed-off-by: Christian Wolf <github@christianwolf.email>
This commit is contained in:
Коммит
98f44587b6
|
@ -1 +1 @@
|
||||||
9
|
10
|
||||||
|
|
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,5 +1,16 @@
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Reduce complex coupling between event handlers in EditInputGroup.vue
|
||||||
|
[#901](https://github.com/nextcloud/cookbook/pull/901) @MarcelRobitaille
|
||||||
|
|
||||||
|
|
||||||
|
## 0.9.10 - 2022-03-04
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Remove prefix of pasted content for better formatting
|
||||||
|
[#887](https://github.com/nextcloud/cookbook/pull/887) @MarcelRobitaille
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Added app info XML back to allow automatic translations
|
- Added app info XML back to allow automatic translations
|
||||||
[#878](https://github.com/nextcloud/cookbook/pull/878) @christianlupus
|
[#878](https://github.com/nextcloud/cookbook/pull/878) @christianlupus
|
||||||
|
@ -9,6 +20,22 @@
|
||||||
[#880](https://github.com/nextcloud/cookbook/pull/880) @christianlupus
|
[#880](https://github.com/nextcloud/cookbook/pull/880) @christianlupus
|
||||||
- Usage of caches for NPM speedup
|
- Usage of caches for NPM speedup
|
||||||
[#883](https://github.com/nextcloud/cookbook/pull/883) @christianlupus
|
[#883](https://github.com/nextcloud/cookbook/pull/883) @christianlupus
|
||||||
|
- Make the controls sticky on top
|
||||||
|
[#888](https://github.com/nextcloud/cookbook/pull/888) @MarcelRobitaille
|
||||||
|
- Cleanup code related to pasting
|
||||||
|
[#886](https://github.com/nextcloud/cookbook/pull/886) @MarcelRobitaille
|
||||||
|
- Make height of control header dependant on server CSS variable
|
||||||
|
[#897](https://github.com/nextcloud/cookbook/pull/897) @MarcelRobitaille
|
||||||
|
- Fix UI glitch when keyword list is empty
|
||||||
|
[#892](https://github.com/nextcloud/cookbook/pull/892) @MarcelRobitaille
|
||||||
|
- Allow switching to new instruction line with Enter key
|
||||||
|
[#890](https://github.com/nextcloud/cookbook/pull/890) @MarcelRobitaille
|
||||||
|
- Prevent inserting newline characters in instructions/ingredients/tools when pressing enter
|
||||||
|
[#900](https://github.com/nextcloud/cookbook/pull/900) @MarcelRobitaille
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- Added clarification between categories and keywords for users
|
||||||
|
[#889](https://github.com/nextcloud/cookbook/pull/889) @MarcelRobitaille
|
||||||
|
|
||||||
|
|
||||||
## 0.9.9 - 2022-01-13
|
## 0.9.9 - 2022-01-13
|
||||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 52 KiB |
Двоичный файл не отображается.
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
### Importing from a Website
|
### Importing from a Website
|
||||||
|
|
||||||
Recipes can be imported by entering the URL to a recipe in the text-input field in the top right area of the Cookbook app.
|
Recipes can be imported by entering the URL to a recipe in the text-input field in the top right area of the Cookbook app.
|
||||||
|
|
||||||
<img src="assets/create_import.png" alt="Recipe-import field" width="200px" />
|
<img src="assets/create_import.png" alt="Recipe-import field" width="200px" />
|
||||||
|
|
||||||
|
@ -23,4 +23,25 @@ Currently, the only way to share recipes is by sharing the Nextcloud folder that
|
||||||
|
|
||||||
### Public Sharing
|
### Public Sharing
|
||||||
|
|
||||||
At the moment it is not possible to share a public link to a recipe.
|
At the moment it is not possible to share a public link to a recipe.
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### When should I use keywords and when should I use categories to organize my recipes?
|
||||||
|
|
||||||
|
The use of keywords and categories is entirely up to you.
|
||||||
|
|
||||||
|
The primary difference between the two is that a recipe can only have a single category,
|
||||||
|
but may have many keywords.
|
||||||
|
In other words,
|
||||||
|
categories are a 1:N relationship while keywords are an N:M relationship.
|
||||||
|
|
||||||
|
Categories can be accessed more directly than keywords,
|
||||||
|
as they appear in the sidebar.
|
||||||
|
By clicking a category in the sidebar,
|
||||||
|
you can quickly narrow down recipes to a certain class, like "Main dishes" or "Deserts".
|
||||||
|
Then, keywords can be used to further narrow down the selection
|
||||||
|
with tags like "vegetarian" or "easy".
|
||||||
|
In this way, categories are used for rough filtering and keywords are used for fine filtering.
|
||||||
|
|
||||||
|
![Example workflow using categories for rough filtering and keywords for fine filtering](assets/keywords-and-categories.png)
|
||||||
|
|
|
@ -58,6 +58,7 @@ OC.L10N.register(
|
||||||
"Could not set recipe update interval to {interval}" : "Kunne ikke sætte opdaterings interval til {interval}.",
|
"Could not set recipe update interval to {interval}" : "Kunne ikke sætte opdaterings interval til {interval}.",
|
||||||
"Could not set recipe folder to {path}" : "Kunne ikke sætte opskrifts mappen til {path}.",
|
"Could not set recipe folder to {path}" : "Kunne ikke sætte opskrifts mappen til {path}.",
|
||||||
"Loading config failed" : "Indlæsning af konfiguration fejlet!",
|
"Loading config failed" : "Indlæsning af konfiguration fejlet!",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Indtast URL eller vælg fra din Nextcloud-instans til højre",
|
||||||
"Pick a local image" : "Vælg et lokalt billede",
|
"Pick a local image" : "Vælg et lokalt billede",
|
||||||
"Path to your recipe image" : "Sti til dit opskriftsbillede",
|
"Path to your recipe image" : "Sti til dit opskriftsbillede",
|
||||||
"Move entry up" : "Flyt op",
|
"Move entry up" : "Flyt op",
|
||||||
|
@ -71,6 +72,9 @@ OC.L10N.register(
|
||||||
"Description" : "Beskrivelse",
|
"Description" : "Beskrivelse",
|
||||||
"URL" : "Url",
|
"URL" : "Url",
|
||||||
"Image" : "Billede",
|
"Image" : "Billede",
|
||||||
|
"Preparation time (hours:minutes)" : "Forberedelsestid (timer:minutter)",
|
||||||
|
"Cooking time (hours:minutes)" : "Tilberedningstid (timer:minutter)",
|
||||||
|
"Total time (hours:minutes)" : "Samlet tid (timer:minutter)",
|
||||||
"Choose category" : "Vælg kategori",
|
"Choose category" : "Vælg kategori",
|
||||||
"Keywords" : "Nøgleord",
|
"Keywords" : "Nøgleord",
|
||||||
"Choose keywords" : "Vælg nøgleord",
|
"Choose keywords" : "Vælg nøgleord",
|
||||||
|
@ -114,6 +118,9 @@ OC.L10N.register(
|
||||||
"Search recipes with this keyword" : "Søg efter opskrifter med dette nøgleord",
|
"Search recipes with this keyword" : "Søg efter opskrifter med dette nøgleord",
|
||||||
"Date created" : "Oprettet den",
|
"Date created" : "Oprettet den",
|
||||||
"Last modified" : "Sidst ændret",
|
"Last modified" : "Sidst ændret",
|
||||||
|
"Preparation time (H:MM)" : "Forberedelsestid (T:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tilberedningstid (T:MM)",
|
||||||
|
"Total time (H:MM)" : "Samlet tid (T:MM)",
|
||||||
"Serving Size" : "Antal portioner",
|
"Serving Size" : "Antal portioner",
|
||||||
"Energy" : "Energiindhold",
|
"Energy" : "Energiindhold",
|
||||||
"Sugar" : "Sukker",
|
"Sugar" : "Sukker",
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"Could not set recipe update interval to {interval}" : "Kunne ikke sætte opdaterings interval til {interval}.",
|
"Could not set recipe update interval to {interval}" : "Kunne ikke sætte opdaterings interval til {interval}.",
|
||||||
"Could not set recipe folder to {path}" : "Kunne ikke sætte opskrifts mappen til {path}.",
|
"Could not set recipe folder to {path}" : "Kunne ikke sætte opskrifts mappen til {path}.",
|
||||||
"Loading config failed" : "Indlæsning af konfiguration fejlet!",
|
"Loading config failed" : "Indlæsning af konfiguration fejlet!",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Indtast URL eller vælg fra din Nextcloud-instans til højre",
|
||||||
"Pick a local image" : "Vælg et lokalt billede",
|
"Pick a local image" : "Vælg et lokalt billede",
|
||||||
"Path to your recipe image" : "Sti til dit opskriftsbillede",
|
"Path to your recipe image" : "Sti til dit opskriftsbillede",
|
||||||
"Move entry up" : "Flyt op",
|
"Move entry up" : "Flyt op",
|
||||||
|
@ -69,6 +70,9 @@
|
||||||
"Description" : "Beskrivelse",
|
"Description" : "Beskrivelse",
|
||||||
"URL" : "Url",
|
"URL" : "Url",
|
||||||
"Image" : "Billede",
|
"Image" : "Billede",
|
||||||
|
"Preparation time (hours:minutes)" : "Forberedelsestid (timer:minutter)",
|
||||||
|
"Cooking time (hours:minutes)" : "Tilberedningstid (timer:minutter)",
|
||||||
|
"Total time (hours:minutes)" : "Samlet tid (timer:minutter)",
|
||||||
"Choose category" : "Vælg kategori",
|
"Choose category" : "Vælg kategori",
|
||||||
"Keywords" : "Nøgleord",
|
"Keywords" : "Nøgleord",
|
||||||
"Choose keywords" : "Vælg nøgleord",
|
"Choose keywords" : "Vælg nøgleord",
|
||||||
|
@ -112,6 +116,9 @@
|
||||||
"Search recipes with this keyword" : "Søg efter opskrifter med dette nøgleord",
|
"Search recipes with this keyword" : "Søg efter opskrifter med dette nøgleord",
|
||||||
"Date created" : "Oprettet den",
|
"Date created" : "Oprettet den",
|
||||||
"Last modified" : "Sidst ændret",
|
"Last modified" : "Sidst ændret",
|
||||||
|
"Preparation time (H:MM)" : "Forberedelsestid (T:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tilberedningstid (T:MM)",
|
||||||
|
"Total time (H:MM)" : "Samlet tid (T:MM)",
|
||||||
"Serving Size" : "Antal portioner",
|
"Serving Size" : "Antal portioner",
|
||||||
"Energy" : "Energiindhold",
|
"Energy" : "Energiindhold",
|
||||||
"Sugar" : "Sukker",
|
"Sugar" : "Sukker",
|
||||||
|
|
|
@ -2,6 +2,7 @@ OC.L10N.register(
|
||||||
"cookbook",
|
"cookbook",
|
||||||
{
|
{
|
||||||
"Cannot detect type of transmitted data. This is a bug, please report it." : "Δεν είναι δυνατή η ανίχνευση τύπου μεταδιδόμενων δεδομένων. Αυτό είναι ένα σφάλμα, αναφέρετέ το.",
|
"Cannot detect type of transmitted data. This is a bug, please report it." : "Δεν είναι δυνατή η ανίχνευση τύπου μεταδιδόμενων δεδομένων. Αυτό είναι ένα σφάλμα, αναφέρετέ το.",
|
||||||
|
"Invalid URL-encoded string found. Please report a bug." : "Βρέθηκε μη-έγκυρη ακολουθία χαρακτήρων κωδικοποιημένου-υπερσυνδέσμου. Παρακαλώ αναφέρετε το σφάλμα.",
|
||||||
"Recipes" : "Συνταγές",
|
"Recipes" : "Συνταγές",
|
||||||
"Another recipe with that name already exists" : "Υπάρχει άλλη συνταγή με το ίδιο όνομα",
|
"Another recipe with that name already exists" : "Υπάρχει άλλη συνταγή με το ίδιο όνομα",
|
||||||
"Cookbook" : "Βιβλίο συνταγών",
|
"Cookbook" : "Βιβλίο συνταγών",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{ "translations": {
|
{ "translations": {
|
||||||
"Cannot detect type of transmitted data. This is a bug, please report it." : "Δεν είναι δυνατή η ανίχνευση τύπου μεταδιδόμενων δεδομένων. Αυτό είναι ένα σφάλμα, αναφέρετέ το.",
|
"Cannot detect type of transmitted data. This is a bug, please report it." : "Δεν είναι δυνατή η ανίχνευση τύπου μεταδιδόμενων δεδομένων. Αυτό είναι ένα σφάλμα, αναφέρετέ το.",
|
||||||
|
"Invalid URL-encoded string found. Please report a bug." : "Βρέθηκε μη-έγκυρη ακολουθία χαρακτήρων κωδικοποιημένου-υπερσυνδέσμου. Παρακαλώ αναφέρετε το σφάλμα.",
|
||||||
"Recipes" : "Συνταγές",
|
"Recipes" : "Συνταγές",
|
||||||
"Another recipe with that name already exists" : "Υπάρχει άλλη συνταγή με το ίδιο όνομα",
|
"Another recipe with that name already exists" : "Υπάρχει άλλη συνταγή με το ίδιο όνομα",
|
||||||
"Cookbook" : "Βιβλίο συνταγών",
|
"Cookbook" : "Βιβλίο συνταγών",
|
||||||
|
|
|
@ -58,6 +58,7 @@ OC.L10N.register(
|
||||||
"Could not set recipe update interval to {interval}" : "No se puede ajustar el intervalo de actualización de la receta a {interval}",
|
"Could not set recipe update interval to {interval}" : "No se puede ajustar el intervalo de actualización de la receta a {interval}",
|
||||||
"Could not set recipe folder to {path}" : "No fue posible establecer {path} como ruta para la carpeta de recetas",
|
"Could not set recipe folder to {path}" : "No fue posible establecer {path} como ruta para la carpeta de recetas",
|
||||||
"Loading config failed" : "Fallo al cargar la configuración",
|
"Loading config failed" : "Fallo al cargar la configuración",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Introduce la URL o selecciona desde tu instancia de Nextcloud a la derecha",
|
||||||
"Pick a local image" : "Seleccione una imagen local",
|
"Pick a local image" : "Seleccione una imagen local",
|
||||||
"Path to your recipe image" : "Ruta a tu imagen de la receta",
|
"Path to your recipe image" : "Ruta a tu imagen de la receta",
|
||||||
"Move entry up" : "Mover entrada hacia arriba",
|
"Move entry up" : "Mover entrada hacia arriba",
|
||||||
|
@ -71,6 +72,9 @@ OC.L10N.register(
|
||||||
"Description" : "Descripción",
|
"Description" : "Descripción",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Imagen",
|
"Image" : "Imagen",
|
||||||
|
"Preparation time (hours:minutes)" : "Tiempo de preparación (horas:minutos)",
|
||||||
|
"Cooking time (hours:minutes)" : "Tiempo de cocinado (horas:minutos)",
|
||||||
|
"Total time (hours:minutes)" : "Tiempo total (horas:minutos)",
|
||||||
"Choose category" : "Escoge una categoría",
|
"Choose category" : "Escoge una categoría",
|
||||||
"Keywords" : "Palabras clave",
|
"Keywords" : "Palabras clave",
|
||||||
"Choose keywords" : "Escoge palabras clave",
|
"Choose keywords" : "Escoge palabras clave",
|
||||||
|
@ -114,6 +118,9 @@ OC.L10N.register(
|
||||||
"Search recipes with this keyword" : "Buscar recetas con esta palabra clave",
|
"Search recipes with this keyword" : "Buscar recetas con esta palabra clave",
|
||||||
"Date created" : "Fecha de creación",
|
"Date created" : "Fecha de creación",
|
||||||
"Last modified" : "Última modificación",
|
"Last modified" : "Última modificación",
|
||||||
|
"Preparation time (H:MM)" : "Tiempo de preparación (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tiempo de cocinado (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Tiempo total (H:MM)",
|
||||||
"Serving Size" : "Tamaño de la porción",
|
"Serving Size" : "Tamaño de la porción",
|
||||||
"Energy" : "Energía",
|
"Energy" : "Energía",
|
||||||
"Sugar" : "Azúcar",
|
"Sugar" : "Azúcar",
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"Could not set recipe update interval to {interval}" : "No se puede ajustar el intervalo de actualización de la receta a {interval}",
|
"Could not set recipe update interval to {interval}" : "No se puede ajustar el intervalo de actualización de la receta a {interval}",
|
||||||
"Could not set recipe folder to {path}" : "No fue posible establecer {path} como ruta para la carpeta de recetas",
|
"Could not set recipe folder to {path}" : "No fue posible establecer {path} como ruta para la carpeta de recetas",
|
||||||
"Loading config failed" : "Fallo al cargar la configuración",
|
"Loading config failed" : "Fallo al cargar la configuración",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Introduce la URL o selecciona desde tu instancia de Nextcloud a la derecha",
|
||||||
"Pick a local image" : "Seleccione una imagen local",
|
"Pick a local image" : "Seleccione una imagen local",
|
||||||
"Path to your recipe image" : "Ruta a tu imagen de la receta",
|
"Path to your recipe image" : "Ruta a tu imagen de la receta",
|
||||||
"Move entry up" : "Mover entrada hacia arriba",
|
"Move entry up" : "Mover entrada hacia arriba",
|
||||||
|
@ -69,6 +70,9 @@
|
||||||
"Description" : "Descripción",
|
"Description" : "Descripción",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Imagen",
|
"Image" : "Imagen",
|
||||||
|
"Preparation time (hours:minutes)" : "Tiempo de preparación (horas:minutos)",
|
||||||
|
"Cooking time (hours:minutes)" : "Tiempo de cocinado (horas:minutos)",
|
||||||
|
"Total time (hours:minutes)" : "Tiempo total (horas:minutos)",
|
||||||
"Choose category" : "Escoge una categoría",
|
"Choose category" : "Escoge una categoría",
|
||||||
"Keywords" : "Palabras clave",
|
"Keywords" : "Palabras clave",
|
||||||
"Choose keywords" : "Escoge palabras clave",
|
"Choose keywords" : "Escoge palabras clave",
|
||||||
|
@ -112,6 +116,9 @@
|
||||||
"Search recipes with this keyword" : "Buscar recetas con esta palabra clave",
|
"Search recipes with this keyword" : "Buscar recetas con esta palabra clave",
|
||||||
"Date created" : "Fecha de creación",
|
"Date created" : "Fecha de creación",
|
||||||
"Last modified" : "Última modificación",
|
"Last modified" : "Última modificación",
|
||||||
|
"Preparation time (H:MM)" : "Tiempo de preparación (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tiempo de cocinado (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Tiempo total (H:MM)",
|
||||||
"Serving Size" : "Tamaño de la porción",
|
"Serving Size" : "Tamaño de la porción",
|
||||||
"Energy" : "Energía",
|
"Energy" : "Energía",
|
||||||
"Sugar" : "Azúcar",
|
"Sugar" : "Azúcar",
|
||||||
|
|
|
@ -71,6 +71,9 @@ OC.L10N.register(
|
||||||
"Description" : "Description",
|
"Description" : "Description",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Image",
|
"Image" : "Image",
|
||||||
|
"Preparation time (hours:minutes)" : "Durée de préparation (heures:minutes)",
|
||||||
|
"Cooking time (hours:minutes)" : "Durée de cuisson (heures:minutes)",
|
||||||
|
"Total time (hours:minutes)" : "Durée totale (heures:minutes)",
|
||||||
"Choose category" : "Sélectionnez une catégorie",
|
"Choose category" : "Sélectionnez une catégorie",
|
||||||
"Keywords" : "Mots-clefs",
|
"Keywords" : "Mots-clefs",
|
||||||
"Choose keywords" : "Sélectionner des mots-clefs",
|
"Choose keywords" : "Sélectionner des mots-clefs",
|
||||||
|
@ -114,6 +117,9 @@ OC.L10N.register(
|
||||||
"Search recipes with this keyword" : "Rechercher des recettes avec ce mot-clef",
|
"Search recipes with this keyword" : "Rechercher des recettes avec ce mot-clef",
|
||||||
"Date created" : "Date de création",
|
"Date created" : "Date de création",
|
||||||
"Last modified" : "Dernière modification",
|
"Last modified" : "Dernière modification",
|
||||||
|
"Preparation time (H:MM)" : "Durée de préparation (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Durée de cuisson (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Durée totale (H:MM)",
|
||||||
"Serving Size" : "Taille des portions",
|
"Serving Size" : "Taille des portions",
|
||||||
"Energy" : "Energie",
|
"Energy" : "Energie",
|
||||||
"Sugar" : "Sucre",
|
"Sugar" : "Sucre",
|
||||||
|
|
|
@ -69,6 +69,9 @@
|
||||||
"Description" : "Description",
|
"Description" : "Description",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Image",
|
"Image" : "Image",
|
||||||
|
"Preparation time (hours:minutes)" : "Durée de préparation (heures:minutes)",
|
||||||
|
"Cooking time (hours:minutes)" : "Durée de cuisson (heures:minutes)",
|
||||||
|
"Total time (hours:minutes)" : "Durée totale (heures:minutes)",
|
||||||
"Choose category" : "Sélectionnez une catégorie",
|
"Choose category" : "Sélectionnez une catégorie",
|
||||||
"Keywords" : "Mots-clefs",
|
"Keywords" : "Mots-clefs",
|
||||||
"Choose keywords" : "Sélectionner des mots-clefs",
|
"Choose keywords" : "Sélectionner des mots-clefs",
|
||||||
|
@ -112,6 +115,9 @@
|
||||||
"Search recipes with this keyword" : "Rechercher des recettes avec ce mot-clef",
|
"Search recipes with this keyword" : "Rechercher des recettes avec ce mot-clef",
|
||||||
"Date created" : "Date de création",
|
"Date created" : "Date de création",
|
||||||
"Last modified" : "Dernière modification",
|
"Last modified" : "Dernière modification",
|
||||||
|
"Preparation time (H:MM)" : "Durée de préparation (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Durée de cuisson (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Durée totale (H:MM)",
|
||||||
"Serving Size" : "Taille des portions",
|
"Serving Size" : "Taille des portions",
|
||||||
"Energy" : "Energie",
|
"Energy" : "Energie",
|
||||||
"Sugar" : "Sucre",
|
"Sugar" : "Sucre",
|
||||||
|
|
|
@ -58,6 +58,7 @@ OC.L10N.register(
|
||||||
"Could not set recipe update interval to {interval}" : "Impossibile impostare l'intervallo di aggiornamento delle ricette a {interval}",
|
"Could not set recipe update interval to {interval}" : "Impossibile impostare l'intervallo di aggiornamento delle ricette a {interval}",
|
||||||
"Could not set recipe folder to {path}" : "Impossibile impostare la cartella delle ricette a {path}",
|
"Could not set recipe folder to {path}" : "Impossibile impostare la cartella delle ricette a {path}",
|
||||||
"Loading config failed" : "Caricamento della configurazione non riuscito",
|
"Loading config failed" : "Caricamento della configurazione non riuscito",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Inserisci l'URL o seleziona dalla tua istanza Nextcloud sulla destra",
|
||||||
"Pick a local image" : "Scegli un'immagine locale",
|
"Pick a local image" : "Scegli un'immagine locale",
|
||||||
"Path to your recipe image" : "Percorso all'immagine della ricetta",
|
"Path to your recipe image" : "Percorso all'immagine della ricetta",
|
||||||
"Move entry up" : "Sposta voce su",
|
"Move entry up" : "Sposta voce su",
|
||||||
|
@ -71,6 +72,9 @@ OC.L10N.register(
|
||||||
"Description" : "Descrizione",
|
"Description" : "Descrizione",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Immagine",
|
"Image" : "Immagine",
|
||||||
|
"Preparation time (hours:minutes)" : "Tempo di preparazione (ore:minuti):",
|
||||||
|
"Cooking time (hours:minutes)" : "Tempo di cottura (ore:minuti):",
|
||||||
|
"Total time (hours:minutes)" : "Tempo totale (ore:minuti):",
|
||||||
"Choose category" : "Scegli la categoria",
|
"Choose category" : "Scegli la categoria",
|
||||||
"Keywords" : "Parole chiave",
|
"Keywords" : "Parole chiave",
|
||||||
"Choose keywords" : "Scegli le parole chiave",
|
"Choose keywords" : "Scegli le parole chiave",
|
||||||
|
@ -114,6 +118,9 @@ OC.L10N.register(
|
||||||
"Search recipes with this keyword" : "Cerca ricette con questa parola chiave",
|
"Search recipes with this keyword" : "Cerca ricette con questa parola chiave",
|
||||||
"Date created" : "Data di creazione",
|
"Date created" : "Data di creazione",
|
||||||
"Last modified" : "Ultima modifica",
|
"Last modified" : "Ultima modifica",
|
||||||
|
"Preparation time (H:MM)" : "Tempo di preparazione (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tempo di cottura (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Tempo totale (H:MM)",
|
||||||
"Serving Size" : "Dimensioni della porzione",
|
"Serving Size" : "Dimensioni della porzione",
|
||||||
"Energy" : "Energia",
|
"Energy" : "Energia",
|
||||||
"Sugar" : "Zuccheri",
|
"Sugar" : "Zuccheri",
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"Could not set recipe update interval to {interval}" : "Impossibile impostare l'intervallo di aggiornamento delle ricette a {interval}",
|
"Could not set recipe update interval to {interval}" : "Impossibile impostare l'intervallo di aggiornamento delle ricette a {interval}",
|
||||||
"Could not set recipe folder to {path}" : "Impossibile impostare la cartella delle ricette a {path}",
|
"Could not set recipe folder to {path}" : "Impossibile impostare la cartella delle ricette a {path}",
|
||||||
"Loading config failed" : "Caricamento della configurazione non riuscito",
|
"Loading config failed" : "Caricamento della configurazione non riuscito",
|
||||||
|
"Enter URL or select from your Nextcloud instance on the right" : "Inserisci l'URL o seleziona dalla tua istanza Nextcloud sulla destra",
|
||||||
"Pick a local image" : "Scegli un'immagine locale",
|
"Pick a local image" : "Scegli un'immagine locale",
|
||||||
"Path to your recipe image" : "Percorso all'immagine della ricetta",
|
"Path to your recipe image" : "Percorso all'immagine della ricetta",
|
||||||
"Move entry up" : "Sposta voce su",
|
"Move entry up" : "Sposta voce su",
|
||||||
|
@ -69,6 +70,9 @@
|
||||||
"Description" : "Descrizione",
|
"Description" : "Descrizione",
|
||||||
"URL" : "URL",
|
"URL" : "URL",
|
||||||
"Image" : "Immagine",
|
"Image" : "Immagine",
|
||||||
|
"Preparation time (hours:minutes)" : "Tempo di preparazione (ore:minuti):",
|
||||||
|
"Cooking time (hours:minutes)" : "Tempo di cottura (ore:minuti):",
|
||||||
|
"Total time (hours:minutes)" : "Tempo totale (ore:minuti):",
|
||||||
"Choose category" : "Scegli la categoria",
|
"Choose category" : "Scegli la categoria",
|
||||||
"Keywords" : "Parole chiave",
|
"Keywords" : "Parole chiave",
|
||||||
"Choose keywords" : "Scegli le parole chiave",
|
"Choose keywords" : "Scegli le parole chiave",
|
||||||
|
@ -112,6 +116,9 @@
|
||||||
"Search recipes with this keyword" : "Cerca ricette con questa parola chiave",
|
"Search recipes with this keyword" : "Cerca ricette con questa parola chiave",
|
||||||
"Date created" : "Data di creazione",
|
"Date created" : "Data di creazione",
|
||||||
"Last modified" : "Ultima modifica",
|
"Last modified" : "Ultima modifica",
|
||||||
|
"Preparation time (H:MM)" : "Tempo di preparazione (H:MM)",
|
||||||
|
"Cooking time (H:MM)" : "Tempo di cottura (H:MM)",
|
||||||
|
"Total time (H:MM)" : "Tempo totale (H:MM)",
|
||||||
"Serving Size" : "Dimensioni della porzione",
|
"Serving Size" : "Dimensioni della porzione",
|
||||||
"Energy" : "Energia",
|
"Energy" : "Energia",
|
||||||
"Sugar" : "Zuccheri",
|
"Sugar" : "Zuccheri",
|
||||||
|
|
|
@ -72,7 +72,7 @@ class MainController extends Controller {
|
||||||
*/
|
*/
|
||||||
public function getApiVersion(): DataResponse {
|
public function getApiVersion(): DataResponse {
|
||||||
$response = [
|
$response = [
|
||||||
'cookbook_version' => [0, 9, 9], /* VERSION_TAG do not change this line manually */
|
'cookbook_version' => [0, 9, 10], /* VERSION_TAG do not change this line manually */
|
||||||
'api_version' => [
|
'api_version' => [
|
||||||
'epoch' => 0,
|
'epoch' => 0,
|
||||||
'major' => 0,
|
'major' => 0,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nextcloud-cookbook",
|
"name": "nextcloud-cookbook",
|
||||||
"version": "0.9.9",
|
"version": "0.9.10",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
"@nextcloud/axios": "^1.6.0",
|
"@nextcloud/axios": "^1.6.0",
|
||||||
"@nextcloud/moment": "^1.1.1",
|
"@nextcloud/moment": "^1.1.1",
|
||||||
"@nextcloud/router": "^2.0.0",
|
"@nextcloud/router": "^2.0.0",
|
||||||
"@nextcloud/vue": "^4.0.2",
|
"@nextcloud/vue": "^5.1.0",
|
||||||
"linkifyjs": "^3.0.1",
|
"linkifyjs": "^3.0.1",
|
||||||
"lozad": "^1.16.0",
|
"lozad": "^1.16.0",
|
||||||
"node-sass": "^7.0.0",
|
"node-sass": "^7.0.0",
|
||||||
|
|
|
@ -344,8 +344,19 @@ export default {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.wrapper {
|
.wrapper {
|
||||||
|
/* Sticky is better than fixed because fixed takes the element out of flow,
|
||||||
|
which breaks the height, putting elements underneath */
|
||||||
|
position: sticky;
|
||||||
|
|
||||||
|
/* This is competing with the recipe instructions which have z-index: 1 */
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
/* The height of the nextcloud header */
|
||||||
|
top: var(--header-height);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
background-color: var(--color-main-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
ref="list-field"
|
ref="list-field"
|
||||||
v-model="buffer[idx]"
|
v-model="buffer[idx]"
|
||||||
type="text"
|
type="text"
|
||||||
@keyup="keyPressed"
|
@keydown="keyDown"
|
||||||
@input="handleInput"
|
@input="handleInput"
|
||||||
@paste="handlePaste"
|
@paste="handlePaste"
|
||||||
/>
|
/>
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
v-else-if="fieldType === 'textarea'"
|
v-else-if="fieldType === 'textarea'"
|
||||||
ref="list-field"
|
ref="list-field"
|
||||||
v-model="buffer[idx]"
|
v-model="buffer[idx]"
|
||||||
@keyup="keyPressed"
|
@keydown="keyDown"
|
||||||
@input="handleInput"
|
@input="handleInput"
|
||||||
@paste="handlePaste"
|
@paste="handlePaste"
|
||||||
></textarea>
|
></textarea>
|
||||||
|
@ -58,6 +58,26 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
const linesMatchAtPosition = (lines, i) =>
|
||||||
|
lines.every((line) => line[i] === lines[0][i])
|
||||||
|
const findCommonPrefix = (lines) => {
|
||||||
|
// Find the substring common to the array of strings
|
||||||
|
// Inspired from https://stackoverflow.com/questions/68702774/longest-common-prefix-in-javascript
|
||||||
|
|
||||||
|
// Check border cases size 1 array and empty first word)
|
||||||
|
if (!lines[0] || lines.length === 1) return lines[0] || ""
|
||||||
|
|
||||||
|
// Loop up index until the characters do not match
|
||||||
|
for (let i = 0; ; i++) {
|
||||||
|
// If first line has fewer than i characters
|
||||||
|
// or the character of each line at position i is not identical
|
||||||
|
if (!lines[0][i] || !linesMatchAtPosition(lines, i)) {
|
||||||
|
// Then the desired prefix is the substring from the beginning to i
|
||||||
|
return lines[0].substr(0, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EditInputGroup",
|
name: "EditInputGroup",
|
||||||
props: {
|
props: {
|
||||||
|
@ -95,8 +115,6 @@ export default {
|
||||||
return {
|
return {
|
||||||
// helper variables
|
// helper variables
|
||||||
buffer: this.value.slice(),
|
buffer: this.value.slice(),
|
||||||
contentPasted: false,
|
|
||||||
singleLinePasted: false,
|
|
||||||
lastFocusedFieldIndex: null,
|
lastFocusedFieldIndex: null,
|
||||||
lastCursorPosition: -1,
|
lastCursorPosition: -1,
|
||||||
ignoreNextKeyUp: false,
|
ignoreNextKeyUp: false,
|
||||||
|
@ -142,41 +160,43 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Handle typing in input or field or textarea
|
* Handle typing in input or field or textarea
|
||||||
*/
|
*/
|
||||||
handleInput() {
|
handleInput(e) {
|
||||||
// wait a tick to check if content was typed or pasted
|
// Exit early if input was pasted. Let `handlePaste` handle this.
|
||||||
this.$nextTick(function handlePastedOrTyped() {
|
// References:
|
||||||
if (this.contentPasted) {
|
// https://developer.mozilla.org/en-US/docs/Web/API/InputEvent/inputType
|
||||||
this.contentPasted = false
|
// https://rawgit.com/w3c/input-events/v1/index.html#interface-InputEvent-Attributes
|
||||||
|
if (
|
||||||
if (this.singleLinePasted) {
|
e.inputType === "insertFromPaste" ||
|
||||||
this.$emit("input", this.buffer)
|
e.inputType === "insertFromPasteAsQuotation"
|
||||||
}
|
) {
|
||||||
|
return
|
||||||
return
|
}
|
||||||
}
|
this.$emit("input", this.buffer)
|
||||||
this.$emit("input", this.buffer)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Handle paste in input field or textarea
|
* Handle paste in input field or textarea
|
||||||
*/
|
*/
|
||||||
handlePaste(e) {
|
handlePaste(e) {
|
||||||
this.contentPasted = true
|
|
||||||
if (!this.createFieldsOnNewlines) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get data from clipboard to keep newline characters, which are stripped
|
// get data from clipboard to keep newline characters, which are stripped
|
||||||
// from the data pasted in the input field (e.target.value)
|
// from the data pasted in the input field (e.target.value)
|
||||||
const clipboardData = e.clipboardData || window.clipboardData
|
const clipboardData = e.clipboardData || window.clipboardData
|
||||||
const pastedData = clipboardData.getData("Text")
|
const pastedData = clipboardData.getData("Text")
|
||||||
const inputLinesArray = pastedData.split(/\r\n|\r|\n/g)
|
const inputLinesArray = pastedData
|
||||||
|
.split(/\r\n|\r|\n/g)
|
||||||
|
// Remove empty lines
|
||||||
|
.filter((line) => line.trim() !== "")
|
||||||
|
|
||||||
|
// If only a single line pasted, emit that line and exit
|
||||||
|
// Treat it as if that single line was typed
|
||||||
if (inputLinesArray.length === 1) {
|
if (inputLinesArray.length === 1) {
|
||||||
this.singleLinePasted = true
|
this.$emit("input", this.buffer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// From here on, multiple lines pasted
|
||||||
|
if (!this.createFieldsOnNewlines) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.singleLinePasted = false
|
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
@ -187,12 +207,25 @@ export default {
|
||||||
$li
|
$li
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remove empty lines
|
// Remove the common prefix from each line of the pasted text
|
||||||
for (let i = inputLinesArray.length - 1; i >= 0; --i) {
|
// For example, if the pasted text uses - for a bullet list
|
||||||
if (inputLinesArray[i].trim() === "") {
|
const prefix = findCommonPrefix(inputLinesArray)
|
||||||
inputLinesArray.splice(i, 1)
|
|
||||||
}
|
// Inspired from https://stackoverflow.com/a/25575009
|
||||||
|
// Ensure that we are only removing common punctuation
|
||||||
|
// For example, if many lines start with the same word, keep that
|
||||||
|
// This is more robust than filtering our [a-zA-Z] in the prefix
|
||||||
|
// as it should work for any alphabet
|
||||||
|
const re =
|
||||||
|
/[^\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-./:;<=>?@[\]^_`{|}~]/g
|
||||||
|
const prefixLength = re.test(prefix)
|
||||||
|
? prefix.search(re)
|
||||||
|
: prefix.length
|
||||||
|
|
||||||
|
for (let i = 0; i < inputLinesArray.length; ++i) {
|
||||||
|
inputLinesArray[i] = inputLinesArray[i].slice(prefixLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < inputLinesArray.length; ++i) {
|
for (let i = 0; i < inputLinesArray.length; ++i) {
|
||||||
this.addNewEntry(
|
this.addNewEntry(
|
||||||
$insertedIndex + i + 1,
|
$insertedIndex + i + 1,
|
||||||
|
@ -210,13 +243,12 @@ export default {
|
||||||
indexToFocus -= 1
|
indexToFocus -= 1
|
||||||
}
|
}
|
||||||
this.$refs["list-field"][indexToFocus].focus()
|
this.$refs["list-field"][indexToFocus].focus()
|
||||||
this.contentPasted = false
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Catches enter and key down presses and either adds a new row or focuses the one below
|
* Catches enter and key down presses and either adds a new row or focuses the one below
|
||||||
*/
|
*/
|
||||||
keyPressed(e) {
|
keyDown(e) {
|
||||||
// If, e.g., enter has been pressed in the multiselect popup to select an option,
|
// If, e.g., enter has been pressed in the multiselect popup to select an option,
|
||||||
// ignore the following keyup event
|
// ignore the following keyup event
|
||||||
if (this.ignoreNextKeyUp) {
|
if (this.ignoreNextKeyUp) {
|
||||||
|
@ -225,58 +257,69 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow new lines with shift key
|
// Allow new lines with shift key
|
||||||
if ((e.keyCode === 13 || e.keyCode === 10) && e.shiftKey) {
|
if (e.key === "Enter" && e.shiftKey) {
|
||||||
// Do nothing here, user wants a line break
|
// Do nothing here, user wants a line break
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using keyup for trigger will prevent repeat triggering if key is held down
|
// Repeat events should be ignored
|
||||||
|
if (e.repeat) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only do anything for enter or # keys
|
||||||
if (
|
if (
|
||||||
e.keyCode === 13 ||
|
e.key !== "Enter" &&
|
||||||
e.keyCode === 10 ||
|
!(this.referencePopupEnabled && e.key === "#")
|
||||||
(this.referencePopupEnabled && e.key === "#")
|
|
||||||
) {
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the index of the pressed list item
|
||||||
|
const $li = e.currentTarget.closest("li")
|
||||||
|
const $ul = $li.closest("ul")
|
||||||
|
const $pressedLiIndex = Array.prototype.indexOf.call(
|
||||||
|
$ul.childNodes,
|
||||||
|
$li
|
||||||
|
)
|
||||||
|
|
||||||
|
if (e.key === "Enter") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const $li = e.currentTarget.closest("li")
|
|
||||||
const $ul = $li.closest("ul")
|
|
||||||
const $pressedLiIndex = Array.prototype.indexOf.call(
|
|
||||||
$ul.childNodes,
|
|
||||||
$li
|
|
||||||
)
|
|
||||||
|
|
||||||
if (e.keyCode === 13 || e.keyCode === 10) {
|
if ($pressedLiIndex >= this.$refs["list-field"].length - 1) {
|
||||||
if (
|
this.addNewEntry()
|
||||||
$pressedLiIndex >=
|
} else {
|
||||||
this.$refs["list-field"].length - 1
|
// Focus the next input or textarea
|
||||||
) {
|
// We have to check for both, as inputs are used for
|
||||||
this.addNewEntry()
|
// ingredients and textareas are used for instructions
|
||||||
} else {
|
$ul.children[$pressedLiIndex + 1]
|
||||||
$ul.children[$pressedLiIndex + 1]
|
.querySelector("input, textarea")
|
||||||
.getElementsByTagName("input")[0]
|
.focus()
|
||||||
.focus()
|
}
|
||||||
}
|
}
|
||||||
} else if (this.referencePopupEnabled && e.key === "#") {
|
if (this.referencePopupEnabled && e.key === "#") {
|
||||||
|
const elm = this.$refs["list-field"][$pressedLiIndex]
|
||||||
|
// Check if the letter before the hash
|
||||||
|
// This is a keydown event listener, so the `#` does not
|
||||||
|
// exist in the input yet
|
||||||
|
// `cursorPos` will be the index in the textfield before the #
|
||||||
|
// was pressed
|
||||||
|
const cursorPos = elm.selectionStart
|
||||||
|
const content = elm.value
|
||||||
|
|
||||||
|
// Show the popup only if the # was inserted at the very
|
||||||
|
// beggining of the input or after any whitespace character
|
||||||
|
if (
|
||||||
|
cursorPos === 0 ||
|
||||||
|
/\s/.test(content.charAt(cursorPos - 1))
|
||||||
|
) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const elm = this.$refs["list-field"][$pressedLiIndex]
|
// Show dialog to select recipe
|
||||||
// Check if the letter before the hash
|
this.$parent.$emit("showRecipeReferencesPopup", {
|
||||||
const cursorPos = elm.selectionStart
|
context: this,
|
||||||
const content = elm.value
|
})
|
||||||
const prevChar =
|
this.lastFocusedFieldIndex = $pressedLiIndex
|
||||||
cursorPos > 1 ? content.charAt(cursorPos - 2) : ""
|
this.lastCursorPosition = cursorPos
|
||||||
|
|
||||||
if (
|
|
||||||
cursorPos === 1 ||
|
|
||||||
prevChar === " " ||
|
|
||||||
prevChar === "\n" ||
|
|
||||||
prevChar === "\r"
|
|
||||||
) {
|
|
||||||
// Show dialog to select recipe
|
|
||||||
this.$parent.$emit("showRecipeReferencesPopup", {
|
|
||||||
context: this,
|
|
||||||
})
|
|
||||||
this.lastFocusedFieldIndex = $pressedLiIndex
|
|
||||||
this.lastCursorPosition = cursorPos
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -667,7 +667,14 @@ export default {
|
||||||
paddedTime: this.recipe.totalTime,
|
paddedTime: this.recipe.totalTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedKeywords = this.recipe.keywords.split(",")
|
this.selectedKeywords = this.recipe.keywords
|
||||||
|
.split(",")
|
||||||
|
.map((kw) => kw.trim())
|
||||||
|
// Remove any empty keywords
|
||||||
|
// If the response from the server is just an empty
|
||||||
|
// string, split will create an array of a single empty
|
||||||
|
// string
|
||||||
|
.filter((kw) => kw !== "")
|
||||||
|
|
||||||
// fallback if fetching all keywords fails
|
// fallback if fetching all keywords fails
|
||||||
this.selectedKeywords.forEach((kw) => {
|
this.selectedKeywords.forEach((kw) => {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче