diff --git a/formwork/src/Pages/Page.php b/formwork/src/Pages/Page.php index 98c4a8c76..570ff929a 100644 --- a/formwork/src/Pages/Page.php +++ b/formwork/src/Pages/Page.php @@ -108,11 +108,6 @@ class Page extends Model implements Stringable #[ReadonlyModelProperty] protected ?string $route = null; - /** - * Page canonical route - */ - protected ?string $canonicalRoute = null; - /** * Page slug */ @@ -167,11 +162,6 @@ class Page extends Model implements Stringable */ protected Site $site; - /** - * Page icon - */ - protected string $icon; - /** * @param array $data */ @@ -315,9 +305,9 @@ public function route(): ?string */ public function canonicalRoute(): ?string { - return $this->canonicalRoute ?? ($this->canonicalRoute = empty($this->data['canonicalRoute']) + return empty($this->data['canonicalRoute']) ? null - : Path::normalize($this->data['canonicalRoute'])); + : Path::normalize($this->data['canonicalRoute']); } /** @@ -379,6 +369,22 @@ public function metadata(): MetadataCollection return $this->metadata = $metadata; } + /** + * Set page metadata + * + * @param array|MetadataCollection $metadata + */ + public function setMetadata(MetadataCollection|array $metadata): void + { + if ($metadata instanceof MetadataCollection) { + $this->metadata = $metadata; + $this->data['metadata'] = $metadata->toArray(); + } else { + unset($this->metadata); + $this->data['metadata'] = $metadata; + } + } + /** * Get page files */ @@ -434,6 +440,24 @@ public function responseStatus(): ResponseStatus return $this->responseStatus; } + /** + * Set page HTTP response status + */ + public function setResponseStatus(ResponseStatus|int|null $responseStatus): void + { + if ($responseStatus === null) { + unset($this->responseStatus, $this->data['responseStatus']); + return; + } + + if (is_int($responseStatus)) { + $responseStatus = ResponseStatus::fromCode($responseStatus); + } + + $this->responseStatus = $responseStatus; + $this->data['responseStatus'] = $responseStatus->code(); + } + /** * Set page language * @@ -641,6 +665,14 @@ public function isDeletable(): bool return !($this->hasChildren() || $this->isIndexPage() || $this->isErrorPage()); } + /** + * Return whether the page is duplicable + */ + public function isDuplicable(): bool + { + return !$this->hasChildren(); + } + /** * Return whether the slug is editable */ @@ -714,7 +746,7 @@ public function contentRelativePath(): ?string */ public function icon(): string { - return $this->icon ??= $this->data['icon'] ?? $this->scheme()->options()->get('icon', 'page'); + return $this->data['icon'] ?? $this->scheme()->options()->get('icon', 'page'); } /** @@ -726,6 +758,49 @@ public function icon(): string * @throws InvalidValueException If the language is invalid */ public function save(?string $language = null): void + { + $this->write($language, copy: false); + } + + /** + * Duplicate the page + * + * @param array $with Data to override in the duplicated page + * @param string|null $language Language code to duplicate the page in + * + * @throws UnexpectedValueException If parent or parent content path is missing + * @throws InvalidValueException If the language is invalid + */ + public function duplicate(array $with = [], ?string $language = null): Page + { + if (!$this->isDuplicable()) { + throw new RuntimeException('Cannot duplicate a non-duplicable page'); + } + + $duplicatePage = clone $this; + + $duplicatePage->setMultiple([ + 'path' => null, + 'canonicalRoute' => null, + 'slug' => $this->slug() . '-copy', + ...$with, + ]); + + $duplicatePage->write($language, copy: true); + + return $duplicatePage; + } + + /** + * Write page contents and move or copy files if needed + * + * @param string|null $language Language code to save the page in + * @param bool $copy Whether to copy the page instead of moving it + * + * @throws UnexpectedValueException If parent or parent content path is missing + * @throws InvalidValueException If the language is invalid + */ + protected function write(?string $language = null, bool $copy = false): void { if ($this->parent() === null) { throw new UnexpectedValueException('Unexpected missing parent'); @@ -765,6 +840,13 @@ public function save(?string $language = null): void Arr::set($frontmatter, $field->name(), $field->value()); } + // Remove default values without a corresponding field from frontmatter + foreach ($defaults as $key => $defaultValue) { + if (Arr::has($frontmatter, $key) && !$fieldCollection->has($key) && $this->get($key) === $defaultValue) { + Arr::remove($frontmatter, $key); + } + } + $content = str_replace("\r\n", "\n", $this->data['content']); $contentTemplate = $this->contentFile() !== null @@ -803,7 +885,11 @@ public function save(?string $language = null): void FileSystem::createDirectory($contentPath, recursive: true); } if ($this->contentPath() !== null) { - FileSystem::moveDirectory($this->contentPath(), $contentPath, overwrite: FileSystem::isEmptyDirectory($contentPath, assertExists: false)); + if ($copy) { + FileSystem::copyDirectory($this->contentPath(), $contentPath, overwrite: FileSystem::isEmptyDirectory($contentPath, assertExists: false)); + } else { + FileSystem::moveDirectory($this->contentPath(), $contentPath, overwrite: FileSystem::isEmptyDirectory($contentPath, assertExists: false)); + } } } elseif ($contentTemplate !== $this->template->name() && $this->contentFile() !== null) { FileSystem::delete($this->contentFile()->path()); @@ -931,8 +1017,16 @@ protected function loadFiles(): void * * @throws UnexpectedValueException If site path is missing */ - protected function setPath(string $path): void + protected function setPath(?string $path): void { + if ($path === null) { + $this->path = null; + $this->relativePath = null; + $this->route = null; + $this->slug = null; + return; + } + $this->path = FileSystem::normalizePath($path . '/'); if ($this->site()->contentPath() === null) { diff --git a/formwork/src/Panel/Controllers/PagesController.php b/formwork/src/Panel/Controllers/PagesController.php index a948ca83e..f2233eff8 100644 --- a/formwork/src/Panel/Controllers/PagesController.php +++ b/formwork/src/Panel/Controllers/PagesController.php @@ -120,6 +120,53 @@ public function create(PageFactory $pageFactory): Response return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => trim($page->route(), '/')])); } + /** + * Pages@duplicate action + */ + public function duplicate(RouteParams $routeParams): Response + { + if (!$this->hasPermission('panel.pages.duplicate')) { + return $this->forward(ErrorsController::class, 'forbidden'); + } + + $requestData = $this->request->input(); + + $fields = $this->modal('duplicatePage')->fields(); + + $page = $this->site->findPage($routeParams->get('page')); + + if ($page === null) { + $this->panel->notify($this->translate('panel.pages.page.cannotDuplicate.pageNotFound'), 'error'); + return $this->redirectToReferer(default: $this->generateRoute('panel.pages'), base: $this->panel->panelRoot()); + } + + if (!$page->isDuplicable()) { + $this->panel->notify($this->translate('panel.pages.page.cannotDuplicate.notDuplicable'), 'error'); + return $this->redirectToReferer(default: $this->generateRoute('panel.pages'), base: $this->panel->panelRoot()); + } + + try { + $fields->setValues($requestData)->validate(); + + // Let's duplicate the page + $duplicatePage = $this->duplicatePage($page, $fields); + $this->panel->notify($this->translate('panel.pages.page.created'), 'success'); + } catch (TranslatedException $e) { + $this->panel->notify($this->translate($e->getLanguageString()), 'error'); + return $this->redirectToReferer(default: $this->generateRoute('panel.pages'), base: $this->panel->panelRoot()); + } catch (InvalidValueException $e) { + $identifier = $e->getIdentifier() ?? 'varMissing'; + $this->panel->notify($this->translate('panel.pages.page.cannotCreate.' . $identifier), 'error'); + return $this->redirectToReferer(default: $this->generateRoute('panel.pages'), base: $this->panel->panelRoot()); + } + + if ($duplicatePage->route() === null) { + throw new UnexpectedValueException('Unexpected missing page route'); + } + + return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => trim($duplicatePage->route(), '/')])); + } + /** * Pages@edit action */ @@ -475,6 +522,24 @@ private function createPage(FieldCollection $fieldCollection, PageFactory $pageF return $page; } + /** + * Duplicate a page + */ + private function duplicatePage(Page $page, FieldCollection $fieldCollection): Page + { + $data = [...$fieldCollection->everyItem()->value()->toArray(), 'published' => false]; + + $duplicatePage = $page->duplicate($data); + + if ($duplicatePage->contentPath()) { + $contentHistory = new ContentHistory($duplicatePage->contentPath()); + $contentHistory->update(ContentHistoryEvent::Created, $this->panel->user()->username(), time()); + $contentHistory->save(); + } + + return $duplicatePage; + } + /** * Update a page */ diff --git a/panel/assets/icons/svg/duplicate.svg b/panel/assets/icons/svg/duplicate.svg new file mode 100644 index 000000000..695e962ab --- /dev/null +++ b/panel/assets/icons/svg/duplicate.svg @@ -0,0 +1 @@ + diff --git a/panel/config/routes/routes.php b/panel/config/routes/routes.php index 4a1bdc00c..7b390ec2d 100644 --- a/panel/config/routes/routes.php +++ b/panel/config/routes/routes.php @@ -91,6 +91,12 @@ 'types' => ['XHR'], ], + 'panel.pages.duplicate' => [ + 'path' => '/pages/{page:all}/duplicate/', + 'action' => 'Formwork\Panel\Controllers\PagesController@duplicate', + 'methods' => ['POST'], + ], + 'panel.pages.delete' => [ 'path' => '/pages/{page:all}/delete/', 'action' => 'Formwork\Panel\Controllers\PagesController@delete', diff --git a/panel/modals/duplicatePage.yaml b/panel/modals/duplicatePage.yaml new file mode 100644 index 000000000..3514be0bd --- /dev/null +++ b/panel/modals/duplicatePage.yaml @@ -0,0 +1,30 @@ +title: '{{panel.pages.duplicatePage}}' + +action: /pages/duplicate/ + +fields: + title: + type: text + label: '{{page.title}}' + required: true + + slug: + type: slug + label: '{{page.slug}}' + suggestion: '{{page.slug.suggestion}}' + required: true + pattern: '[a-z0-9\-]+' + source: title + +buttons: + dismiss: + action: dismiss + icon: times-circle + label: '{{panel.modal.action.cancel}}' + variant: secondary + + submit: + action: submit + icon: check-circle + label: '{{panel.modal.action.continue}}' + align: right diff --git a/panel/src/ts/components/views/pages.ts b/panel/src/ts/components/views/pages.ts index 477515e1c..314ef22a0 100644 --- a/panel/src/ts/components/views/pages.ts +++ b/panel/src/ts/components/views/pages.ts @@ -1,5 +1,5 @@ import { $, $$ } from "../../utils/selectors"; -import { escapeRegExp, makeDiacriticsRegExp } from "../../utils/validation"; +import { escapeRegExp, makeDiacriticsRegExp, makeSlug } from "../../utils/validation"; import { app } from "../../app"; import { debounce } from "../../utils/events"; import { Form } from "../form"; @@ -19,6 +19,7 @@ export class Pages { const newPageModal = app.modals["newPageModal"]; const deletePageItemModal = app.modals["deletePageItemModal"]; + const duplicatePageModal = app.modals["duplicatePageModal"]; $$(".pages-tree").forEach((element) => { if (element.dataset.orderableChildren === "true") { @@ -214,6 +215,22 @@ export class Pages { }); } + if (duplicatePageModal) { + duplicatePageModal.onOpen((modal, trigger) => { + if (trigger && modal.form) { + const duplicateTitle = trigger.dataset.duplicateTitle; + + if (duplicateTitle) { + const title = $('[name="duplicatePageModal[title]"]', modal.form.element) as HTMLInputElement; + const slug = $('[name="duplicatePageModal[slug]"]', modal.form.element) as HTMLInputElement; + title.value = duplicateTitle; + slug.value = makeSlug(duplicateTitle); + title.setSelectionRange(0, title.value.length); + } + } + }); + } + if (commandPreview) { const editorForm = app.forms["page-editor-form"]; diff --git a/panel/translations/de.yaml b/panel/translations/de.yaml index 2c0539deb..e6c143ea6 100644 --- a/panel/translations/de.yaml +++ b/panel/translations/de.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Datei löschen panel.pages.deleteFile.prompt: Möchten Sie diese Datei wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden. panel.pages.deletePage: Seite löschen panel.pages.deletePage.prompt: Möchten Sie diese Seite wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden. +panel.pages.duplicatePage: Seite duplizieren +panel.pages.duplicatePage.title: '%s Kopie' panel.pages.edit: Seite bearbeiten panel.pages.editPage: Seite bearbeiten %s panel.pages.history.event.created: Seite erstellt von %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Seite kann nicht erstellt werden, eine panel.pages.page.cannotDelete.invalidLanguage: "Seite kann nicht gelöscht werden, ungültige Sprache: %s" panel.pages.page.cannotDelete.notDeletable: Seite kann nicht gelöscht werden, die Seite ist nicht löschbar panel.pages.page.cannotDelete.pageNotFound: Seite kann nicht gelöscht werden, Seite nicht gefunden +panel.pages.page.cannotDuplicate.notDuplicable: Seite kann nicht dupliziert werden, sie ist nicht duplizierbar +panel.pages.page.cannotDuplicate.pageNotFound: Seite kann nicht dupliziert werden, nicht gefunden panel.pages.page.cannotEdit.alreadyExists: Seite kann nicht bearbeitet werden, eine Seite mit demselben URI existiert bereits panel.pages.page.cannotEdit.indexOrErrorPageSlug: Slug von Index- und Fehlerseiten kann nicht bearbeitet werden panel.pages.page.cannotEdit.invalidLanguage: "Seite kann nicht bearbeitet werden, ungültige Sprache: %s" diff --git a/panel/translations/en.yaml b/panel/translations/en.yaml index d899e3ca3..804ce4a98 100644 --- a/panel/translations/en.yaml +++ b/panel/translations/en.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Delete file panel.pages.deleteFile.prompt: Are you sure you want to delete this file? This action can’t be undone. panel.pages.deletePage: Delete page panel.pages.deletePage.prompt: Are you sure you want to delete this page? This action can’t be undone. +panel.pages.duplicatePage: Duplicate page +panel.pages.duplicatePage.title: '%s copy' panel.pages.edit: Edit page panel.pages.editPage: Edit page %s panel.pages.history.event.created: Page created by %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Cannot create page, missing a variable panel.pages.page.cannotDelete.invalidLanguage: 'Cannot delete page, invalid language: %s' panel.pages.page.cannotDelete.notDeletable: Cannot delete page, the page is not deletable panel.pages.page.cannotDelete.pageNotFound: Cannot delete page, page not found +panel.pages.page.cannotDuplicate.notDuplicable: Cannot duplicate page, the page is not duplicable +panel.pages.page.cannotDuplicate.pageNotFound: Cannot duplicate page, page not found panel.pages.page.cannotEdit.alreadyExists: Cannot edit page, a page with the same uri already exists panel.pages.page.cannotEdit.indexOrErrorPageSlug: Cannot edit page slug of index and error pages panel.pages.page.cannotEdit.invalidLanguage: 'Cannot edit page, invalid language: %s' diff --git a/panel/translations/es.yaml b/panel/translations/es.yaml index cf0a5a35f..5d67e6422 100644 --- a/panel/translations/es.yaml +++ b/panel/translations/es.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Borrar archivo panel.pages.deleteFile.prompt: ¿Estás seguro de que quieres borrar este archivo? Esta acción no se puede deshacer. panel.pages.deletePage: Borrar página panel.pages.deletePage.prompt: ¿Estás seguro de que quieres borrar esta página? Esta acción no se puede deshacer. +panel.pages.duplicatePage: Duplicar página +panel.pages.duplicatePage.title: '%s copia' panel.pages.edit: Editar página panel.pages.editPage: Editar página %s panel.pages.history.event.created: Página creada por %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: No se puede crear la página, falta un panel.pages.page.cannotDelete.invalidLanguage: 'No se puede borrar la página, idioma no válido: %s' panel.pages.page.cannotDelete.notDeletable: No se puede borrar la página, la página no es eliminable panel.pages.page.cannotDelete.pageNotFound: No se puede borrar la página, página no encontrada +panel.pages.page.cannotDuplicate.notDuplicable: No se puede duplicar la página, no es duplicable +panel.pages.page.cannotDuplicate.pageNotFound: No se puede duplicar la página, no encontrada panel.pages.page.cannotEdit.alreadyExists: No se puede editar la página, ya existe una página con la misma URI panel.pages.page.cannotEdit.indexOrErrorPageSlug: No se puede editar el slug de la página de índice y error panel.pages.page.cannotEdit.invalidLanguage: 'No se puede editar la página, idioma no válido: %s' diff --git a/panel/translations/fr.yaml b/panel/translations/fr.yaml index 0ba40b2fe..43f3988f1 100644 --- a/panel/translations/fr.yaml +++ b/panel/translations/fr.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Supprimer le fichier panel.pages.deleteFile.prompt: ÊtesVous sûr de vouloir supprimer ce fichier ? Cette action est irréversible. panel.pages.deletePage: Supprimer la page panel.pages.deletePage.prompt: ÊtesVous sûr de vouloir supprimer cette page ? Cette action est irréversible. +panel.pages.duplicatePage: Dupliquer la page +panel.pages.duplicatePage.title: '%s copie' panel.pages.edit: Modifier la page panel.pages.editPage: Modifier la page %s panel.pages.history.event.created: Page créée par %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Impossible de créer une page, il manq panel.pages.page.cannotDelete.invalidLanguage: 'Impossible de supprimer la page, terme non défini : %s' panel.pages.page.cannotDelete.notDeletable: Impossible de supprimer la page, la page ne peut être supprimée panel.pages.page.cannotDelete.pageNotFound: Impossible de supprimer la page, page introuvable +panel.pages.page.cannotDuplicate.notDuplicable: Impossible de dupliquer la page, elle n’est pas duplicable +panel.pages.page.cannotDuplicate.pageNotFound: Impossible de dupliquer la page, introuvable panel.pages.page.cannotEdit.alreadyExists: Impossible de modifier la page, une page avec la même url existe déjà panel.pages.page.cannotEdit.indexOrErrorPageSlug: Impossible de modifier l’identifiant de la page d’acceuil et celle de la page d’erreur panel.pages.page.cannotEdit.invalidLanguage: 'Impossible de modifier la page, terme non défini : %s' diff --git a/panel/translations/it.yaml b/panel/translations/it.yaml index 4eb3cd2ce..8386ffbb7 100644 --- a/panel/translations/it.yaml +++ b/panel/translations/it.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Elimina file panel.pages.deleteFile.prompt: Si è sicuri di eliminare il file? Questa azione non può essere annullata. panel.pages.deletePage: Elimina pagina panel.pages.deletePage.prompt: Si è sicuri di eliminare la pagina? Questa azione non può essere annullata. +panel.pages.duplicatePage: Duplica pagina +panel.pages.duplicatePage.title: '%s copia' panel.pages.edit: Modifica pagina panel.pages.editPage: Modifica pagina %s panel.pages.history.event.created: Pagina creata da %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Impossibile creare la pagina, manca un panel.pages.page.cannotDelete.invalidLanguage: Impossibile eliminare la pagina, lingua %s non valida panel.pages.page.cannotDelete.notDeletable: Impossibile eliminare la pagina, la pagina non è eliminabile panel.pages.page.cannotDelete.pageNotFound: Impossibile eliminare la pagina, pagina non trovata +panel.pages.page.cannotDuplicate.notDuplicable: Impossibile duplicare la pagina, non è duplicabile +panel.pages.page.cannotDuplicate.pageNotFound: Impossibile duplicare la pagina, pagina non trovata panel.pages.page.cannotEdit.alreadyExists: Impossibile modificare la pagina, una pagina con lo stesso indirizzo esiste già panel.pages.page.cannotEdit.indexOrErrorPageSlug: Impossibile cambiare l’indirizzo della pagina iniziale o di errore panel.pages.page.cannotEdit.invalidLanguage: Impossibile modificare la pagina, lingua %s non valida diff --git a/panel/translations/nl.yaml b/panel/translations/nl.yaml index 87b04f357..8b7d926bf 100644 --- a/panel/translations/nl.yaml +++ b/panel/translations/nl.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Bestand verwijderen panel.pages.deleteFile.prompt: Weet je zeker dat je dit bestand wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt. panel.pages.deletePage: Pagina verwijderen panel.pages.deletePage.prompt: Weet je zeker dat je deze pagina wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt. +panel.pages.duplicatePage: Pagina dupliceren +panel.pages.duplicatePage.title: '%s kopie' panel.pages.edit: Pagina bewerken panel.pages.editPage: Pagina %s bewerken panel.pages.history.event.created: Pagina aangemaakt door %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Kan pagina niet aanmaken, ontbrekende panel.pages.page.cannotDelete.invalidLanguage: 'Kan pagina niet verwijderen, ongeldige taal: %s' panel.pages.page.cannotDelete.notDeletable: Kan pagina niet verwijderen, de pagina is niet verwijderbaar panel.pages.page.cannotDelete.pageNotFound: Kan pagina niet verwijderen, pagina niet gevonden +panel.pages.page.cannotDuplicate.notDuplicable: Kan pagina niet dupliceren, niet dupliceerbaar +panel.pages.page.cannotDuplicate.pageNotFound: Kan pagina niet dupliceren, niet gevonden panel.pages.page.cannotEdit.alreadyExists: Kan pagina niet bewerken, een pagina met dezelfde URI bestaat al panel.pages.page.cannotEdit.indexOrErrorPageSlug: Kan slug van index- of foutpagina niet bewerken panel.pages.page.cannotEdit.invalidLanguage: 'Kan pagina niet bewerken, ongeldige taal: %s' diff --git a/panel/translations/pl.yaml b/panel/translations/pl.yaml index 541df2768..e1f5fd064 100644 --- a/panel/translations/pl.yaml +++ b/panel/translations/pl.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Usuń plik panel.pages.deleteFile.prompt: Czy na pewno chcesz usunąć ten plik? Ta akcja jest nieodwracalna. panel.pages.deletePage: Usuń stronę panel.pages.deletePage.prompt: Czy na pewno chcesz usunąć tę stronę? Ta akcja jest nieodwracalna. +panel.pages.duplicatePage: Duplikuj stronę +panel.pages.duplicatePage.title: '%s kopia' panel.pages.edit: Edytuj stronę panel.pages.editPage: Edytuj stronę %s panel.pages.history.event.created: Strona utworzona przez %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Nie można utworzyć strony, brak zmie panel.pages.page.cannotDelete.invalidLanguage: 'Nie można usunąć strony, nieprawidłowy język: %s' panel.pages.page.cannotDelete.notDeletable: Nie można usunąć strony, strona nie jest do usunięcia panel.pages.page.cannotDelete.pageNotFound: Nie można usunąć strony, strona nie została znaleziona +panel.pages.page.cannotDuplicate.notDuplicable: Nie można zduplikować strony, nie jest duplikowalna +panel.pages.page.cannotDuplicate.pageNotFound: Nie można zduplikować strony, nie znaleziono panel.pages.page.cannotEdit.alreadyExists: Nie można edytować strony, strona o tym samym URI już istnieje panel.pages.page.cannotEdit.indexOrErrorPageSlug: Nie można edytować slug strony dla strony indeksu lub strony błędu panel.pages.page.cannotEdit.invalidLanguage: 'Nie można edytować strony, nieprawidłowy język: %s' diff --git a/panel/translations/pt.yaml b/panel/translations/pt.yaml index 061f17910..1ff6b3e66 100644 --- a/panel/translations/pt.yaml +++ b/panel/translations/pt.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Remover ficheiro panel.pages.deleteFile.prompt: Tem certeza de que deseja remover este ficheiro? Esta acção não pode ser desfeita. panel.pages.deletePage: Remover página panel.pages.deletePage.prompt: Tem certeza que deseja remover esta página? Esta ação não pode ser desfeita. +panel.pages.duplicatePage: Duplicar página +panel.pages.duplicatePage.title: '%s cópia' panel.pages.edit: Editar página panel.pages.editPage: Editar página %s panel.pages.history.event.created: Página criada por %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Não é possível criar página, falta panel.pages.page.cannotDelete.invalidLanguage: 'Não é possível excluir página, idioma inválido: %s' panel.pages.page.cannotDelete.notDeletable: Não é possível excluir a página, a página não pode ser excluída panel.pages.page.cannotDelete.pageNotFound: Não é possível excluir página, página não encontrada +panel.pages.page.cannotDuplicate.notDuplicable: Não é possível duplicar a página, não é duplicável +panel.pages.page.cannotDuplicate.pageNotFound: Não é possível duplicar a página, não encontrada panel.pages.page.cannotEdit.alreadyExists: Não é possível editar a página, já existe uma página com o mesmo uri panel.pages.page.cannotEdit.indexOrErrorPageSlug: Não é possível editar slug de página de índice e páginas de erro panel.pages.page.cannotEdit.invalidLanguage: 'Não é possível editar a página, idioma inválido: %s' diff --git a/panel/translations/ro.yaml b/panel/translations/ro.yaml index 172157fee..6aa89dc29 100644 --- a/panel/translations/ro.yaml +++ b/panel/translations/ro.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Șterge fișier panel.pages.deleteFile.prompt: Ești sigur că vrei să ștergi acest fișier? Această acțiune nu poate fi anulată. panel.pages.deletePage: Șterge pagină panel.pages.deletePage.prompt: Ești sigur că vrei să ștergi această pagină? Această acțiune nu poate fi anulată. +panel.pages.duplicatePage: Duplică pagina +panel.pages.duplicatePage.title: '%s copie' panel.pages.edit: Editează pagină panel.pages.editPage: Editează pagina %s panel.pages.history.event.created: Pagină creată de %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Nu se poate crea pagina, lipsește o v panel.pages.page.cannotDelete.invalidLanguage: 'Nu se poate șterge pagina, limbă invalidă: %s' panel.pages.page.cannotDelete.notDeletable: Nu se poate șterge pagina, pagina nu poate fi ștearsă panel.pages.page.cannotDelete.pageNotFound: Nu se poate șterge pagina, pagina nu a fost găsită +panel.pages.page.cannotDuplicate.notDuplicable: Nu se poate duplica pagina, nu este duplicabilă +panel.pages.page.cannotDuplicate.pageNotFound: Nu se poate duplica pagina, nu a fost găsită panel.pages.page.cannotEdit.alreadyExists: Nu se poate edita pagina, o pagină cu aceeași URI există deja panel.pages.page.cannotEdit.indexOrErrorPageSlug: Nu se poate edita slug-ul paginii index sau paginilor de eroare panel.pages.page.cannotEdit.invalidLanguage: 'Nu se poate edita pagina, limbă invalidă: %s' diff --git a/panel/translations/ru.yaml b/panel/translations/ru.yaml index 7980554dc..f7074e343 100644 --- a/panel/translations/ru.yaml +++ b/panel/translations/ru.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Удалить файл panel.pages.deleteFile.prompt: Вы уверены, что хотите удалить этот файл? Это действие не может быть отменено. panel.pages.deletePage: Удалить страницу panel.pages.deletePage.prompt: Вы уверены, что хотите удалить эту страницу? Это действие не может быть отменено. +panel.pages.duplicatePage: Дублировать страницу +panel.pages.duplicatePage.title: '%s копия' panel.pages.edit: Редактировать страницу panel.pages.editPage: Отредактировать страницу %s panel.pages.history.event.created: Страница создана %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Не удается создать с panel.pages.page.cannotDelete.invalidLanguage: 'Невозможно удалить страницу, недопустимый язык: %s' panel.pages.page.cannotDelete.notDeletable: Невозможно удалить страницу, страница не файл удаляемая panel.pages.page.cannotDelete.pageNotFound: Невозможно удалить страницу, страница не найдена +panel.pages.page.cannotDuplicate.notDuplicable: Невозможно дублировать страницу, она недублируемая +panel.pages.page.cannotDuplicate.pageNotFound: Невозможно дублировать страницу, не найдена panel.pages.page.cannotEdit.alreadyExists: Не могу редактировать страницу, страница с той же URI уже существует panel.pages.page.cannotEdit.indexOrErrorPageSlug: Не могу редактировать страницу слизняка индекса и ошибок страниц panel.pages.page.cannotEdit.invalidLanguage: 'Не могу редактировать страницы, недопустимый язык: %s' diff --git a/panel/translations/uk.yaml b/panel/translations/uk.yaml index 630de6968..fee348f04 100644 --- a/panel/translations/uk.yaml +++ b/panel/translations/uk.yaml @@ -197,6 +197,8 @@ panel.pages.deleteFile: Видалити файл panel.pages.deleteFile.prompt: Ви впевнені, що хочете видалити цей файл? Цю дію не можна скасувати. panel.pages.deletePage: Видалити сторінку panel.pages.deletePage.prompt: Ви впевнені, що хочете видалити цю сторінку? Цю дію не можна скасувати. +panel.pages.duplicatePage: Дублювати сторінку +panel.pages.duplicatePage.title: '%s копія' panel.pages.edit: Редагувати сторінку panel.pages.editPage: Редагувати сторінку %s panel.pages.history.event.created: Сторінка створена %s %s. @@ -219,6 +221,8 @@ panel.pages.page.cannotCreate.varMissing: Неможливо створити с panel.pages.page.cannotDelete.invalidLanguage: 'Неможливо видалити сторінку, недійсна мова: %s' panel.pages.page.cannotDelete.notDeletable: Неможливо видалити сторінку, сторінка не може бути видалена panel.pages.page.cannotDelete.pageNotFound: Неможливо видалити сторінку, сторінка не знайдена +panel.pages.page.cannotDuplicate.notDuplicable: Неможливо дублювати сторінку, вона не дублюється +panel.pages.page.cannotDuplicate.pageNotFound: Неможливо дублювати сторінку, не знайдено panel.pages.page.cannotEdit.alreadyExists: Неможливо редагувати сторінку, сторінка з таким URI вже існує panel.pages.page.cannotEdit.indexOrErrorPageSlug: Неможливо редагувати slug сторінки індексу та помилок panel.pages.page.cannotEdit.invalidLanguage: 'Неможливо редагувати сторінку, недійсна мова: %s' diff --git a/panel/views/pages/editor.php b/panel/views/pages/editor.php index 3793a7afc..680ea27ff 100644 --- a/panel/views/pages/editor.php +++ b/panel/views/pages/editor.php @@ -1,6 +1,6 @@ layout('panel') ?> -modals()->addMultiple(['changes', 'deletePage']) ?> +modals()->addMultiple(['changes', 'deletePage', 'duplicatePage']) ?>
attr(['hidden' => true, 'aria-hidden' => 'true', 'tabindex' => -1, 'data-command' => 'save', 'formaction' => $history?->isJustCreated() ? '?publish=false' : null]) ?>> @@ -28,9 +28,17 @@ href="uri('/pages/' . trim($nextPage->route(), '/') . '/edit/') ?>" title="translate('panel.pages.next') ?>" aria-label="translate('panel.pages.next') ?>">icon('chevron-right') ?> published() && $page->routable()) : ?>href="uri(includeLanguage: $currentLanguage ?: true) ?>" target="formwork-view-page-uid() ?>" title="translate('panel.pages.viewPage') ?>" aria-label="translate('panel.pages.viewPage') ?>">icon('arrow-right-up-box') ?> - user()->permissions()->has('panel.pages.delete')) : ?> - - + languages()->hasMultiple()) : ?>