diff --git a/.editorconfig b/.editorconfig index 9f62084fe..5ec095c88 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,4 @@ indent_size = 4 [*.{html,js,json}] indent_style = space -indent_size = 2 \ No newline at end of file +indent_size = 2 diff --git a/.phpactor.json b/.phpactor.json new file mode 100644 index 000000000..83d4ce3fc --- /dev/null +++ b/.phpactor.json @@ -0,0 +1,4 @@ +{ + "$schema": "/phpactor.schema.json", + "language_server_php_cs_fixer.enabled": true +} \ No newline at end of file diff --git a/actions/newtextsearch.php b/actions/newtextsearch.php index 74ac15190..0830fd7a5 100644 --- a/actions/newtextsearch.php +++ b/actions/newtextsearch.php @@ -189,13 +189,13 @@ function displayNewSearchResult($string, $phrase, $needles = []) } echo ''; - // affichage des résultats en ligne + // affichage des résultats en ligne } else { $separator = htmlspecialchars($separator, ENT_COMPAT, YW_CHARSET); echo '

' . _t('SEARCH_RESULT_OF') . ' "', htmlspecialchars($phrase, ENT_COMPAT, YW_CHARSET), '" : '; foreach ($resultat as $i => $line) { if ($this->HasAccess('read', $line['tag'])) { - echo (($i > 0) ? $separator : '') . $this->ComposeLinkToPage($line['tag']); + echo(($i > 0) ? $separator : '') . $this->ComposeLinkToPage($line['tag']); } } echo '

', "\n"; @@ -204,4 +204,4 @@ function displayNewSearchResult($string, $phrase, $needles = []) } else { echo $this->Format('---- --- **' . _t('NO_SEARCH_RESULT') . '.**'); } -} \ No newline at end of file +} diff --git a/docs/actions/lang/actionsbuilder_en.inc.php b/docs/actions/lang/actionsbuilder_en.inc.php index 391df9bc2..ec21f5a49 100644 --- a/docs/actions/lang/actionsbuilder_en.inc.php +++ b/docs/actions/lang/actionsbuilder_en.inc.php @@ -1,4 +1,5 @@ 'Ascending', 'AB_bazar_commons2_ordre_option_desc' => 'Descending', 'AB_bazar_commons2_nb_label' => 'Limitation', - 'AB_bazar_commons2_nb_hint' => "Limit the number of entries displayed", + 'AB_bazar_commons2_nb_hint' => 'Limit the number of entries displayed', 'AB_bazar_commons2_query_label' => 'Query (advanced)', 'AB_bazar_commons2_filtersresultnb_label' => 'Display the number of entries found by filters', 'AB_bazar_commons2_resetfiltersbutton_label' => 'Button to reset filters', - 'AB_bazar_commons2_showexportbuttons' => "Export button (CSV, JSON...)", + 'AB_bazar_commons2_showexportbuttons' => 'Export button (CSV, JSON...)', 'AB_bazar_commons2_title' => 'Filters', 'AB_bazar_commons2_showmapinlistview_label' => 'Present a card associated with each entry', 'AB_bazar_facettes_btn-label-add' => 'Add a filter', @@ -519,9 +520,9 @@ 'AB_bazarcarto_spider_label' => 'Spider mode', 'AB_bazarcarto_zoommolette_label' => 'Enable zooming with the scroll wheel', 'AB_bazaragenda_label' => 'Agenda', - 'AB_bazaragenda_description' => "The entries will display as events in a calendar.", + 'AB_bazaragenda_description' => 'The entries will display as events in a calendar.', 'AB_bazaragenda_nbcol_label' => 'Number of columns', - 'AB_bazaragenda_modal_label' => "Display a modal window on click", + 'AB_bazaragenda_modal_label' => 'Display a modal window on click', 'AB_bazarcard_description' => 'The entries will appear as cards', 'AB_bazarliste_label' => 'List', 'AB_bazarliste_displayfields_title_label' => 'Title area', @@ -550,11 +551,11 @@ 'AB_bazargaleriephoto_hint' => 'A field of type bf_image is required.', 'AB_bazarlistephotobox_hint' => 'A field of type bf_image is required.', 'AB_attach_no' => 'No', - 'AB_attach_size_label' => "Image size", + 'AB_attach_size_label' => 'Image size', 'AB_attach_size_small' => 'Small', 'AB_attach_size_medium' => 'Medium', 'AB_attach_size_big' => 'Large', - 'AB_attach_size_original' => "Original size", + 'AB_attach_size_original' => 'Original size', 'AB_attach_width_label' => 'Width', 'AB_attach_height_label' => 'Height', 'AB_attach_class_label' => 'Class', @@ -564,7 +565,7 @@ 'AB_buttons_action_button_pull_right' => 'Right', 'AB_attach_link_label' => 'Associated link', 'AB_attach_caption_label' => 'Text displayed on hovering', - 'AB_attach_nofullimagelink_label' => "Add a link to only display the full image", + 'AB_attach_nofullimagelink_label' => 'Enable to click on the image to display the full image', 'AB_attach_class_position_left' => 'Left', 'AB_attach_class_position_center' => 'Center', 'AB_attach_class_position_right' => 'Right', @@ -591,15 +592,15 @@ 'AB_bazarcarto_barregestion_label' => 'Entry management bar', 'AB_bazarlisteliens_label' => 'List of links', 'AB_bazarblog_description' => 'The entries will be in the form of a blog.', - 'AB_bazarblog_header_label' => "Show the header", + 'AB_bazarblog_header_label' => 'Show the header', 'AB_bazarannuaire_label' => 'Directory', - 'AB_bazarannuaire_description' => "Displays the entries as an alphabetical directory", + 'AB_bazarannuaire_description' => 'Displays the entries as an alphabetical directory', 'AB_bazarcarousel_avecpage_hint' => 'Page will be named PageDessusSlider', 'AB_bazargaleriephoto_label' => 'Picture gallery', 'AB_bazarmail_label' => 'Write to all', 'AB_attach_commons_title' => 'For images', 'AB_attach_class_position_none' => 'Text below', - 'AB_attach_class_izmir_hint' => "And much more effects available on https://ciar4n.com/izmir", + 'AB_attach_class_izmir_hint' => 'And much more effects available on https://ciar4n.com/izmir', 'AB_attach_class_izmir_border' => 'Border', 'AB_attach_class_izmir_revealup' => 'Pop-up text', 'AB_advanced_action_listusers_last_label' => 'List only the last accounts created', @@ -611,11 +612,11 @@ 'AB_advanced_action_interwikilist_label' => 'Show interwiki list', 'AB_advanced_action_mychanges_label' => 'Show me my changes', 'AB_advanced_action_textsearch_label_label' => 'label to be displayed in front of the input area', - 'AB_advanced_action_login_signupurl_label' => "Registration Url", + 'AB_advanced_action_login_signupurl_label' => 'Registration Url', 'AB_advanced_action_login_profileurl_label' => 'Profile Url', 'AB_buttons_action_button_modal_label' => 'Open link content in a popup', 'AB_buttons_action_button_modal_modalbox_hover' => 'On hovering', - 'AB_buttons_action_button_hideifnoaccess_label' => "Hide if the user does not have access to the linked page", + 'AB_buttons_action_button_hideifnoaccess_label' => 'Hide if the user does not have access to the linked page', 'AB_syndication_action_url_label' => 'RSS feed address', 'AB_syndication_action_template_list' => 'List flow', 'AB_syndication_action_template_list_and_description' => 'Flow as a list with description', @@ -625,10 +626,10 @@ 'AB_advanced_action_textsearch_label' => 'Search for text', 'AB_advanced_action_pageonlyindex_label' => 'List all pages except bazar entries', 'AB_buttons_action_button_text_default' => 'My button', - 'AB_bazarmaterialcard_modal_label' => "Display a modal window on click", + 'AB_bazarmaterialcard_modal_label' => 'Display a modal window on click', 'AB_bazarblog_show_date_label' => 'Display creation date', 'AB_bazargogocarto_description' => 'The entries will be in marker format.', - 'AB_bazargogocarto_height_label' => "Map height", + 'AB_bazargogocarto_height_label' => 'Map height', 'AB_bazargogocarto_width_label' => 'Map width', 'AB_advanced_action_tocjs_size_label' => 'Width', 'AB_advanced_action_login_template_horizontal' => 'Horizontal', diff --git a/docs/actions/lang/actionsbuilder_it.inc.php b/docs/actions/lang/actionsbuilder_it.inc.php index 1641d482d..c4679b90a 100644 --- a/docs/actions/lang/actionsbuilder_it.inc.php +++ b/docs/actions/lang/actionsbuilder_it.inc.php @@ -1,4 +1,5 @@ 'Título', 'AB_attach_link_label' => 'Link relacionado', 'AB_attach_caption_label' => 'Texto da miniatura', - 'AB_attach_size_label' => "Tamanho de imagem", + 'AB_attach_size_label' => 'Tamanho de imagem', 'AB_attach_class_position_left' => 'Esquerda', 'AB_attach_desc_label' => 'Descrição', 'AB_attach_no' => 'Não', @@ -489,23 +490,23 @@ 'AB_syndication_action_title_label' => 'Título', 'AB_advanced_action_login_template_label' => 'Template', 'AB_MYFAVORITES_TEMPLATE_LABEL' => 'Template', - 'AB_bazar_commons_iconfield_label' => "Campo para o ícone", + 'AB_bazar_commons_iconfield_label' => 'Campo para o ícone', 'AB_bazar_commons_iconfield_iconprefix_label' => 'Prefixo para ícones', - 'AB_bazar_commons_iconfield_iconprefix_hint' => "Se você usar o seletor do ícone, você não precisa deste campo", + 'AB_bazar_commons_iconfield_iconprefix_hint' => 'Se você usar o seletor do ícone, você não precisa deste campo', 'AB_bazar_commons_pagination_label' => 'Número de folhas por página', 'AB_bazar_commons_pagination_hint' => 'Deixe vazio para não usar a paginação', 'AB_bazar_commons2_champ_label' => 'Campo para classificação', 'AB_bazar_commons_search_label_dynamic' => 'Pesquisa dinâmica', 'AB_bazar_commons_title' => 'Exposição', - 'AB_bazar_commons2_champ_hint' => "É possível fazer pedidos avançados, aprender mais", + 'AB_bazar_commons2_champ_hint' => 'É possível fazer pedidos avançados, aprender mais', 'AB_bazar_commons2_filter_on_date_on_current_month' => 'no mês que acontece', - 'AB_bazar_commons2_filter_user_as_owner' => "Exibir apenas os plugues atuais do usuário", + 'AB_bazar_commons2_filter_user_as_owner' => 'Exibir apenas os plugues atuais do usuário', 'AB_bazar_commons2_filtercolsize_label' => 'Largura do rosto', 'AB_bazar_commons2_filterposition_label' => 'Posição faceta', 'AB_bazar_commons2_groupsexpanded_label' => 'Exposição inicial de facetas', 'AB_bazar_commons2_ordre_option_asc' => 'Croissant', 'AB_bazar_commons2_ordre_option_desc' => 'Descendo', - 'AB_bazar_commons2_nb_hint' => "Limita a exibição do número de folhas", + 'AB_bazar_commons2_nb_hint' => 'Limita a exibição do número de folhas', 'AB_bazar_commons2_query_label' => 'Pedido (avançado)', 'AB_bazar_commons2_filtersresultnb_label' => 'Mostrar o número de folhas encontradas pelos filtros', 'AB_bazarcarto_description' => 'As cartas estarão na forma de um marcador.', @@ -521,10 +522,10 @@ 'AB_bazarliste_popupselectedfields_label' => 'Campos para manter no popup', 'AB_bazarcarto_navigation_label' => 'Zoom botões de controle', 'AB_bazarcarto_zoommolette_label' => 'Para ampliar com a roda do mouse', - 'AB_bazaragenda_description' => "Os arquivos serão na forma de um evento em uma agenda.", - 'AB_bazaragenda_modal_label' => "Exibição de uma janela modal ao clicar", + 'AB_bazaragenda_description' => 'Os arquivos serão na forma de um evento em uma agenda.', + 'AB_bazaragenda_modal_label' => 'Exibição de uma janela modal ao clicar', 'AB_bazarliste_label' => 'Lista', - 'AB_bazarliste_description' => "As cartas estarão na forma de acordeões", + 'AB_bazarliste_description' => 'As cartas estarão na forma de acordeões', 'AB_bazarliste_displayfields_text_label' => 'Área de texto', 'AB_bazarliste_displayfields_floating_label' => 'Área flutuante', 'AB_bazarliste_displayfields_visual_label' => 'Área visual', @@ -533,13 +534,13 @@ 'AB_bazarcard_style_vertical' => 'Vertical', 'AB_bazarcard_style_horizontal' => 'Horizontal', 'AB_bazarlistephotobox_label' => 'Caixa de fotos', - 'AB_bazargogocarto_height_label' => "Altura do cartão", + 'AB_bazargogocarto_height_label' => 'Altura do cartão', 'AB_attach_size_small' => 'Pequeno', 'AB_attach_attach_title' => 'Parâmetros gerais', 'AB_attach_attach_description' => 'Anexar um arquivo', 'AB_attach_displaypdf_label' => 'Ver o arquivo PDF', 'AB_buttons_action_button_size_big' => 'Grandioso', - 'AB_syndication_action_nouvellefenetre_label' => "Os links abrem em uma nova guia", + 'AB_syndication_action_nouvellefenetre_label' => 'Os links abrem em uma nova guia', 'AB_bazarcard_imgstyle_label' => 'Dimensão da imagem', 'AB_bazarcard_imgstyle_cover' => 'Cubra a área / Rogner', 'AB_BAZAR_MAP_AND_TABLE_LABEL' => 'Mapa e tabela', @@ -577,21 +578,21 @@ 'AB_bazarblog_label' => 'Blog', 'AB_bazargogocarto_label' => 'Cartografia 2 - GoGocarto', 'AB_attach_legend_label' => 'Lenda', - 'AB_attach_nofullimagelink_label' => "Permitir clicar na imagem para exibi-la em grande", + 'AB_attach_nofullimagelink_label' => 'Permitir clicar na imagem para exibi-la em grande', 'AB_attach_yes' => 'Sim', - 'AB_attach_size_original' => "Tamanho original", - 'AB_attach_class_displaylink_label' => "Tipo de abertura de conexão, caso além", + 'AB_attach_size_original' => 'Tamanho original', + 'AB_attach_class_displaylink_label' => 'Tipo de abertura de conexão, caso além', 'AB_attach_class_displaylink_modalbox' => 'em uma janela', 'AB_attach_class_position_label' => 'Posição', 'AB_attach_class_izmir_zoom' => 'Zoom', 'AB_attach_class_izmir_gradiant' => 'Graduação', 'AB_attach_class_izmir_topcentertext' => 'Texto acima', - 'AB_attach_file_hint' => "Para exibir o arquivo em outra página, digite \"Name/NameDeFichier.ext\"", - 'AB_attach_video_hint' => "O ID de vídeo corresponde aos números ou letras no final da URL", + 'AB_attach_file_hint' => 'Para exibir o arquivo em outra página, digite "Name/NameDeFichier.ext"', + 'AB_attach_video_hint' => 'O ID de vídeo corresponde aos números ou letras no final da URL', 'AB_management_themeselector_label' => 'Teste de temas disponíveis', 'AB_advanced_action_progressbar_label' => 'Mostrar uma barra de progresso', 'AB_advanced_action_tocjs_label' => 'Criar um resumo da página', - 'AB_advanced_action_login_userpage_label' => "Ir para a página do usuário uma vez conectado", + 'AB_advanced_action_login_userpage_label' => 'Ir para a página do usuário uma vez conectado', 'AB_advanced_action_login_lostpasswordurl_label' => 'Url para senhas perdidas', 'AB_advanced_action_login_nobtn_label' => 'Substitua o botão com um link (apenas modal)', 'AB_advanced_action_login_loggedinurl_label' => 'Redirecionar url após conexão bem sucedida', @@ -602,10 +603,10 @@ 'AB_buttons_action_button_size_medium' => 'Média', 'AB_buttons_action_button_pull_label' => 'Posição', 'AB_syndication_action_template_label' => 'Modelo de visualização', - 'AB_syndication_action_template_acordion' => "Fluxo na forma de acordeões", + 'AB_syndication_action_template_acordion' => 'Fluxo na forma de acordeões', 'AB_attach_video_url_hint' => 'Substituir servidor e id', 'AB_attach_video_largeur_max_label' => 'Largura máxima', - 'AB_attach_pdf_hint' => "Para ver o seu PDF, primeiro carregá-lo em uma página desta wiki e copiar o link aqui.", + 'AB_attach_pdf_hint' => 'Para ver o seu PDF, primeiro carregá-lo em uma página desta wiki e copiar o link aqui.', 'AB_management_label' => 'Gestão de YesWiki', 'AB_management_despam_label' => 'Limpeza de páginas recentemente vandalizadas', 'AB_management_editconfig_label' => 'Modifique as configurações do arquivo de configuração', @@ -623,15 +624,15 @@ 'AB_MYFAVORITES_TEMPLATE_LINKS_WITH_TITLES' => 'Links com títulos', 'AB_MYFAVORITES_TEMPLATE_TILES' => 'Vignetas', 'AB_syndication_main_label' => 'Sindicato / RSS feeds', - 'AB_syndication_action_description' => "Sincronizar o feed RSS de um site de terceiros", - 'AB_syndication_action_url_hint' => "Você pode adicionar vários fluxos separados de uma vírgula", + 'AB_syndication_action_description' => 'Sincronizar o feed RSS de um site de terceiros', + 'AB_syndication_action_url_hint' => 'Você pode adicionar vários fluxos separados de uma vírgula', 'AB_syndication_action_formatdate_option_jmh' => 'Dia mês hora', 'AB_syndication_action_formatdate_option_jmah' => 'Dia do mês', 'AB_bazartableau_displayimagesasthumbnails_label' => 'Exibir imagens como uma miniatura', 'AB_bazar_commons_search_fields_label' => 'Campos de pesquisa', 'AB_bazar_commons2_resetfiltersbutton_label' => 'Botão para redefinir filtros', 'AB_bazar_commons2_title' => 'Filtros / Facetas', - 'AB_bazar_commons2_showexportbuttons' => "Botões de exportação (CSV, JSON...)", + 'AB_bazar_commons2_showexportbuttons' => 'Botões de exportação (CSV, JSON...)', 'AB_bazarcarto_displayfields_markhover_label' => 'Campo para exibir no topo do marcador', 'AB_bazarcarto_smallmarker_label' => 'Pequenos marcadores', 'AB_bazarcarto_spider_label' => 'Modo de aranha', @@ -662,7 +663,7 @@ 'AB_bazarcarto_coordinates_label' => 'Vista inicial', 'AB_attach_width_label' => 'Largura', 'AB_bazarblog_show_date_label' => 'Ver data de criação', - 'AB_attach_class_displaylink_default' => "No separador atual", + 'AB_attach_class_displaylink_default' => 'No separador atual', 'AB_attach_class_displaylink_new-window' => 'Em um novo separador', 'AB_advanced_action_tocjs_size_label' => 'Largura', 'AB_MYFAVORITES_TEMPLATE_TABLE' => 'Tabela', diff --git a/docs/actions/lang/actionsbuilder_ru.inc.php b/docs/actions/lang/actionsbuilder_ru.inc.php index 6011d2298..854b71b7f 100644 --- a/docs/actions/lang/actionsbuilder_ru.inc.php +++ b/docs/actions/lang/actionsbuilder_ru.inc.php @@ -1,4 +1,5 @@ "க uch ச்சே", - 'AB_RIGHT' => "டிராயிட்", - 'AB_advanced' => "அவான்சே", + 'AB_LEFT' => 'க uch ச்சே', + 'AB_RIGHT' => 'டிராயிட்', + 'AB_advanced' => 'அவான்சே', // BAZAR 'AB_bazar_label' => "Afficher les données d'Un fumlaire", 'AB_bazar_commons_colorfield_label' => 'சாம்ப் லா கூலூர்', @@ -16,14 +16,14 @@ 'AB_bazar_commons_iconfield_iconprefix_label' => 'முன்னொட்டு லெச் ஐகோன்களை ஊற்றவும்', 'AB_bazar_commons_iconfield_iconprefix_hint' => "Si vous utitilisez le selecter d'ycone, vous n'avez pas besoin de ce samp", 'AB_bazar_commons_minical' => "Afficher le contenu sous forme d'Un mini calendrier", - 'AB_bazar_commons_pagination_label' => "நோம்ப்ரே டி ஃபைச் பார் பக்கம்", - 'AB_bazar_commons_pagination_hint' => "லெய்சர் வைட் ஊற்றவும் NE PAS பயன்பாட்டு லா மண்பாண்டம்", - 'AB_bazar_commons_search_fields_label' => "சாம்ப்ச் லா ரீச்செர்ச்சை ஊற்றவும்", - 'AB_bazar_commons_search_label' => "பாரே டி ரெச்செர்ச்", - 'AB_bazar_commons_search_label_dynamic' => "Recherche Dimenic", - 'AB_bazar_commons_subproperty_id_label' => "Foruer", - 'AB_bazar_commons_title' => "அஃபிசேச்", - 'AB_bazar_commons2_champ_label' => "சாம்பியன் ட்ரை போர்", + 'AB_bazar_commons_pagination_label' => 'நோம்ப்ரே டி ஃபைச் பார் பக்கம்', + 'AB_bazar_commons_pagination_hint' => 'லெய்சர் வைட் ஊற்றவும் NE PAS பயன்பாட்டு லா மண்பாண்டம்', + 'AB_bazar_commons_search_fields_label' => 'சாம்ப்ச் லா ரீச்செர்ச்சை ஊற்றவும்', + 'AB_bazar_commons_search_label' => 'பாரே டி ரெச்செர்ச்', + 'AB_bazar_commons_search_label_dynamic' => 'Recherche Dimenic', + 'AB_bazar_commons_subproperty_id_label' => 'Foruer', + 'AB_bazar_commons_title' => 'அஃபிசேச்', + 'AB_bazar_commons2_champ_label' => 'சாம்பியன் ட்ரை போர்', 'AB_bazar_commons2_champ_hint' => "Il est சாத்தியமான d'fectuer des requedes avancees, powr என் savoir plus", 'AB_bazar_commons2_filter_index' => "'bf_date_debut_evenment' doit être defini.", 'AB_bazar_commons2_filter_on_date' => 'ஃபில்டர் சுர் லெச் தேதிகள்', @@ -35,28 +35,28 @@ 'AB_bazar_commons2_filter_on_date_for_two_years' => 'depuis deux ans', 'AB_bazar_commons2_filter_on_date_one_week_more_and_less' => '+/- une செமெய்ன்', 'AB_bazar_commons2_filter_user_as_owner' => "N'afficher que les fiches de l'utilisateur corant", - 'AB_bazar_commons2_filtercolsize_label' => "லார்ச் டெச் ஃபேச்பெட்டுகள்", - 'AB_bazar_commons2_filterposition_label' => "நிலை DES FACETS", - 'AB_bazar_commons2_groupsexpanded_label' => "Affichage ஆரம்ப DES FACETS", - 'AB_bazar_commons2_groupsexpanded_false' => "தனித்துவமான லா பிரீமியர் டெப்லீ", - 'AB_bazar_commons2_groupsexpanded_true' => "டூட்ச் டெப்ளியச்", - 'AB_bazar_commons2_ordre_label' => "ஆர்டர் டி கிளாசென்ட்", - 'AB_bazar_commons2_ordre_option_asc' => "குரோசண்ட்", - 'AB_bazar_commons2_ordre_option_desc' => "Décroissant", - 'AB_bazar_commons2_nb_label' => "வரம்பு", - 'AB_bazar_commons2_nb_hint' => "லிமிட் எல் அஃபிசேச் டு நோம்ப்ரே டி ஃபிச்", - 'AB_bazar_commons2_query_label' => "Requese (avance)", - 'AB_bazar_commons2_filtersresultnb_label' => "Afficher le nombre de fiches troues par les filtres", - 'AB_bazar_commons2_resetfiltersbutton_label' => "பூட்டன் போர் ரைனிடியாலிசர் லெச் ஃபில்ட்ரெச்", - 'AB_bazar_commons2_showexportbuttons' => "பூட்டன்ச் டி எக்ச்போர்ட் (சி.எச்.வி, சேசன்…)", - 'AB_bazar_commons2_title' => "பில்ட்ரெச் / ஃபேசெட்டுகள்", - 'AB_bazar_commons2_showmapinlistview_label' => "ப்ரெசென்டர் யு.என்.இ கார்டே அசோசியே à சாக் ஃபிச்", - 'AB_bazar_commons2_showmapinlistview_hint' => "தனித்துவத்தை ஊற்றவும் லெச் ஃபிடச் குய் ஒன்ட் எட் சியோலோகலிசீச்", - 'AB_bazar_facettes_btn-label-add' => "அசூட்டர் யு.என்.இ ஃபேச்", - 'AB_bazar_facettes_field_label' => "வீரர்", - 'AB_bazar_facettes_title_label' => "டைட்ரே", - 'AB_bazar_bf_date_debut_evenement_label' => "சாம்பியன் போர் லா தேதி டி டெபட்", - 'AB_bazar_bf_date_fin_evenement_label' => "சாம்பியன் போர் லா தேதி டி ஃபின்", + 'AB_bazar_commons2_filtercolsize_label' => 'லார்ச் டெச் ஃபேச்பெட்டுகள்', + 'AB_bazar_commons2_filterposition_label' => 'நிலை DES FACETS', + 'AB_bazar_commons2_groupsexpanded_label' => 'Affichage ஆரம்ப DES FACETS', + 'AB_bazar_commons2_groupsexpanded_false' => 'தனித்துவமான லா பிரீமியர் டெப்லீ', + 'AB_bazar_commons2_groupsexpanded_true' => 'டூட்ச் டெப்ளியச்', + 'AB_bazar_commons2_ordre_label' => 'ஆர்டர் டி கிளாசென்ட்', + 'AB_bazar_commons2_ordre_option_asc' => 'குரோசண்ட்', + 'AB_bazar_commons2_ordre_option_desc' => 'Décroissant', + 'AB_bazar_commons2_nb_label' => 'வரம்பு', + 'AB_bazar_commons2_nb_hint' => 'லிமிட் எல் அஃபிசேச் டு நோம்ப்ரே டி ஃபிச்', + 'AB_bazar_commons2_query_label' => 'Requese (avance)', + 'AB_bazar_commons2_filtersresultnb_label' => 'Afficher le nombre de fiches troues par les filtres', + 'AB_bazar_commons2_resetfiltersbutton_label' => 'பூட்டன் போர் ரைனிடியாலிசர் லெச் ஃபில்ட்ரெச்', + 'AB_bazar_commons2_showexportbuttons' => 'பூட்டன்ச் டி எக்ச்போர்ட் (சி.எச்.வி, சேசன்…)', + 'AB_bazar_commons2_title' => 'பில்ட்ரெச் / ஃபேசெட்டுகள்', + 'AB_bazar_commons2_showmapinlistview_label' => 'ப்ரெசென்டர் யு.என்.இ கார்டே அசோசியே à சாக் ஃபிச்', + 'AB_bazar_commons2_showmapinlistview_hint' => 'தனித்துவத்தை ஊற்றவும் லெச் ஃபிடச் குய் ஒன்ட் எட் சியோலோகலிசீச்', + 'AB_bazar_facettes_btn-label-add' => 'அசூட்டர் யு.என்.இ ஃபேச்', + 'AB_bazar_facettes_field_label' => 'வீரர்', + 'AB_bazar_facettes_title_label' => 'டைட்ரே', + 'AB_bazar_bf_date_debut_evenement_label' => 'சாம்பியன் போர் லா தேதி டி டெபட்', + 'AB_bazar_bf_date_fin_evenement_label' => 'சாம்பியன் போர் லா தேதி டி ஃபின்', // Bazarcarto 'AB_bazarcarto_label' => 'கார்டோகிராஃபி', 'AB_bazarcarto_description' => 'லெச் ஃபிடச் செரண்ட் ச ous ச் ஃபார்ம் டி மார்குவூர்.', @@ -225,17 +225,17 @@ 'AB_attach_class_label' => 'கிளாச்', 'AB_attach_class_displaylink_label' => "டைப் டி'ஓட்வெர்டூர் டு லீன், லு காச் échéant", 'AB_attach_class_displaylink_default' => "டான்ச் எல்'ன்க்லெட் கூரண்ட்", - 'AB_attach_class_displaylink_new-window' => "டான்ச் அன் நோவெல் ஓங்க்லெட்", - 'AB_attach_class_displaylink_modalbox' => "டான்ச் யு.என்.இ ஃபெனட்ரே மோடேல்", - 'AB_attach_class_position_label' => "நிலை", - 'AB_attach_class_position_none' => "டெக்ச்டே என் டெசச்", - 'AB_attach_class_position_left' => "க uch ச்சே", - 'AB_attach_class_position_center' => "நடுவண்", - 'AB_attach_class_position_right' => "டிராயிட்", - 'AB_attach_class_effect_lightshadow' => "Efet ombre portée", - 'AB_attach_class_effect_whiteborder' => "எஃபெட் போர்டு பிளாங்க்", - 'AB_attach_class_effect_zoom' => "Effet agarandisment அயு survol", - 'AB_attach_class_izmir_label' => "Izmir", + 'AB_attach_class_displaylink_new-window' => 'டான்ச் அன் நோவெல் ஓங்க்லெட்', + 'AB_attach_class_displaylink_modalbox' => 'டான்ச் யு.என்.இ ஃபெனட்ரே மோடேல்', + 'AB_attach_class_position_label' => 'நிலை', + 'AB_attach_class_position_none' => 'டெக்ச்டே என் டெசச்', + 'AB_attach_class_position_left' => 'க uch ச்சே', + 'AB_attach_class_position_center' => 'நடுவண்', + 'AB_attach_class_position_right' => 'டிராயிட்', + 'AB_attach_class_effect_lightshadow' => 'Efet ombre portée', + 'AB_attach_class_effect_whiteborder' => 'எஃபெட் போர்டு பிளாங்க்', + 'AB_attach_class_effect_zoom' => 'Effet agarandisment அயு survol', + 'AB_attach_class_izmir_label' => 'Izmir', 'AB_attach_class_izmir_hint' => "Et beaucoup plus d'fets disponibles சுர் https://ciar4n.com/izmir", 'AB_attach_class_izmir_izmir' => 'இச்மிர்', 'AB_attach_class_izmir_border' => 'எல்லை', @@ -262,91 +262,91 @@ 'AB_attach_video_largeur_max_label' => 'பெரிய மாக்சிமேல்', 'AB_attach_video_hauteur_max_label' => 'ஆட்டூர் மாக்சிமேல்', //pdf - 'AB_attach_pdf_label' => "Fichier pdf integre", - 'AB_attach_pdf_description' => "இன்டெக்ரேசன் டி அன் ஃபைச்சியர் பி.டி.எஃப் டி சிஇ தளம்.", - 'AB_attach_pdf_hint' => "அஃபிச்சர் வோட்ரே பி.டி.எஃப், டி.", - 'AB_attach_pdf_url_label' => "முகவரி DU FICHIER", - 'AB_attach_pdf_ratio_label' => "விகிதம் ஊற்றவும்", - 'AB_attach_pdf_ratio_option_portrait' => "உருவப்படம்", - 'AB_attach_pdf_ratio_option_paysage' => "paysage", - 'AB_attach_pdf_ratio_option_carre' => "CARRE", - 'AB_attach_pdf_position_label' => "நிலை DU PDF", - 'AB_attach_pdf_largeur_max_label' => "பெரிய மாக்சிமேல்", - 'AB_attach_pdf_hauteur_max_label' => "ஆட்டூர் மாக்சிமேல்", + 'AB_attach_pdf_label' => 'Fichier pdf integre', + 'AB_attach_pdf_description' => 'இன்டெக்ரேசன் டி அன் ஃபைச்சியர் பி.டி.எஃப் டி சிஇ தளம்.', + 'AB_attach_pdf_hint' => 'அஃபிச்சர் வோட்ரே பி.டி.எஃப், டி.', + 'AB_attach_pdf_url_label' => 'முகவரி DU FICHIER', + 'AB_attach_pdf_ratio_label' => 'விகிதம் ஊற்றவும்', + 'AB_attach_pdf_ratio_option_portrait' => 'உருவப்படம்', + 'AB_attach_pdf_ratio_option_paysage' => 'paysage', + 'AB_attach_pdf_ratio_option_carre' => 'CARRE', + 'AB_attach_pdf_position_label' => 'நிலை DU PDF', + 'AB_attach_pdf_largeur_max_label' => 'பெரிய மாக்சிமேல்', + 'AB_attach_pdf_hauteur_max_label' => 'ஆட்டூர் மாக்சிமேல்', // management 'AB_management_label' => 'கெச்டியன் டு யெச்விகி', 'AB_management_editactionsacls_label' => 'எடிட்டர் லெச் ட்ரோய்ட்ச் டி அக்யச் ஆக்ச் செயல்கள்', 'AB_management_edithandlersacls_label' => 'எடிட்டர் லெச் ட்ரோய்ட்ச் டி அக்ச் ஆக்ச் ஏண்ட்லர்கள்', 'AB_management_editgroups_label' => "எடிட்டர் லெச் குழுக்கள் டி'அபிலிசேட்டர்கள்", - 'AB_management_adminpages_label' => "கெச்டியன் டெச் பக்கங்கள்", - 'AB_management_gererdroits_label' => "செரர் லெச் ட்ரோய்ட்ச் டி அக்ச் ஆக்ச் பக்கங்கள்", - 'AB_management_gererthemes_label' => "செரர் லு தெம் டெச் பக்கங்கள்", - 'AB_management_setwikidefaulttheme_label' => "டெஃபினிர் லு தெம் டி பேச்", - 'AB_management_userstable_label' => "அட்டவணை டெச் பயன்பாட்டாளர்கள்", - 'AB_management_filemanager_label' => "கெச்டியன் டெச் பிச்சியர்ச்", - 'AB_management_themeselector_label' => "சோதனையாளர் லெச் தெம்ச் டிச்போனிபிள்ச்", - 'AB_management_despam_label' => "நெட்டோயர் லெச் பக்கங்கள் reécemment vandalisees", - 'AB_management_despam_hint' => "Liste les dernieres பதிப்புகள் டெச் பக்கங்கள் récemment créees pour pouvoir soisir cells à supprimer", - 'AB_management_editconfig_label' => "மாற்றியமைக்கும் டெச் பரமரேட்ச் டு ஃபைச்சியர் டி உள்ளமைவு", - 'AB_management_adminbackups_label' => "கெச்டியன் டெச் சாவெகார்ட்ச்", - 'AB_management_commentstable_label' => "டேபிள் டெச் கருத்துரு", - 'AB_management_usercomments_label' => "Mes commpressaires", + 'AB_management_adminpages_label' => 'கெச்டியன் டெச் பக்கங்கள்', + 'AB_management_gererdroits_label' => 'செரர் லெச் ட்ரோய்ட்ச் டி அக்ச் ஆக்ச் பக்கங்கள்', + 'AB_management_gererthemes_label' => 'செரர் லு தெம் டெச் பக்கங்கள்', + 'AB_management_setwikidefaulttheme_label' => 'டெஃபினிர் லு தெம் டி பேச்', + 'AB_management_userstable_label' => 'அட்டவணை டெச் பயன்பாட்டாளர்கள்', + 'AB_management_filemanager_label' => 'கெச்டியன் டெச் பிச்சியர்ச்', + 'AB_management_themeselector_label' => 'சோதனையாளர் லெச் தெம்ச் டிச்போனிபிள்ச்', + 'AB_management_despam_label' => 'நெட்டோயர் லெச் பக்கங்கள் reécemment vandalisees', + 'AB_management_despam_hint' => 'Liste les dernieres பதிப்புகள் டெச் பக்கங்கள் récemment créees pour pouvoir soisir cells à supprimer', + 'AB_management_editconfig_label' => 'மாற்றியமைக்கும் டெச் பரமரேட்ச் டு ஃபைச்சியர் டி உள்ளமைவு', + 'AB_management_adminbackups_label' => 'கெச்டியன் டெச் சாவெகார்ட்ச்', + 'AB_management_commentstable_label' => 'டேபிள் டெச் கருத்துரு', + 'AB_management_usercomments_label' => 'Mes commpressaires', // advanced actions - 'AB_advanced_actions_label' => "செயல்கள் அவான்சச்", - 'AB_advanced_action_backlinks_label' => "Afficher les பக்கங்கள் QUI ONT UN LIEN VERS LA PAGE CORANTE", - 'AB_advanced_action_backlinks_page_label' => "பக்கம் டி அடிப்படை", - 'AB_advanced_action_backlinks_page_hint' => "Vide = பக்க கூரண்டே", - 'AB_advanced_action_wantedpages_label' => "லிச்டர் லெச் பக்கங்கள் à க்ரீயர்", - 'AB_advanced_action_include_label' => "Indure une page dans une autre", - 'AB_advanced_action_redirect_label' => "Rédiriger vers ine autre page du wiki", - 'AB_advanced_action_listpages_label' => "Afficher les பக்கங்கள் sous forme de liste", - 'AB_advanced_action_listpages_sort_label' => "ட்ரை", - 'AB_advanced_action_listpages_tree_label' => "Afficher sous forme de வரைபடம்/திட்டம்", - 'AB_advanced_action_listpages_tree_hint' => "டேக் டி லா பேச் டி பேச்; மரம் = ரூட்_பேச்", - 'AB_advanced_action_listpages_levels_label' => "நோம்ப்ரே டி நிவோக்ச்", - 'AB_advanced_action_listpages_levels_hint' => "(எண் உள்ளிடு 1 முதல் 7 வரை, 3 இயல்பான மதிப்பு)", + 'AB_advanced_actions_label' => 'செயல்கள் அவான்சச்', + 'AB_advanced_action_backlinks_label' => 'Afficher les பக்கங்கள் QUI ONT UN LIEN VERS LA PAGE CORANTE', + 'AB_advanced_action_backlinks_page_label' => 'பக்கம் டி அடிப்படை', + 'AB_advanced_action_backlinks_page_hint' => 'Vide = பக்க கூரண்டே', + 'AB_advanced_action_wantedpages_label' => 'லிச்டர் லெச் பக்கங்கள் à க்ரீயர்', + 'AB_advanced_action_include_label' => 'Indure une page dans une autre', + 'AB_advanced_action_redirect_label' => 'Rédiriger vers ine autre page du wiki', + 'AB_advanced_action_listpages_label' => 'Afficher les பக்கங்கள் sous forme de liste', + 'AB_advanced_action_listpages_sort_label' => 'ட்ரை', + 'AB_advanced_action_listpages_tree_label' => 'Afficher sous forme de வரைபடம்/திட்டம்', + 'AB_advanced_action_listpages_tree_hint' => 'டேக் டி லா பேச் டி பேச்; மரம் = ரூட்_பேச்', + 'AB_advanced_action_listpages_levels_label' => 'நோம்ப்ரே டி நிவோக்ச்', + 'AB_advanced_action_listpages_levels_hint' => '(எண் உள்ளிடு 1 முதல் 7 வரை, 3 இயல்பான மதிப்பு)', 'AB_advanced_action_listpages_owner_label' => "N'afficher que les fiches dont l'பயன்பாடு", 'AB_advanced_action_listpages_owner_hint' => 'முதன்மை டெஃபினி லு பயன்முறை மரத்தை ஊற்றவும்', 'AB_advanced_action_listpages_user_label' => "N'afficher que les fiches dans lesquelles l'utilisateur a பங்கேற்பு", 'AB_advanced_action_listpages_user_hint' => 'Ne peut être comminé avec மரம்', 'AB_advanced_action_listpages_exclude_label' => 'டெச் பக்கங்கள் மற்றும் லியர்ச் வம்சாவளியை விலக்கு', 'AB_advanced_action_listpages_exclude_hint' => "செபரர் சாக் டேக் பார் ';' ',' '|'ou'/'", - 'AB_advanced_action_bazarrecordsindex_label' => "லிச்டர் சியுலேமென்ட் லெச் ஃபிடச் கடைவீதி", - 'AB_advanced_action_interwikilist_label' => "Afficher la liste interwiki", - 'AB_advanced_action_listusers_label' => "லிச்டர் லெச் பயன்பாட்டாளர்கள், பயன்பாட்டு செயல்கள்", - 'AB_advanced_action_listusers_last_label' => "லிச்டர் தனித்துவம் லெச் டெர்னியர்ச் காம்ப்டெச் க்ரீச்", - 'AB_advanced_action_listusers_last_hint' => "நோம்ப்ரே டி காம்ப்டெச் à அஃப்சர்", - 'AB_advanced_action_mychanges_label' => "Afficher mes மாற்றங்கள்", - 'AB_advanced_action_mychanges_bydate_label' => "ட்ரையர் சம தேதி", - 'AB_advanced_action_mypages_label' => "Afficher Mes பக்கங்கள்", - 'AB_advanced_action_textsearch_label' => "ரீச்செச் டி டெக்ச்டே", - 'AB_advanced_action_newtextsearch_label' => "ரீச்செச் டி டெக்ச்டே", - 'AB_advanced_action_textsearch_label_label' => "சிட்டை à அஃப்சர் தேவந்த் லா மண்டல டி சைசி", - 'AB_advanced_action_textsearch_size_label' => "லார்ச் டி லா சோன் டி சைசி", - 'AB_advanced_action_textsearch_button_label' => "டெக்ச்டே டு பூட்டன்", - 'AB_advanced_action_textsearch_phrase_label' => "டெக்ச்டே à செச்சர்", - 'AB_advanced_action_textsearch_separator_label' => "séparateur entre les éléments trouves", - 'AB_advanced_action_orphanedpages_label' => "லிச்டர் லெச் பக்கங்கள் ஆர்ப்லைன்ச்", - 'AB_advanced_action_pageindex_label' => "லிச்டர் டூட்ச் லெச் பக்கங்கள்", - 'AB_advanced_action_pageonlyindex_label' => "லிச்டர் டூட்ச் லெச் பக்கங்கள் SAUF LES FICHES BAZAR", - 'AB_advanced_action_progressbar_label' => "Afficher une parre de முன்னேற்றம்", - 'AB_advanced_action_progressbar_val_label' => "Foruer", - 'AB_advanced_action_progressbar_val_hint' => "(என்ட்ரே 0 மற்றும் 100)", - 'AB_advanced_action_tocjs_label' => "க்ரீயர் அன் சோமெய்ர் டி லா பேச்", - 'AB_advanced_action_tocjs_position_label' => "நிலை", - 'AB_advanced_action_tocjs_position_right_option' => "டிராயிட்", - 'AB_advanced_action_tocjs_position_left_option' => "க uch ச்சே", - 'AB_advanced_action_tocjs_size_label' => "பெரியவர்", - 'AB_advanced_action_trail_label' => "Afficher des liens \"Page suivante\" \"SOMMAIRE\" \"PAGE MEXEDENTE\" டான்ச் UNE பக்கம்", - 'AB_advanced_action_trail_toc_label' => "பக்கம் சோமெய்ர்", - 'AB_advanced_action_recentchanges_label' => "லெச்டே LES DERNIERS மாற்றங்கள்", - 'AB_advanced_action_recentchanges_max_label' => "நோம்ப்ரே அதிகபட்ச டி மாற்றங்கள் à அஃப்சர்", - 'AB_advanced_action_recentchanges_period_label' => "தேதி à பார்ட்டிர் டி லாக்வெல் லெச் மாற்றங்கள் சோன்ட் அஃபிசச்", - 'AB_advanced_action_recentchanges_period_hint' => "வடிவம்: 2000-01-01 00:00:00", - 'AB_advanced_action_recentcomments_label' => "லிச்டே லெச் டெர்னியர்ச் கருத்துரை", - 'AB_advanced_action_recentcomments_max_label' => "நோம்ப்ரே அதிகபட்ச டி கருத்துரை à அஃப்சர்", - 'AB_advanced_action_configuration_label' => "Afficher le contenu du fichier de உள்ளமைவு", - 'AB_advanced_action_login_label' => "இணைப்பு", + 'AB_advanced_action_bazarrecordsindex_label' => 'லிச்டர் சியுலேமென்ட் லெச் ஃபிடச் கடைவீதி', + 'AB_advanced_action_interwikilist_label' => 'Afficher la liste interwiki', + 'AB_advanced_action_listusers_label' => 'லிச்டர் லெச் பயன்பாட்டாளர்கள், பயன்பாட்டு செயல்கள்', + 'AB_advanced_action_listusers_last_label' => 'லிச்டர் தனித்துவம் லெச் டெர்னியர்ச் காம்ப்டெச் க்ரீச்', + 'AB_advanced_action_listusers_last_hint' => 'நோம்ப்ரே டி காம்ப்டெச் à அஃப்சர்', + 'AB_advanced_action_mychanges_label' => 'Afficher mes மாற்றங்கள்', + 'AB_advanced_action_mychanges_bydate_label' => 'ட்ரையர் சம தேதி', + 'AB_advanced_action_mypages_label' => 'Afficher Mes பக்கங்கள்', + 'AB_advanced_action_textsearch_label' => 'ரீச்செச் டி டெக்ச்டே', + 'AB_advanced_action_newtextsearch_label' => 'ரீச்செச் டி டெக்ச்டே', + 'AB_advanced_action_textsearch_label_label' => 'சிட்டை à அஃப்சர் தேவந்த் லா மண்டல டி சைசி', + 'AB_advanced_action_textsearch_size_label' => 'லார்ச் டி லா சோன் டி சைசி', + 'AB_advanced_action_textsearch_button_label' => 'டெக்ச்டே டு பூட்டன்', + 'AB_advanced_action_textsearch_phrase_label' => 'டெக்ச்டே à செச்சர்', + 'AB_advanced_action_textsearch_separator_label' => 'séparateur entre les éléments trouves', + 'AB_advanced_action_orphanedpages_label' => 'லிச்டர் லெச் பக்கங்கள் ஆர்ப்லைன்ச்', + 'AB_advanced_action_pageindex_label' => 'லிச்டர் டூட்ச் லெச் பக்கங்கள்', + 'AB_advanced_action_pageonlyindex_label' => 'லிச்டர் டூட்ச் லெச் பக்கங்கள் SAUF LES FICHES BAZAR', + 'AB_advanced_action_progressbar_label' => 'Afficher une parre de முன்னேற்றம்', + 'AB_advanced_action_progressbar_val_label' => 'Foruer', + 'AB_advanced_action_progressbar_val_hint' => '(என்ட்ரே 0 மற்றும் 100)', + 'AB_advanced_action_tocjs_label' => 'க்ரீயர் அன் சோமெய்ர் டி லா பேச்', + 'AB_advanced_action_tocjs_position_label' => 'நிலை', + 'AB_advanced_action_tocjs_position_right_option' => 'டிராயிட்', + 'AB_advanced_action_tocjs_position_left_option' => 'க uch ச்சே', + 'AB_advanced_action_tocjs_size_label' => 'பெரியவர்', + 'AB_advanced_action_trail_label' => 'Afficher des liens "Page suivante" "SOMMAIRE" "PAGE MEXEDENTE" டான்ச் UNE பக்கம்', + 'AB_advanced_action_trail_toc_label' => 'பக்கம் சோமெய்ர்', + 'AB_advanced_action_recentchanges_label' => 'லெச்டே LES DERNIERS மாற்றங்கள்', + 'AB_advanced_action_recentchanges_max_label' => 'நோம்ப்ரே அதிகபட்ச டி மாற்றங்கள் à அஃப்சர்', + 'AB_advanced_action_recentchanges_period_label' => 'தேதி à பார்ட்டிர் டி லாக்வெல் லெச் மாற்றங்கள் சோன்ட் அஃபிசச்', + 'AB_advanced_action_recentchanges_period_hint' => 'வடிவம்: 2000-01-01 00:00:00', + 'AB_advanced_action_recentcomments_label' => 'லிச்டே லெச் டெர்னியர்ச் கருத்துரை', + 'AB_advanced_action_recentcomments_max_label' => 'நோம்ப்ரே அதிகபட்ச டி கருத்துரை à அஃப்சர்', + 'AB_advanced_action_configuration_label' => 'Afficher le contenu du fichier de உள்ளமைவு', + 'AB_advanced_action_login_label' => 'இணைப்பு', 'AB_advanced_action_login_signupurl_label' => "முகவரி D'கல்வெட்டு", 'AB_advanced_action_login_signupurl_hint' => "பக்கம் டு விக்கி ஓ உர் '0' ஊற்றப்பட்ட முகமூடி லு பூட்டன் டி கல்வெட்டு", 'AB_advanced_action_login_profileurl_label' => 'முகவரி DU PROFIL', @@ -377,33 +377,33 @@ 'AB_buttons_action_button_text_default' => 'மோன் பூட்டன்', 'AB_buttons_action_button_link_label' => "Lien விரலிடைத் தோல் ou nom d'ne page de ce wiki", 'AB_buttons_action_button_link_hint' => "Si lien web, n'oubliez pas le \"https: //\"", - 'AB_buttons_action_button_title_label' => "டெக்ச்டே அஃபிச் ஆ சர்வர்", - 'AB_buttons_action_button_icon_label' => "ஐகோன்", - 'AB_buttons_action_button_class_label' => "கிளாச்", - 'AB_buttons_action_button_color_label' => "கூலூர்", - 'AB_buttons_action_button_color_default' => "Defaut", - 'AB_buttons_action_button_color_primary' => "முதன்மை", - 'AB_buttons_action_button_color_secondary1' => "செகண்டேர் -1", - 'AB_buttons_action_button_color_secondary2' => "செகண்டேர் -2", - 'AB_buttons_action_button_color_success' => "சக்ச்", - 'AB_buttons_action_button_color_info' => "செய்தி", - 'AB_buttons_action_button_color_warning' => "கவனம்", - 'AB_buttons_action_button_color_danger' => "இடர்", - 'AB_buttons_action_button_color_link' => "உரிமை", - 'AB_buttons_action_button_size_label' => "டெயில்", - 'AB_buttons_action_button_size_standard' => "சாதாரண", - 'AB_buttons_action_button_size_small' => "பெட்டிட்", - 'AB_buttons_action_button_size_medium' => "மோயன்", - 'AB_buttons_action_button_size_big' => "மாபெரும்", - 'AB_buttons_action_button_modal_label' => "ஓவ்ரிர் லு கான்டெனு டு லீன் டான்ச் யூன் பாப்அப்", - 'AB_buttons_action_button_modal_hint' => "Fonctionne vers une page de ce wiki", - 'AB_buttons_action_button_modal_modalbox' => "லோர்ச் டு சொடுக்கு", - 'AB_buttons_action_button_modal_modalbox_hover' => "அயு சர்வோல்", - 'AB_buttons_action_button_pull_label' => "நிலை", - 'AB_buttons_action_button_pull_right' => "டிராயிட்", - 'AB_buttons_action_button_pull_block' => "Toute la largur", - 'AB_buttons_action_button_new_window_label' => "Ouvrir dans une nouvelle fenétre", - 'AB_buttons_action_button_new_window_yes' => "oui", + 'AB_buttons_action_button_title_label' => 'டெக்ச்டே அஃபிச் ஆ சர்வர்', + 'AB_buttons_action_button_icon_label' => 'ஐகோன்', + 'AB_buttons_action_button_class_label' => 'கிளாச்', + 'AB_buttons_action_button_color_label' => 'கூலூர்', + 'AB_buttons_action_button_color_default' => 'Defaut', + 'AB_buttons_action_button_color_primary' => 'முதன்மை', + 'AB_buttons_action_button_color_secondary1' => 'செகண்டேர் -1', + 'AB_buttons_action_button_color_secondary2' => 'செகண்டேர் -2', + 'AB_buttons_action_button_color_success' => 'சக்ச்', + 'AB_buttons_action_button_color_info' => 'செய்தி', + 'AB_buttons_action_button_color_warning' => 'கவனம்', + 'AB_buttons_action_button_color_danger' => 'இடர்', + 'AB_buttons_action_button_color_link' => 'உரிமை', + 'AB_buttons_action_button_size_label' => 'டெயில்', + 'AB_buttons_action_button_size_standard' => 'சாதாரண', + 'AB_buttons_action_button_size_small' => 'பெட்டிட்', + 'AB_buttons_action_button_size_medium' => 'மோயன்', + 'AB_buttons_action_button_size_big' => 'மாபெரும்', + 'AB_buttons_action_button_modal_label' => 'ஓவ்ரிர் லு கான்டெனு டு லீன் டான்ச் யூன் பாப்அப்', + 'AB_buttons_action_button_modal_hint' => 'Fonctionne vers une page de ce wiki', + 'AB_buttons_action_button_modal_modalbox' => 'லோர்ச் டு சொடுக்கு', + 'AB_buttons_action_button_modal_modalbox_hover' => 'அயு சர்வோல்', + 'AB_buttons_action_button_pull_label' => 'நிலை', + 'AB_buttons_action_button_pull_right' => 'டிராயிட்', + 'AB_buttons_action_button_pull_block' => 'Toute la largur', + 'AB_buttons_action_button_new_window_label' => 'Ouvrir dans une nouvelle fenétre', + 'AB_buttons_action_button_new_window_yes' => 'oui', 'AB_buttons_action_button_hideifnoaccess_label' => "முகமூடி si l'utilisateur n'a pas acces à la page leiee", 'AB_buttons_action_button_nobtn_label' => 'Afficher sous forme de lien', // reactions @@ -426,25 +426,25 @@ 'AB_MYFAVORITES_TEMPLATE_TILES' => 'விக்னெட்டுகள்', 'AB_MYFAVORITES_TEMPLATE_TABLE' => 'அட்டவணை', // syndication - 'AB_syndication_main_label' => "சிண்டிகேசன் / ஃப்ளக்ச் ஆர்.எச்.எச்", - 'AB_syndication_action_label' => "சிண்டிகேசன்", - 'AB_syndication_action_description' => "சிண்டிகர் லு ஃப்ளக்ச் ஆர்எச்எச் டி அன் தள அடுக்குகள்", - 'AB_syndication_action_url_label' => "அட்ரெச் டு ஃப்ளக்ச் ஆர்.எச்.எச்", + 'AB_syndication_main_label' => 'சிண்டிகேசன் / ஃப்ளக்ச் ஆர்.எச்.எச்', + 'AB_syndication_action_label' => 'சிண்டிகேசன்', + 'AB_syndication_action_description' => 'சிண்டிகர் லு ஃப்ளக்ச் ஆர்எச்எச் டி அன் தள அடுக்குகள்', + 'AB_syndication_action_url_label' => 'அட்ரெச் டு ஃப்ளக்ச் ஆர்.எச்.எச்', 'AB_syndication_action_url_hint' => "Vous pouvez ajouter plusierures இளக்கி sépares d'Une விர்சூல்", - 'AB_syndication_action_title_label' => "டைட்ரே", - 'AB_syndication_action_source_label' => "டைட்ரே டெச் ஃப்ளக்ச்", - 'AB_syndication_action_source_hint' => "டைட்ரே டு ஃப்ளக்ச் 1, டைட்ரே டு ஃப்ளக்ச் 2… இண்டிக் என் காச் டி ஆதாரங்கள் மடங்குகள் லு டைட்ரே டு ஃப்ளக்ச்", - 'AB_syndication_action_nb_label' => "நோம்ப்ரே டி செய்தி à அஃப்சர்", - 'AB_syndication_action_template_label' => "வார்ப்புரு டி காட்சிப்படுத்தல்", + 'AB_syndication_action_title_label' => 'டைட்ரே', + 'AB_syndication_action_source_label' => 'டைட்ரே டெச் ஃப்ளக்ச்', + 'AB_syndication_action_source_hint' => 'டைட்ரே டு ஃப்ளக்ச் 1, டைட்ரே டு ஃப்ளக்ச் 2… இண்டிக் என் காச் டி ஆதாரங்கள் மடங்குகள் லு டைட்ரே டு ஃப்ளக்ச்', + 'AB_syndication_action_nb_label' => 'நோம்ப்ரே டி செய்தி à அஃப்சர்', + 'AB_syndication_action_template_label' => 'வார்ப்புரு டி காட்சிப்படுத்தல்', 'AB_syndication_action_template_acordion' => "இளக்கி ச ous ச் ஃபார்ம் டி'லேடியோன்கள்", - 'AB_syndication_action_template_list' => "இளக்கி ச ous ச் ஃபார்ம் டி பட்டியல்", - 'AB_syndication_action_template_list_and_description' => "ஃப்ளக்ச் ச ous ச் ஃபார்ம் டி பட்டியல் அவெக் விளக்கம்", + 'AB_syndication_action_template_list' => 'இளக்கி ச ous ச் ஃபார்ம் டி பட்டியல்', + 'AB_syndication_action_template_list_and_description' => 'ஃப்ளக்ச் ச ous ச் ஃபார்ம் டி பட்டியல் அவெக் விளக்கம்', 'AB_syndication_action_nouvellefenetre_label' => "லெச் லீன்ச் s'ouvrent dans un nouvel onglet", - 'AB_syndication_action_formatdate_label' => "Affiche les வெளியீடு தேதிகள்", - 'AB_syndication_action_formatdate_option_jm' => "அருமை மோயிச்", - 'AB_syndication_action_formatdate_option_jma' => "அருமை மோயிச் அன்னே", - 'AB_syndication_action_formatdate_option_jmh' => "அருமை மோயிச் இயூர்", - 'AB_syndication_action_formatdate_option_jmah' => "அருமை மோயிச் அன்னே இயூர்", + 'AB_syndication_action_formatdate_label' => 'Affiche les வெளியீடு தேதிகள்', + 'AB_syndication_action_formatdate_option_jm' => 'அருமை மோயிச்', + 'AB_syndication_action_formatdate_option_jma' => 'அருமை மோயிச் அன்னே', + 'AB_syndication_action_formatdate_option_jmh' => 'அருமை மோயிச் இயூர்', + 'AB_syndication_action_formatdate_option_jmah' => 'அருமை மோயிச் அன்னே இயூர்', // tableau 'AB_bazartableau_label' => 'அட்டவணை', 'AB_bazartableau_description' => 'Afficher sous forme de tableau', @@ -457,17 +457,17 @@ 'AB_bazartableau_sumfieldsids_label' => 'சாம்ப்ச் லெச்குவல்ச் கால்குலர் லா சோம்', 'AB_bazartableau_sumfieldsids_hint' => 'Vide = aucun', 'AB_bazartableau_displayadmincol_label' => "Afficher les boutons d'நிர்வாகம்", - 'AB_bazartableau_displayadmincol_hint' => "மாற்றியமைப்பாளர்/சப்ம்பிரிமர்", - 'AB_bazartableau_displayadmincol_onlyadmins' => "சியுலேமென்ட் போர் லெச் நிர்வாகிகள்", - 'AB_bazartableau_displaycreationdate_label' => "Afficher la திகதி de creation", - 'AB_bazartableau_displaylastchangedate_label' => "Afficher la திகதி de modification", - 'AB_bazartableau_displayowner_label' => "Afficher le propriétaire", - 'AB_bazartableau_defaultcolumnwidth_label' => "லார்ச் மினிமேல் டெச் கோர்ன்ச்", - 'AB_bazartableau_defaultcolumnwidth_hint' => "முன்னாள். : 100px ou 20%; vide = பெரிய ஆட்டோமேட்டிக் (vide est plus joli என் cas de andernalization par samp)", - 'AB_bazartableau_columnswidth_label' => "பெரிய ஆளுமை டெச் கோர்ன்ச்", - 'AB_bazartableau_columnswidth_hint' => "முன்னாள். : 100px ou 20%; vide = பெரிய ஆட்டோமாட்டிக்", - 'AB_bazartableau_columnswidth_field_label' => "வீரர்", - 'AB_bazartableau_columnswidth_width_label' => "பெரியவர்", - 'AB_bazartableau_exportallcolumns_label' => "ஏற்றுமதியாளர் ஆசி லெச் கோர்ன்ச் மாச்கச்", - 'AB_bazartableau_displayimagesasthumbnails_label' => "Afficher les படங்கள் sous forme de vignette", + 'AB_bazartableau_displayadmincol_hint' => 'மாற்றியமைப்பாளர்/சப்ம்பிரிமர்', + 'AB_bazartableau_displayadmincol_onlyadmins' => 'சியுலேமென்ட் போர் லெச் நிர்வாகிகள்', + 'AB_bazartableau_displaycreationdate_label' => 'Afficher la திகதி de creation', + 'AB_bazartableau_displaylastchangedate_label' => 'Afficher la திகதி de modification', + 'AB_bazartableau_displayowner_label' => 'Afficher le propriétaire', + 'AB_bazartableau_defaultcolumnwidth_label' => 'லார்ச் மினிமேல் டெச் கோர்ன்ச்', + 'AB_bazartableau_defaultcolumnwidth_hint' => 'முன்னாள். : 100px ou 20%; vide = பெரிய ஆட்டோமேட்டிக் (vide est plus joli என் cas de andernalization par samp)', + 'AB_bazartableau_columnswidth_label' => 'பெரிய ஆளுமை டெச் கோர்ன்ச்', + 'AB_bazartableau_columnswidth_hint' => 'முன்னாள். : 100px ou 20%; vide = பெரிய ஆட்டோமாட்டிக்', + 'AB_bazartableau_columnswidth_field_label' => 'வீரர்', + 'AB_bazartableau_columnswidth_width_label' => 'பெரியவர்', + 'AB_bazartableau_exportallcolumns_label' => 'ஏற்றுமதியாளர் ஆசி லெச் கோர்ன்ச் மாச்கச்', + 'AB_bazartableau_displayimagesasthumbnails_label' => 'Afficher les படங்கள் sous forme de vignette', ]; diff --git a/formatters/wakka.php b/formatters/wakka.php index 43b81a563..360689db0 100755 --- a/formatters/wakka.php +++ b/formatters/wakka.php @@ -418,6 +418,7 @@ public function callback($things) $src = $matches[2]; $alt = htmlspecialchars($matches[1]); $title = htmlspecialchars($matches[3]); + return '' . $alt . ''; } // if we reach this point, it must have been an accident. @@ -574,4 +575,4 @@ public function indentedText($matches) } $form = new \YesWiki\WikiniFormatter($this); -echo $form->format($text); \ No newline at end of file +echo $form->format($text); diff --git a/handlers/DuplicateHandler.php b/handlers/DuplicateHandler.php new file mode 100644 index 000000000..c3829555d --- /dev/null +++ b/handlers/DuplicateHandler.php @@ -0,0 +1,143 @@ +authController = $this->getService(AuthController::class); + $this->entryController = $this->getService(EntryController::class); + $this->duplicationManager = $this->getService(DuplicationManager::class); + $title = $error = ''; + $toExternalWiki = isset($_GET['toUrl']) && $_GET['toUrl'] == '1'; + if (!$this->wiki->page) { + $error .= $this->render('@templates\alert-message.twig', [ + 'type' => 'warning', + 'message' => str_replace( + ['{beginLink}', '{endLink}'], + ["wiki->href('')}\">", ''], + _t('NOT_FOUND_PAGE') + ), + ]); + } elseif (!$this->getService(AclService::class)->hasAccess('read', $this->wiki->GetPageTag())) { + // if no read access to the page + if ($content = $this->getService(PageManager::class)->getOne('PageLogin')) { + // si une page PageLogin existe, on l'affiche + $error .= $this->wiki->Format($content['body']); + } else { + // sinon on affiche le formulaire d'identification minimal + $error .= '
' . "\n" + . '
' . "\n" + . _t('LOGIN_NOT_AUTORIZED') . '. ' . _t('LOGIN_PLEASE_REGISTER') . '.' . "\n" + . '
' . "\n" + . $this->wiki->Format('{{login signupurl="0"}}' . "\n\n") + . '
' . "\n"; + } + } elseif (!empty($_POST)) { + try { + $data = $this->duplicationManager->checkPostData($_POST); + $this->duplicationManager->duplicateLocally($data); + if ($data['duplicate-action'] == 'edit') { + $this->wiki->Redirect($this->wiki->href('edit', $data['newTag'])); + + return; + } elseif ($data['duplicate-action'] == 'return') { + $this->wiki->Redirect($this->wiki->href()); + + return; + } + $this->wiki->Redirect($this->wiki->href('', $data['newTag'])); + + return; + } catch (Throwable $th) { + $error .= $this->render('@templates\alert-message-with-back.twig', [ + 'type' => 'warning', + 'message' => $th->getMessage(), + ]); + } + } elseif (!$toExternalWiki && !$this->wiki->UserIsAdmin()) { + $error .= $this->render('@templates\alert-message-with-back.twig', [ + 'type' => 'warning', + 'message' => _t('ONLY_ADMINS_CAN_DUPLICATE') . '.', + ]); + } elseif ($this->getService(AclService::class)->hasAccess('read', $this->wiki->GetPageTag())) { + $isEntry = $this->getService(EntryManager::class)->isEntry($this->wiki->GetPageTag()); + $isList = $this->getService(ListManager::class)->isList($this->wiki->GetPageTag()); + $type = $isEntry ? 'entry' : ($isList ? 'list' : 'page'); + $pageTitle = ''; + if ($isEntry) { + $title = _t('TEMPLATE_DUPLICATE_ENTRY') . ' ' . $this->wiki->GetPageTag(); + $originalContent = $this->getService(EntryManager::class)->getOne($this->wiki->GetPageTag()); + if ($toExternalWiki) { + $pageTitle = $originalContent['bf_titre']; + $proposedTag = $this->wiki->GetPageTag(); + $originalContent = $this->wiki->page['body']; + $form = $this->getService(FormManager::class)->getOne($this->getService(EntryManager::class)->getOne($proposedTag)['id_typeannonce']); + } else { + $pageTitle = $originalContent['bf_titre'] . ' (' . _t('DUPLICATE') . ')'; + $proposedTag = genere_nom_wiki($pageTitle); + } + } elseif ($isList) { + $title = _t('TEMPLATE_DUPLICATE_LIST') . ' ' . $this->wiki->GetPageTag(); + $originalContent = $this->getService(ListManager::class)->getOne($this->wiki->GetPageTag()); + if ($toExternalWiki) { + $pageTitle = $originalContent['titre_liste']; + $proposedTag = $this->wiki->GetPageTag(); + } else { + $pageTitle = $originalContent['titre_liste'] . ' (' . _t('DUPLICATE') . ')'; + $proposedTag = genere_nom_wiki('Liste ' . $pageTitle); + } + } else { // page + $title = _t('TEMPLATE_DUPLICATE_PAGE') . ' ' . $this->wiki->GetPageTag(); + if ($toExternalWiki) { + $proposedTag = $this->wiki->GetPageTag(); + } else { + $proposedTag = genere_nom_wiki($this->wiki->GetPageTag() . ' ' . _t('DUPLICATE')); + } + $originalContent = $this->wiki->page['body']; + } + $attachments = $this->duplicationManager->findFiles($this->wiki->page['tag']); + $totalSize = 0; + foreach ($attachments as $a) { + $totalSize = $totalSize + $a['size']; + } + } + + if ($toExternalWiki) { + $title .= ' ' . _t('TO_ANOTHER_YESWIKI'); + } + // in ajax request for modal, no title + if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { + $title = ''; + } + + return $this->renderInSquelette('@core/handlers/duplicate.twig', [ + 'title' => $title, + 'originalTag' => $this->wiki->GetPageTag(), + 'error' => $error, + 'sourceUrl' => $this->wiki->href(), + 'proposedTag' => $proposedTag ?? '', + 'attachments' => $attachments ?? [], + 'pageTitle' => $pageTitle ?? '', + 'originalContent' => $originalContent ?? '', + 'totalSize' => $this->duplicationManager->humanFilesize($totalSize ?? 0), + 'type' => $type ?? '', + 'form' => $form ?? '', + 'baseUrl' => preg_replace('/\?$/Ui', '', $this->wiki->config['base_url']), + 'toExternalWiki' => $toExternalWiki, + ]); + } +} diff --git a/includes/YesWiki.php b/includes/YesWiki.php index b72416bf8..a4b12b2dc 100755 --- a/includes/YesWiki.php +++ b/includes/YesWiki.php @@ -79,6 +79,7 @@ public function __construct($config = []) $this->services = $init->initCoreServices($this); $this->loadExtensions(); + $this->routes = $init->initRoutes($this); } @@ -1243,7 +1244,7 @@ public function Run($tag = '', $method = '') unset($_SESSION['redirects']); } // do nothing except and script with message - exit($th->getMessage); + exit($th->getMessage()); } } diff --git a/includes/YesWikiMigration.php b/includes/YesWikiMigration.php index 6f1ca4f25..0600925ad 100644 --- a/includes/YesWikiMigration.php +++ b/includes/YesWikiMigration.php @@ -39,4 +39,4 @@ protected function getService(string $className) { return $this->wiki->services->get($className); } -} \ No newline at end of file +} diff --git a/includes/controllers/ApiController.php b/includes/controllers/ApiController.php index d13aa97de..ffdd0bdfa 100644 --- a/includes/controllers/ApiController.php +++ b/includes/controllers/ApiController.php @@ -18,12 +18,12 @@ use YesWiki\Core\Service\CommentService; use YesWiki\Core\Service\DbService; use YesWiki\Core\Service\DiffService; +use YesWiki\Core\Service\DuplicationManager; use YesWiki\Core\Service\PageManager; use YesWiki\Core\Service\ReactionManager; use YesWiki\Core\Service\TripleStore; use YesWiki\Core\Service\UserManager; use YesWiki\Core\YesWikiController; -use YesWiki\Security\Controller\SecurityController; class ApiController extends YesWikiController { @@ -44,9 +44,15 @@ public function getDocumentation() $urlPages = $this->wiki->Href('', 'api/pages'); $output .= '

' . _t('PAGES') . '

' . "\n" . - '

GET ' . $urlPages . '

'; - $urlPagesComments = $this->wiki->Href('', 'api/pages/{pageTag}/comments'); - $output .= '

GET ' . $urlPagesComments . '

'; + '

GET ' . $urlPages . '
Get all pages

'; + $urlPages = $this->wiki->Href('', 'api/pages/{pageTag}'); + $output .= '

GET ' . $urlPages . '
Get indicated page\'s informations, with raw and html contents

'; + + $urlPages = $this->wiki->Href('', 'api/pages/{pageTag}/comments'); + $output .= '

GET ' . $urlPages . '
Get indicated page\'s comments

'; + + $urlPages = $this->wiki->Href('', 'api/pages/{pageTag}/duplicate'); + $output .= '

POST ' . $urlPages . '
Duplicate an external page into this YesWiki pageTag

'; $urlComments = $this->wiki->Href('', 'api/comments'); $output .= '

' . _t('COMMENTS') . '

' . "\n" . @@ -65,7 +71,6 @@ public function getDocumentation() '

POST ' . $urlArchives . '/{id}

'; // TODO use annotations to document the API endpoints - $extensions = $this->wiki->extensions; foreach ($this->wiki->extensions as $extension => $pluginBase) { $response = null; if (file_exists($pluginBase . 'controllers/ApiController.php')) { @@ -179,7 +184,7 @@ public function createUser() $user = $userController->create([ 'name' => strval($_POST['name']), 'email' => strval($_POST['email']), - 'password' => $this->wiki->generateRandomString(30) + 'password' => $this->wiki->generateRandomString(30), ]); if (!boolval($this->wiki->config['contact_disable_email_for_password']) && !empty($user)) { $link = $userController->sendPasswordRecoveryEmail($user); @@ -193,7 +198,7 @@ public function createUser() 'name' => $user['name'], 'email' => $user['email'], 'signuptime' => $user['signuptime'], - 'link' => $link + 'link' => $link, ], ]; } catch (UserNameAlreadyUsedException $th) { @@ -382,6 +387,22 @@ public function getPage(Request $request, $tag) return new ApiResponse($page); } + /** + * @Route("/api/pages/{tag}/duplicate",methods={"POST"},options={"acl":{"public","@admins"}}) + */ + public function duplicatePage(Request $request, $tag) + { + $this->denyAccessUnlessAdmin(); + $duplicationManager = $this->getService(DuplicationManager::class); + try { + $duplicationManager->importDistantContent($tag, $request); + } catch (\Throwable $th) { + return new ApiResponse($th->getMessage(), Response::HTTP_FORBIDDEN); + } + + return new ApiResponse($request->request->all(), Response::HTTP_OK); + } + /** * @Route("/api/pages/{tag}",methods={"DELETE"},options={"acl":{"public","+"}}) */ @@ -820,11 +841,14 @@ private function extractTriplesParams(string $method, $resource): array Response::HTTP_BAD_REQUEST ); } else { - $property = $this->getService(SecurityController::class)->filterInput($method, 'property', FILTER_DEFAULT, true); + $property = filter_input($method, 'property', FILTER_UNSAFE_RAW); + $property = in_array($property, [false, null], true) ? '' : htmlspecialchars(strip_tags($property)); if (empty($property)) { $property = null; } - $username = $this->getService(SecurityController::class)->filterInput($method, 'user', FILTER_DEFAULT, true); + + $username = filter_input($method, 'user', FILTER_UNSAFE_RAW); + $username = in_array($username, [false, null], true) ? '' : htmlspecialchars(strip_tags($username)); if (empty($username)) { if (!$this->wiki->UserIsAdmin()) { $username = $this->getService(AuthController::class)->getLoggedUser()['name']; diff --git a/includes/controllers/AuthController.php b/includes/controllers/AuthController.php index 2db97a7f7..490c05f08 100644 --- a/includes/controllers/AuthController.php +++ b/includes/controllers/AuthController.php @@ -155,10 +155,12 @@ public function connectUser() // connect in SESSION $this->login($data['user'], $data['remember'] ? 1 : 0); } catch (BadUserConnectException $th) { - if (empty($_SESSION['user']['name']) || + if ( + empty($_SESSION['user']['name']) || empty($data['user']['name']) || $data['user']['name'] != $_SESSION['user']['name'] || - !$this->wiki->UserIsAdmin($data['user']['name'])) { + !$this->wiki->UserIsAdmin($data['user']['name']) + ) { // do not disconnect admin during update $this->logout(); } diff --git a/includes/controllers/PageController.php b/includes/controllers/PageController.php index 08e954018..45569b860 100644 --- a/includes/controllers/PageController.php +++ b/includes/controllers/PageController.php @@ -46,4 +46,13 @@ public function delete(string $tag): bool return true; } } + + public function duplicate(string $sourceTag, string $destinationTag = ''): bool + { + if ($this->entryManager->isEntry($sourceTag)) { + return $this->entryController->duplicate($sourceTag, $destinationTag); + } else { + return $this->pageManager->duplicate($sourceTag, $destinationTag); + } + } } diff --git a/includes/controllers/UserController.php b/includes/controllers/UserController.php index 8af9d5f50..41beb85a9 100644 --- a/includes/controllers/UserController.php +++ b/includes/controllers/UserController.php @@ -103,14 +103,14 @@ public function create(array $newValues): ?User return null; } - + public function sendPasswordRecoveryEmail(User $user): string { if ($this->userManager->sendPasswordRecoveryEmail($user, _t('LOGIN_PASSWORD_FOR'))) { return $this->userManager->getUserLink(); } else { - return ""; - } + return ''; + } } /** diff --git a/includes/migrations/20240502083251_RefactorListStruture.php b/includes/migrations/20240502083251_RefactorListStruture.php index 55c5e4da0..1a14222ae 100644 --- a/includes/migrations/20240502083251_RefactorListStruture.php +++ b/includes/migrations/20240502083251_RefactorListStruture.php @@ -23,4 +23,4 @@ public function run() $pageManager->save($tag, json_encode($newJson)); } } -} \ No newline at end of file +} diff --git a/includes/services/DuplicationManager.php b/includes/services/DuplicationManager.php new file mode 100644 index 000000000..053bc7bc1 --- /dev/null +++ b/includes/services/DuplicationManager.php @@ -0,0 +1,357 @@ +wiki = $wiki; + $this->uploadPath = $this->getLocalFileUploadPath(); + } + + /** + * Get the local path to files uploads (usually "files"). + * + * @return string local path to files uploads + */ + private function getLocalFileUploadPath() + { + $attachConfig = $this->wiki->config['attach_config']; + + if (!is_array($attachConfig)) { + $attachConfig = []; + } + + if (empty($attachConfig['upload_path'])) { + $this->uploadPath = 'files'; + } else { + $this->uploadPath = $attachConfig['upload_path']; + } + + return $this->uploadPath; + } + + /** + * Return fields that may contain attachments to import (fichier, image, or textelong fields for bazar entries). + * + * @param array $id + * + * @return array keys of fields that may contain attachments to import + */ + private function getUploadFieldsFromEntry($id) + { + $fields = []; + $entry = $this->wiki->services->get(EntryManager::class)->getOne($id); + if (!empty($entry['id_fiche'])) { // bazar entry + $formManager = $this->wiki->services->get(FormManager::class); + $form = $formManager->getOne($entry['id_typeannonce']); + // find fields that are textareas + foreach ($form['prepared'] as $field) { + if ($field instanceof TextareaField || $field instanceof ImageField || $field instanceof FileField) { + $fields[] = $field; + } + } + } + + return $fields; + } + + private function findFilesInUploadField($fieldValue) + { + $f = $this->uploadPath . '/' . $fieldValue; + if ($f !== $this->uploadPath . '/' && file_exists($f)) { + $size = filesize($f); + $humanSize = $this->humanFilesize($size); + + return ['path' => $f, 'size' => $size, 'humanSize' => $humanSize]; + } else { + return []; + } + } + + /** + * find files in wiki text. + * + * @param string $wikiTag + * @param string $wikiText + * + * @return array files + */ + private function findFilesInWikiText($tag, $wikiText) + { + $filesMatched = []; + $regex = '#\{\{attach.*file="(.*)".*\}\}#Ui'; + preg_match_all( + $regex, + $wikiText, + $attachments + ); + if (is_array($attachments[1])) { + foreach ($attachments[1] as $a) { + $ext = pathinfo($a, PATHINFO_EXTENSION); + $filename = pathinfo($a, PATHINFO_FILENAME); + $searchPattern = '`^' . $tag . '_' . $filename . '_\d{14}_(\d{14})\.' . $ext . '_?$`'; + $path = $this->getLocalFileUploadPath(); + $fh = opendir($path); + while (($file = readdir($fh)) !== false) { + if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0 || is_dir($file)) { + continue; + } + if (preg_match($searchPattern, $file, $matches)) { + $filePath = $path . '/' . $file; + $size = filesize($filePath); + $humanSize = $this->humanFilesize($size); + if (in_array($filename, array_keys($filesMatched)) && $matches[1] < $filesMatched[$filename]['modified']) { + continue; // we only take the latest modified version of file + } + $filesMatched[$filename] = ['path' => $filePath, 'size' => $size, 'humanSize' => $humanSize, 'modified' => $matches[1]]; + } + } + } + } + $fileUrlRegex = '#' . preg_quote(str_replace('?', '', $this->wiki->config['base_url']), '#') . + '(' . $this->uploadPath . '/.*\.[a-zA-Z0-9]{1,16}\b([-a-zA-Z0-9!@:%_\+.~\#?&\/\/=]*))#Ui'; + preg_match_all( + $fileUrlRegex, + $wikiText, + $fileUrls + ); + foreach ($fileUrls[1] as $f) { + if (file_exists($f)) { + $size = filesize($f); + $humanSize = $this->humanFilesize($size); + $filesMatched[] = ['path' => $f, 'size' => $size, 'humanSize' => $humanSize]; + } + } + + return $filesMatched; + } + + /** + * Get file attachements from newTag. + * + * @param string $tag page id + * + * @return array attachments filenames + */ + public function findFiles($tag = '') + { + $files = []; + if (empty(trim($tag))) { + $tag = $this->wiki->GetPageTag(); + } + if ($this->wiki->services->get(EntryManager::class)->isEntry($tag)) { + // bazar + $fields = $this->getUploadFieldsFromEntry($tag); + $entry = $this->wiki->services->get(EntryManager::class)->getOne($tag); + foreach ($fields as $f) { + if ($f instanceof ImageField || $f instanceof FileField) { + if (!empty($fi = $this->findFilesInUploadField($entry[$f->getPropertyName()]))) { + $files[] = $fi; + } + } elseif ($f instanceof TextareaField) { + if (!empty($fi = $this->findFilesInWikiText($tag, $entry[$f->getPropertyName()]))) { + $files = array_merge($files, $fi); + } + } + } + } elseif (!$this->wiki->services->get(ListManager::class)->isList($tag)) { // page + $wikiText = $this->wiki->services->get(PageManager::class)->getOne($tag)['body']; + if ($fi = $this->findFilesInWikiText($tag, $wikiText)) { + $files = array_merge($files, $fi); + } + } + + return $files; + } + + public function duplicateFiles($fromTag, $toTag) + { + $files = $this->findFiles($fromTag); + $doneFiles = []; + foreach ($files as $f) { + $newPath = preg_replace( + '~' . $this->uploadPath . '/' . preg_quote($fromTag, '~') . '_~Ui', + $this->uploadPath . '/' . $toTag . '_', + $f['path'] + ); + // if the file name has not changed, we add newPageTag_ as filename prefix + if ($f['path'] == $newPath) { + $newPath = str_replace($this->uploadPath . '/', $this->uploadPath . '/' . $toTag . '_', $newPath); + } + copy($f['path'], $newPath); + $doneFiles[] = [ + 'originalFile' => str_replace($this->uploadPath . '/', '', $f['path']), + 'duplicatedFile' => str_replace($this->uploadPath . '/', '', $newPath), + ]; + } + + return $doneFiles; + } + + public function checkPostData($data) + { + if (empty($data['type']) || !in_array($data['type'], ['form', 'page', 'list', 'entry'])) { + throw new \Exception(_t('NO_VALID_DATA_TYPE')); + } + if (empty($data['newTag'])) { + throw new \Exception(_t('EMPTY_PAGE_TAG')); + } + if ($data['type'] != 'page' && empty($data['newTitle'])) { + throw new \Exception(_t('EMPTY_PAGE_TITLE')); + } + if (!$this->wiki->UserIsAdmin()) { + throw new \Exception(_t('ONLY_ADMINS_CAN_DUPLICATE') . '.'); + } + $page = $this->wiki->services->get(PageManager::class)->getOne($data['newTag']); + if ($page) { + throw new \Exception($data['newTag'] . ' ' . _t('ALREADY_EXISTING')); + } + if (empty($data['duplicate-action']) || !in_array($data['duplicate-action'], ['open', 'edit', 'return'])) { + throw new \Exception(_t('NO_DUPLICATE_ACTION') . '.'); + } + + return $data; + } + + public function duplicateLocally($data) + { + if (!$this->wiki->UserIsAdmin()) { + throw new \Exception(_t('ONLY_ADMINS_CAN_DUPLICATE') . '.'); + } + switch ($data['type']) { + case 'list': + $list = $this->wiki->services->get(ListManager::class)->getOne($data['originalTag']); + $this->wiki->services->get(ListManager::class)->create($data['newTitle'], $list['label'], $data['newTag']); + break; + + case 'entry': + $files = $this->duplicateFiles($data['originalTag'], $data['newTag']); + $entry = $this->wiki->services->get(EntryManager::class)->getOne($this->wiki->getPageTag()); + $fields = $this->getUploadFieldsFromEntry($this->wiki->GetPageTag()); + foreach ($fields as $f) { + foreach ($files as $fi) { + $entry[$f->getPropertyName()] = str_replace($fi['originalFile'], $fi['duplicatedFile'], $entry[$f->getPropertyName()]); + } + } + $entry['id_fiche'] = $data['newTag']; + $entry['bf_titre'] = $data['newTitle']; + $entry['antispam'] = 1; + $this->wiki->services->get(EntryManager::class)->create($entry['id_typeannonce'], $entry); + break; + + default: + case 'page': + $newBody = $this->wiki->page['body']; + $files = $this->duplicateFiles($data['originalTag'], $data['newTag']); + foreach ($files as $f) { + $newBody = str_replace($f['originalFile'], $f['duplicatedFile'], $newBody); + } + $this->wiki->services->get(PageManager::class)->save($data['newTag'], $newBody); + break; + } + + // duplicate acls + foreach (['read', 'write', 'comment'] as $privilege) { + $values = $this->wiki->services->get(AclService::class)->load( + $this->wiki->getPageTag(), + $privilege + ); + + $this->wiki->services->get(AclService::class)->save( + $data['newTag'], + $privilege, + $values['list'] + ); + } + + // duplicate metadatas and tags (TODO: is there more duplicable triples?) + $properties = [ + 'http://outils-reseaux.org/_vocabulary/metadata', + 'http://outils-reseaux.org/_vocabulary/tag', + ]; + foreach ($properties as $prop) { + $values = $this->wiki->services->get(TripleStore::class)->getAll($data['originalTag'], $prop, '', ''); + foreach ($values as $val) { + $this->wiki->services->get(TripleStore::class)->create($data['newTag'], $prop, $val['value'], '', ''); + } + } + } + + public function importDistantContent($tag, $request) + { + if ($this->wiki->services->get(PageManager::class)->getOne($tag)) { + throw new Exception(_t('ACEDITOR_LINK_PAGE_ALREADY_EXISTS')); + } + $req = $request->request->all(); + foreach (['originalContent', 'sourceUrl', 'originalTag', 'type'] as $key) { + if (empty($req[$key])) { + throw new Exception(_t('NOT_FOUND_IN_REQUEST', $key)); + } + } + foreach ($req['files'] as $fileUrl) { + $this->downloadFile($fileUrl, $req['originalTag'], $tag); + } + + $newUrl = explode('/?', $this->wiki->config['base_url'])[0]; + $newBody = str_replace($req['sourceUrl'], $newUrl, $req['originalContent']); + if ($req['type'] === 'page') { + $this->wiki->services->get(PageManager::class)->save($tag, $newBody); + } elseif ($req['type'] === 'entry') { + $entry = json_decode($newBody, true); + $entry['id_fiche'] = $tag; + $entry['antispam'] = 1; + $this->wiki->services->get(EntryManager::class)->create($entry['id_typeannonce'], $entry, false, $req['sourceUrl']); + } + } + + public function downloadFile($sourceUrl, $fromTag, $toTag, $timeoutInSec = 10) + { + $t = explode('/', $sourceUrl); + $fileName = array_pop($t); + $destPath = 'files/' . str_replace($fromTag, $toTag, $fileName); + $fp = fopen($destPath, 'wb'); + $ch = curl_init($sourceUrl); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_HEADER, 0); + // TODO: make options to allow ssl verify + curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeoutInSec); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeoutInSec); + curl_exec($ch); + curl_close($ch); + fclose($fp); + + return $destPath; + } + + public function humanFilesize($bytes, $decimals = 2) + { + $factor = floor((strlen($bytes) - 1) / 3); + if ($factor > 0) { + $sz = 'KMGT'; + } + + return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor - 1] . 'B'; + } +} diff --git a/includes/services/PageManager.php b/includes/services/PageManager.php index 59f0c347a..0b8a8cf12 100644 --- a/includes/services/PageManager.php +++ b/includes/services/PageManager.php @@ -407,8 +407,8 @@ public function getOwner($tag = '', $time = '') $timeQuery = $time ? "time = '{$this->dbService->escape($time)}'" : "latest = 'Y'"; $page = $this->dbService->loadSingle( "SELECT `owner` FROM {$this->dbService->prefixTable('pages')} " . - "WHERE tag = '{$this->dbService->escape($tag)}' AND {$timeQuery} " . - 'LIMIT 1' + "WHERE tag = '{$this->dbService->escape($tag)}' AND {$timeQuery} " . + 'LIMIT 1' ); $this->ownersCache[$tag] = $page['owner'] ?? null; } @@ -499,11 +499,19 @@ private function checkEntriesACL(array $pages, ?string $tag = null, ?string $use } $pages = array_map(function ($page) use ($guard, $allEntriesTags, $userNameForCheckingACL) { return (isset($page['tag']) && - in_array($page['tag'], $allEntriesTags) + in_array($page['tag'], $allEntriesTags) ) ? $guard->checkAcls($page, $page['tag'], $userNameForCheckingACL) - : $page; + : $page; }, $pages); return $pages; } + + private function duplicate($sourceTag, $destinationTag): bool + { + $result = false; + $this->wiki->LogAdministrativeAction($this->authController->getLoggedUserName(), 'Duplication de la page ""' . $sourceTag . '"" vers la page ""' . $destinationTag . '""'); + + return $result; + } } diff --git a/includes/services/UserManager.php b/includes/services/UserManager.php index 047a70154..c7c668b46 100644 --- a/includes/services/UserManager.php +++ b/includes/services/UserManager.php @@ -19,7 +19,7 @@ use YesWiki\Security\Controller\SecurityController; use YesWiki\Wiki; -if (! function_exists('send_mail')) { +if (!function_exists('send_mail')) { require_once 'includes/email.inc.php'; } @@ -49,7 +49,7 @@ public function __construct( $this->securityController = $securityController; $this->params = $params; $this->getOneByNameCacheResults = []; - $this->userlink = ""; + $this->userlink = ''; } private function arrayToUser(?array $userAsArray = null, bool $fillEmpty = false): ?User @@ -209,7 +209,7 @@ protected function generateUserLink($user) $this->userlink = $this->wiki->Href('', 'MotDePassePerdu', [ 'a' => 'recover', 'email' => $key, - 'u' => base64_encode($user['name']) + 'u' => base64_encode($user['name']), ], false); } @@ -242,9 +242,7 @@ public function sendPasswordRecoveryEmail(User $user, string $title): bool } /** - * Assessor for userlink field - * - * @return string + * Assessor for userlink field. */ public function getUserLink(): string { @@ -252,9 +250,7 @@ public function getUserLink(): string } /** - * Assessor for userlink field - * - * @return string + * Assessor for userlink field. */ public function getLastUserLink(User $user): string { @@ -264,11 +260,12 @@ public function getLastUserLink(User $user): string $this->userlink = $this->wiki->Href('', 'MotDePassePerdu', [ 'a' => 'recover', 'email' => $key, - 'u' => base64_encode($user['name']) + 'u' => base64_encode($user['name']), ], false); } else { $this->generateUserLink($user); } + return $this->userlink; } @@ -518,4 +515,4 @@ public function logout() { $this->wiki->services->get(AuthController::class)->logout(); } -} \ No newline at end of file +} diff --git a/index.php b/index.php index 92ad9acdf..8b2fe5c16 100755 --- a/index.php +++ b/index.php @@ -1,4 +1,5 @@ arr.some((i) => i.id === v.id && i.type === v.type)) +} + +function blockDuplicationName(tag) { + $('[name=duplicate-action]').attr('disabled', 'disabled').addClass('disabled') + $('#newTag').parents('.form-group').removeClass('has-success').addClass('has-error') + $('#pagetag-message').html(_t('PAGE_NOT_AVAILABLE', { tag })) +} + +function validateDuplicationName(tag) { + $('[name=duplicate-action]').removeAttr('disabled').removeClass('disabled') + $('#newTag').parents('.form-group').removeClass('has-error').addClass('has-success') + $('#pagetag-message').html(_t('PAGE_AVAILABLE', { tag })) +} + +function checkPageExistence(url) { + $.ajax({ + method: 'GET', + url + }).done(() => { + blockDuplicationName(url.replace(`${shortUrl}/?api/pages/`, '')) + }).fail((jqXHR) => { + if (jqXHR.status === 404) { + validateDuplicationName(url.replace(`${shortUrl}/?api/pages/`, '')) + } else { + blockDuplicationName(url.replace(`${shortUrl}/?api/pages/`, '')) + } + }) +} + +function handleLoginResponse(data) { + if (data.isAdmin === true) { + $('#login-message').html(_t('CONNECTED_AS_ADMIN', { user: data.user })).parents('.form-group') + .removeClass('has-error') + .addClass('has-success') + $('.login-fields').addClass('hide') + $('.duplication-fields').removeClass('hide') + checkPageExistence(`${shortUrl}/?api/pages/${$('#newTag').val()}`) + } else { + $('#login-message').html(_t('CONNECTED_BUT_NOT_ADMIN', { user: data.user })).parents('.form-group') + .removeClass('has-success') + .addClass('has-error') + $('.duplication-fields').addClass('hide') + $('.login-fields').removeClass('hide') + } +} + +document.addEventListener('DOMContentLoaded', () => { + $('.duplication-wiki-form, .duplication-login-form, #form-duplication').on('submit', (e) => { + e.stopPropagation() + return false + }) + $('#url-wiki').on('change', () => { + $('.login-fields, .duplication-fields').addClass('hide') + $('#login-message').html('') + }) + + $('.btn-distant-login').on('click', () => { + $.ajax({ + method: 'POST', + url: `${shortUrl}/?api/login`, + data: { + username: $('#username').val(), + password: $('#password').val() + } + }).done((data) => { + handleLoginResponse(data) + }).fail((jqXHR) => { + toastMessage(jqXHR.responseJSON.error, 3000, 'alert alert-danger') + if (jqXHR.status === 401) { + $('#login-message').html(`
${_t('NOT_CONNECTED')}
`) + $('.login-fields').removeClass('hide') + } + }) + return false + }) + + $('[name="duplicate-action"]').on('click', (e) => { + const btnAction = e.currentTarget.value + $.ajax({ + method: 'POST', + url: `${shortUrl}/?api/pages/${$('#newTag').val()}/duplicate`, + data: $('#form-duplication').serialize() + }).done((d) => { + if (btnAction === 'open') { + document.location = `${shortUrl}/?${d.newTag}` + } else if (btnAction === 'edit') { + document.location = `${shortUrl}/?${d.newTag}/edit` + } else { + const url = document.location.href.replace(/\/duplicate.*/, '') + document.location = url + } + }).fail((jqXHR) => { + toastMessage(`${_t('ERROR')} ${jqXHR.status}`, 3000, 'alert alert-danger') + }) + return false + }) + + $('.btn-verify-tag').on('click', () => { + checkPageExistence(`${shortUrl}/?api/pages/${$('#newTag').val()}`) + }) + + $('.btn-verify-wiki').on('click', () => { + let url = $('.duplication-wiki-form').find('#url-wiki').val() + + if (isValidUrl(url)) { + let taburl = [] + if (url.search('wakka.php') > -1) { + taburl = url.split('wakka.php') + } else { + taburl = url.split('?') + } + shortUrl = taburl[0].replace(/\/+$/g, '') + $('#base-url').text(`${shortUrl}/?`) + url = `${shortUrl}/?api/auth/me` + $.ajax({ + method: 'GET', + url + }).done((data) => { + handleLoginResponse(data) + + // if case of entry, we need to check if form id is available and compatible + // or propose another id + const formId = $('#form-id').val() + if (typeof formId !== 'undefined') { + const formUrl = `${shortUrl}/?api/forms/${formId}` + $.ajax({ + method: 'GET', + url: formUrl + }).done((form) => { + const requiredFields = form.prepared.filter((field) => field.required === true) + // we check if the found formId is compatible + if (arrayIncludesAllRequiredFields(window.sourceForm.prepared, requiredFields)) { + $('#form-message').removeClass('has-error').addClass('has-success').find('.help-block') + .html(_t('FORM_ID_IS_COMPATIBLE', { id: formId })) + } else { + $('#form-message').removeClass('has-success').addClass('has-error').find('.help-block') + .html(_t('FORM_ID_NOT_AVAILABLE', { id: formId })) + } + }).fail((jqXHR) => { + if (jqXHR.status === 404) { + // the formId is available + $('#form-message').removeClass('has-error').addClass('has-success').find('.help-block') + .html(_t('FORM_ID_AVAILABLE', { id: formId })) + } + }) + } + }).fail((jqXHR) => { + if (jqXHR.status === 401) { + $('#login-message').html(`
${_t('NOT_CONNECTED')}
`) + $('.login-fields').removeClass('hide') + } else { + toastMessage(_t('NOT_WIKI_OR_OLD_WIKI', { url }), 3000, 'alert alert-danger') + } + }) + } else { + toastMessage(_t('NOT_VALID_URL', { url }), 3000, 'alert alert-danger') + } + }) +}) diff --git a/javascripts/users-table.js b/javascripts/users-table.js index 3dc85030a..2a458ff01 100644 --- a/javascripts/users-table.js +++ b/javascripts/users-table.js @@ -35,7 +35,7 @@ const usersTableService = { '' ]).draw() if (userLink !== '') { - $(`#users-table-link-change-password`).html("

"+userLink+"") + $('#users-table-link-change-password').html(`

${userLink}`) } toastMessage(_t('USERSTABLE_USER_CREATED', { name: userName }), 1100, 'alert alert-success') }, diff --git a/javascripts/yeswiki-base.js b/javascripts/yeswiki-base.js index 542fb9624..558d6ad7d 100755 --- a/javascripts/yeswiki-base.js +++ b/javascripts/yeswiki-base.js @@ -921,4 +921,4 @@ $('#yw-a11y-jump-content').click(() => { setTimeout(() => { $('#yw-topnav').removeClass('nav-down').addClass('nav-up') }, 300) -}) \ No newline at end of file +}) diff --git a/lang/yeswiki_ca.php b/lang/yeswiki_ca.php index 65c0a554a..ac905b9f9 100644 --- a/lang/yeswiki_ca.php +++ b/lang/yeswiki_ca.php @@ -1,4 +1,5 @@ 'Sauvegardes', diff --git a/lang/yeswiki_en.php b/lang/yeswiki_en.php index 8eac91d7c..9f9bee6b0 100644 --- a/lang/yeswiki_en.php +++ b/lang/yeswiki_en.php @@ -1,4 +1,5 @@ 'Sauvegardes', diff --git a/lang/yeswiki_fr.php b/lang/yeswiki_fr.php index 906f3fc98..712f19e43 100644 --- a/lang/yeswiki_fr.php +++ b/lang/yeswiki_fr.php @@ -1,4 +1,5 @@ 'Sauvegardes', @@ -629,4 +630,25 @@ 'REACTION_TITLE_PARAM_NEEDED' => 'Le paramètre \'titre\' est obligatoire', 'REACTION_BAD_IMAGE_FORMAT' => 'Mauvais format d\'image : doit être un fichier, un icône utf8 ou une classe Fontawesome', 'REACTION_NO_IMAGE' => 'Image manquante', -]; \ No newline at end of file + + // Duplication + 'DUPLICATE' => 'copie', + 'FILES_TO_DUPLICATE' => 'Fichiers à dupliquer', + 'TOTAL_SIZE' => 'taille totale', + 'DUPLICATE_AND_OPEN' => 'Dupliquer et afficher', + 'DUPLICATE_AND_EDIT' => 'Dupliquer et éditer', + 'DUPLICATE_AND_RETURN' => 'Dupliquer et retourner sur la page source', + 'NO_DUPLICATE_ACTION' => 'Pas d\'action après duplication indiquée (duplicate-action)', + 'PAGE_TITLE_TO_DUPLICATE' => 'Titre après duplication', + 'PAGE_TAG_TO_DUPLICATE' => 'Identifiant de la page dupliquée', + 'NO_VALID_DATA_TYPE' => 'Pas de type de données valide', + 'EMPTY_PAGE_TAG' => 'L\'identifiant ne peut pas être vide', + 'EMPTY_PAGE_TITLE' => 'Le titre ne peut pas être vide', + 'TO_ANOTHER_YESWIKI' => 'vers un autre YesWiki', + 'WIKI_URL' => 'Url du YesWiki de destination', + 'WIKI_URL_RECENT' => 'Entrez l\'url d\'un YesWiki version > 4.5.0 pour que la duplication puisse fonctionner', + 'VERIFY_WIKI' => 'Vérifier cette adresse', + 'VERIFY_PAGE_AVAILABILITY' => 'Vérifier la disponibilité de la page', + 'ONLY_ADMINS_CAN_DUPLICATE' => 'Seuls les membres du groupe "admins" de ce wiki peuvent dupliquer localement', + 'DISTANT_LOGIN' => 'Se connecter sur le YesWiki', +]; diff --git a/lang/yeswiki_nl.php b/lang/yeswiki_nl.php index 8d165a489..9e952be15 100644 --- a/lang/yeswiki_nl.php +++ b/lang/yeswiki_nl.php @@ -1,4 +1,5 @@ 'Sauvegardes', diff --git a/lang/yeswiki_pt.php b/lang/yeswiki_pt.php index 233dafdd9..f012df3ac 100644 --- a/lang/yeswiki_pt.php +++ b/lang/yeswiki_pt.php @@ -1,4 +1,5 @@ 'Sauvegardes', diff --git a/lang/yeswiki_rom.php b/lang/yeswiki_rom.php index e9b522a3e..52775c980 100644 --- a/lang/yeswiki_rom.php +++ b/lang/yeswiki_rom.php @@ -1,4 +1,5 @@ '', 'USER_YOU_MUST_SPECIFY_A_NAME' => '', diff --git a/lang/yeswiki_ta.php b/lang/yeswiki_ta.php index fb04f016e..d5ffd7c3b 100644 --- a/lang/yeswiki_ta.php +++ b/lang/yeswiki_ta.php @@ -1,4 +1,5 @@ 'நோம்', 'ADMIN_BACKUPS_ARCHIVE_SIZE' => 'அளவு', diff --git a/lang/yeswikijs_en.php b/lang/yeswikijs_en.php index ee645a2be..be8f8b551 100644 --- a/lang/yeswikijs_en.php +++ b/lang/yeswikijs_en.php @@ -1,4 +1,5 @@ 'April', @@ -83,7 +84,7 @@ 'MULTIDELETE_END' => 'Deletions finished', 'MULTIDELETE_ERROR' => 'Item {itemId} has not been deleted! {error}', // javascripts/users-table.js - 'LINK_TO_CHANGE_PASSWORD' => "Link to change password", + 'LINK_TO_CHANGE_PASSWORD' => 'Link to change password', 'USERSTABLE_USER_CREATED' => "User '{name}' created", 'USERSTABLE_USER_NOT_CREATED' => "User '{name}' not created : {error}", 'USERSTABLE_USER_DELETED' => 'The user "{username}" was deleted.', diff --git a/lang/yeswikijs_fr.php b/lang/yeswikijs_fr.php index 7d78d6998..59c4ccbe2 100644 --- a/lang/yeswikijs_fr.php +++ b/lang/yeswikijs_fr.php @@ -113,7 +113,7 @@ 'MULTIDELETE_ERROR' => "L'élément {itemId} n'a pas été supprimé ! {error}", // javascripts/users-table.js - 'LINK_TO_CHANGE_PASSWORD' => "Lien pour changer le mot de passe", + 'LINK_TO_CHANGE_PASSWORD' => 'Lien pour changer le mot de passe', 'USERSTABLE_USER_CREATED' => "Utilisateur '{name}' créé", 'USERSTABLE_USER_NOT_CREATED' => "Utilisateur '{name}' non créé : {error}", 'USERSTABLE_USER_DELETED' => 'L\'utilisateur "{username}" a été supprimé.', @@ -150,4 +150,16 @@ // Doc 'DOC_EDIT_THIS_PAGE_ON_GITHUB' => 'Modifier cette page sur Github', + + // Duplication + 'NOT_VALID_URL' => 'Url non valide : {url}', + 'PAGE_AVAILABLE' => 'La page {tag} est disponible sur le YesWiki de destination', + 'PAGE_NOT_AVAILABLE' => 'La page {tag} n\'est pas disponible sur le YesWiki de destination', + 'NOT_CONNECTED' => 'Il faut se connecter au YesWiki de destination avec un compte disposant de droits d\'administration.', + 'CONNECTED_AS_ADMIN' => 'L\'utilisateurice {user} est bien connecté.e sur le YesWiki de destination, avec des droits d\'administration.', + 'CONNECTED_BUT_NOT_ADMIN' => 'L\'utilisateurice {user} est bien connecté.e sur le YesWiki de destination, mais n\'a pas les droits d\'administration. Veuillez-vous connecter avec un compte admin.', + 'NOT_WIKI_OR_OLD_WIKI' => 'Le site indiqué ne semble pas être un YesWiki, ou sa version est antérieure à 4.5.0', + 'FORM_ID_AVAILABLE' => 'Le formulaire avec l\'identifiant {id} n\'existant pas encore sur l\'url indiqué, il sera créé.', + 'FORM_ID_NOT_AVAILABLE' => 'Le formulaire avec l\'identifiant {id} n\'est plus disponible sur l\'url indiqué, il faut changer d\'identifiant.', + 'FORM_ID_IS_COMPATIBLE' => 'Un formulaire du même identifiant ({id}) existe sur l\'url indiqué et semble avoir au moins les champs obligatoires similaires. Il sera utilisé pour la duplication.', ]; diff --git a/lang/yeswikijs_nb_NO.php b/lang/yeswikijs_nb_NO.php index da5a37d48..62bfcc74f 100644 --- a/lang/yeswikijs_nb_NO.php +++ b/lang/yeswikijs_nb_NO.php @@ -1,4 +1,5 @@ '', diff --git a/lang/yeswikijs_ta.php b/lang/yeswikijs_ta.php index cf9756aab..f787df599 100644 --- a/lang/yeswikijs_ta.php +++ b/lang/yeswikijs_ta.php @@ -1,4 +1,5 @@ 'அவ்ரில்', diff --git a/templates/handlers/duplicate.twig b/templates/handlers/duplicate.twig new file mode 100644 index 000000000..50153e007 --- /dev/null +++ b/templates/handlers/duplicate.twig @@ -0,0 +1,89 @@ +{% if title %}

{{ title }}

{% endif %} +{% if error %} + {{ error|raw }} +{% else %} + {% if toExternalWiki %} + {{ include_javascript('javascripts/handlers/duplicate.js') }} +
+
{{ _t('WIKI_URL_RECENT') }}.
+
+ +
+ + + + +
+ +
+
+
{# hide the field while no valid yeswiki url given #} +
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+
+
+ {% if form %} + + +
+ {% endif %} +
{# hide the field while not connected #} + {% endif %} +
+ {% if pageTitle %} +
+ +
+ +
+
+ {% endif %} +
+ +
+ {{ baseUrl }} + + {% if toExternalWiki %} + + + + {% endif %} +
+ +
+ {% if attachments|length > 0 %} + {{ _t('FILES_TO_DUPLICATE') }} ({{ _t('TOTAL_SIZE') ~ ' ' ~ totalSize }}) +
    + {% for a in attachments %} +
  1. {{a.path|replace({'files/': ''})}} ({{a.humanSize}})
  2. + {% if toExternalWiki %}{% endif %} + {% endfor %} +
+ {% endif %} + {% if toExternalWiki %}{% endif %} + + + + + + {% if toExternalWiki %} +
+ {% endif %} + +{% endif %} \ No newline at end of file diff --git a/tools/aceditor/lang/aceditorjs_ca.inc.php b/tools/aceditor/lang/aceditorjs_ca.inc.php index 7da0638d8..cac06e033 100644 --- a/tools/aceditor/lang/aceditorjs_ca.inc.php +++ b/tools/aceditor/lang/aceditorjs_ca.inc.php @@ -1,4 +1,5 @@ 'Desa', 'ACEDITOR_FORMAT' => 'Format', diff --git a/tools/aceditor/lang/aceditorjs_es.inc.php b/tools/aceditor/lang/aceditorjs_es.inc.php index 3ee815df4..254e367cf 100644 --- a/tools/aceditor/lang/aceditorjs_es.inc.php +++ b/tools/aceditor/lang/aceditorjs_es.inc.php @@ -1,4 +1,5 @@ 'Guardar', 'ACEDITOR_FORMAT' => 'Formato', diff --git a/tools/attach/lang/attach_ca.inc.php b/tools/attach/lang/attach_ca.inc.php index 201358f06..cf14cb4fd 100644 --- a/tools/attach/lang/attach_ca.inc.php +++ b/tools/attach/lang/attach_ca.inc.php @@ -1,4 +1,5 @@ "Fournit l'url du fichier de cache pour l'image voulue\n". @@ -97,7 +98,7 @@ 'FAILED' => 'Error', 'ATTACH_FILENAME' => 'Nom del fitxer', 'ATTACH_SIZE' => 'Cintura', - 'ATTACH_GET_CACHE_URLIMAGE_NO_FILE' => "Fitxer d'imatge inexistent", + 'ATTACH_GET_CACHE_URLIMAGE_NO_FILE' => 'Fitxer imatge inexistent', 'INVALID_REQUEST_METHOD' => 'Mètode de requète invàlid', 'ERROR_MOVING_TEMPORARY_FILE' => 'Error durant el d✱;ubicació del fitxer temporal', 'ERROR_NO_FILE_UPLOADED' => 'Cap fitxer no ha estat descarregat.', @@ -124,7 +125,7 @@ 'ERROR_MAX_FILE_SIZE' => 'El fitxer t markedeacute;l exposedeacute;charg markedeacute excitedcirc;de la mida de MAX_FILE_SIZE, que ha \'eacute;t yawned; spŭeacute;cifi primeacute;e en la forma HTML.', 'ERROR_PARTIAL_UPLOAD' => 'El fitxer té "eacute;t `eacute;; que parcialment cap aeacute;l neglecteacute;charg towardseacute.', 'ERROR_NOT_AUTHORIZED_EXTENSION' => 'El fitxer no té una extensió autoritzada, heus aquí les que la configuració autoritza: ', - 'ATTACH_ACTION_FULLIMAGELINK_TEXT' => "Permet fer clic a la imatge per mostrar-la en gran", + 'ATTACH_ACTION_FULLIMAGELINK_TEXT' => 'Permetre clicar sobre la imatge per anunciar-lo en gran', 'ATTACH_FILE_MANAGEMENT' => 'Gestió dels fitxers', 'ATTACH_RESTORE' => 'Restauració', 'ATTACH_EMPTY_TRASH_NOTICE' => 'els fitxers esborrats a partir de la cistella ho seran definitivament.', diff --git a/tools/attach/lang/attach_es.inc.php b/tools/attach/lang/attach_es.inc.php index 989688522..264b0d670 100644 --- a/tools/attach/lang/attach_es.inc.php +++ b/tools/attach/lang/attach_es.inc.php @@ -1,4 +1,5 @@ "Fournit l'url du fichier de cache pour l'image voulue\n". @@ -96,10 +97,10 @@ 'RIGHT' => 'Derecha', 'FAILED' => 'Error', // controllers/ApiController.php - 'ATTACH_GET_CACHE_URLIMAGE_NO_FILE' => "Sin archivo de imagen", + 'ATTACH_GET_CACHE_URLIMAGE_NO_FILE' => 'Sin archivo de imagen', 'ATTACH_UPLOAD_FORM_FOR_FILE' => 'Formulario de envío de archivos', 'ERROR_NOT_AUTHORIZED_EXTENSION' => 'El archivo no tiene extensiones permitidas, estas son las que la configuración permite: ', - 'ATTACH_ACTION_FULLIMAGELINK_TEXT' => "Permitir hacer clic en la imagen para verla en tamaño grande", + 'ATTACH_ACTION_FULLIMAGELINK_TEXT' => 'Permitir hacer clic en la imagen para verla en tamaño grande', 'ATTACH_FILE_MANAGEMENT' => 'Gestión de archivos', 'ATTACH_FILENAME' => 'Nombre de archivo', 'ATTACH_SIZE' => 'Tamaño', diff --git a/tools/attach/lang/attach_nl.inc.php b/tools/attach/lang/attach_nl.inc.php index 9b5c31563..3f76c0431 100644 --- a/tools/attach/lang/attach_nl.inc.php +++ b/tools/attach/lang/attach_nl.inc.php @@ -1,4 +1,5 @@ "Fournit l'url du fichier de cache pour l'image voulue\n". diff --git a/tools/attach/lang/attach_pt.inc.php b/tools/attach/lang/attach_pt.inc.php index 7ac3373a7..c64f1995d 100644 --- a/tools/attach/lang/attach_pt.inc.php +++ b/tools/attach/lang/attach_pt.inc.php @@ -1,4 +1,5 @@ "Fournit l'url du fichier de cache pour l'image voulue\n". diff --git a/tools/attach/lang/attach_ta.inc.php b/tools/attach/lang/attach_ta.inc.php index 9910914ff..605c0e0bf 100644 --- a/tools/attach/lang/attach_ta.inc.php +++ b/tools/attach/lang/attach_ta.inc.php @@ -1,4 +1,5 @@ 'பட கோப்பு இல்லை', diff --git a/tools/autoupdate/services/MigrationService.php b/tools/autoupdate/services/MigrationService.php index 4ab27602c..62f95c0db 100644 --- a/tools/autoupdate/services/MigrationService.php +++ b/tools/autoupdate/services/MigrationService.php @@ -79,4 +79,4 @@ public function run() return $messages; } -} \ No newline at end of file +} diff --git a/tools/bazar/controllers/ApiController.php b/tools/bazar/controllers/ApiController.php index 820662f61..18be9b71c 100644 --- a/tools/bazar/controllers/ApiController.php +++ b/tools/bazar/controllers/ApiController.php @@ -323,10 +323,10 @@ public function getBazarListData() } $result[] = $entry[$field] ?? null; } + return $result; }, $entries); - return new ApiResponse( [ 'entries' => $entries, diff --git a/tools/bazar/fields/ImageField.php b/tools/bazar/fields/ImageField.php index e819ac5d2..19ca01280 100644 --- a/tools/bazar/fields/ImageField.php +++ b/tools/bazar/fields/ImageField.php @@ -53,6 +53,7 @@ protected function getDefaultImageName($entry) if (file_exists($this->getBasePath() . $default_image_filename)) { return $default_image_filename; } + return false; } @@ -91,6 +92,7 @@ protected function renderInput($entry) || (!empty($imgDefault) && file_exists($this->getBasePath() . $imgDefault)) ) { $img = $value ? $value : $imgDefault; + return $output . ($alertMessage ?? '') . $this->render('@bazar/inputs/image.twig', [ 'value' => $img, 'downloadUrl' => $this->getBasePath() . $img, @@ -182,6 +184,7 @@ public function formatValuesBeforeSave($entry) } else { $entry[$this->propertyName] = ''; } + return [ $this->propertyName => $this->getValue($entry), 'fields-to-remove' => ['oldimage_' . $this->propertyName], diff --git a/tools/bazar/lang/bazar_ca.inc.php b/tools/bazar/lang/bazar_ca.inc.php index daca7be2f..2f24d1331 100644 --- a/tools/bazar/lang/bazar_ca.inc.php +++ b/tools/bazar/lang/bazar_ca.inc.php @@ -1,4 +1,5 @@ 'Formularis', 'BAZ_LISTES' => 'Llistes', @@ -468,21 +469,21 @@ 'BAZ_REACTIONS_DEFAULT_I_LOVE' => 'M\'encanta', 'BAZ_REACTIONS_DEFAULT_I_UNDERSTOOD' => 'He après alguna cosa', 'BAZ_REACTIONS_DEFAULT_NOT_AGREE' => 'No estic d\'acord', - 'BAZ_REACTIONS_DEFAULT_NOT_UNDERSTOOD' => 'No ho entenc', - 'BAZ_YEAR' => 'Ann ateacute;e', - 'BAZ_FACETTES_DISPLAY' => 'Aspecte de les facetes', - 'BAZ_PREVIEW' => 'Vista prèvia', - 'BAZ_PREVIEW_DETAILS' => 'aquesta part no es pot clicar, els paramesos canvien a la columna esquerra', - 'BAZ_CORRESPONDANCE_ERROR' => 'acció bazarista: paràmetre de coincidència mal omplert: ha de coincidir amb la forma="identifiant_1=identifiant_2" o la correspondència="identifiant_1=identifiant_2, identificador_3=identifiant_4"', - 'BAZ_WIDGET_INSTRUCTION2' => 'Codi d\'acció wiki una pasta de còpia en una pàgina d\'aquest lloc', - 'BAZ_CORRESPONDANCE_ERROR2' => "acció baazarista: el paràmetre de partit està mal omplert. -© 2019 Fundació Catalunya Europa. CIF: G64693914. Reg. de Fundacions Núm. 2395", - 'BAZ_FILEFIELD_TOO_LARGE_FILE' => 'El fitxer és massa gran, màxim %{fileMaxSize} bytes', - 'BAZ_IMAGE_ALREADY_EXISTING' => 'La imatge {fileName} va existir en el cas de imiteacute;ja, no va \'eacute; remplac✱eacute;e.', - 'BAZ_DRAG_n_DROP_CHECKBOX_DELETE_ITEM' => 'Eliminació de l\'Ateacute;l Isacute;ment', - 'BAZ_DRAG_n_DROP_CHECKBOX_FROM_THE_LIST' => 'llista', - 'BAZ_DRAG_n_DROP_CHECKBOX_SEE_ITEM' => 'Veure el Ateacute;l neglecteacute;ment', - 'BAZ_DRAG_n_DROP_CHECKBOX_ORDER_ITEM_INFO' => 'Si us plau, introdueix dins de la caixa de text els caràcters que veu a la imatge de sota. Això és requerit per evitar enviaments automàtics. Pots moure’ls d’esquerra a dreta', + 'BAZ_REACTIONS_DEFAULT_NOT_UNDERSTOOD' => 'He comprès pas', + 'BAZ_YEAR' => 'Any', + 'BAZ_FACETTES_DISPLAY' => 'Aparença de les facetes', + 'BAZ_PREVIEW' => 'Prévisualisation', + 'BAZ_PREVIEW_DETAILS' => 'aquesta part és no cliquable, les paramêtres es canvien en la columna d\'esquerra', + 'BAZ_CORRESPONDANCE_ERROR' => 'acció bazarliste: parametre correspondència mal omplert: deu etre de la forma correspondència="identificant_1=identificador_2" o correspondència="identificant_1=identificador_2, identificant_3=identificador_4"', + 'BAZ_WIDGET_INSTRUCTION2' => 'Codi acció wiki té copiar enganxar en una pàgina d\'aquest lloc', + 'BAZ_CORRESPONDANCE_ERROR2' => 'acció bazarliste: el paràmetre correspondència està mal omplert. +Ha de ser de la forma correspondència="identificant_1=identificador_2" o correspondència="identificant_1=identificador_2, identificant_3=identificador_4"', + 'BAZ_FILEFIELD_TOO_LARGE_FILE' => 'El fitxer és massa voluminós, màxim %{fileMaxSize} octets', + 'BAZ_IMAGE_ALREADY_EXISTING' => 'La imatge {fileName} existia déja, no ha estada reemplaçada.', + 'BAZ_DRAG_n_DROP_CHECKBOX_DELETE_ITEM' => 'Treure l\'element', + 'BAZ_DRAG_n_DROP_CHECKBOX_FROM_THE_LIST' => 'de la llista', + 'BAZ_DRAG_n_DROP_CHECKBOX_SEE_ITEM' => 'Veure l\'element', + 'BAZ_DRAG_n_DROP_CHECKBOX_ORDER_ITEM_INFO' => 'Desplaceu els elements per posar-los en l\'ordre que us convé. Podeu també desplaçar-los d\'esquerra a la dreta', 'BAZ_DRAG_n_DROP_CHECKBOX_LIST' => 'llista', 'BAZ_MORE_INFOS' => 'Més informació', 'BAZ_NOT_EXPANDED' => 'No es desplega', diff --git a/tools/bazar/lang/bazar_en.inc.php b/tools/bazar/lang/bazar_en.inc.php index 73a4b7e1c..2bbfe9beb 100644 --- a/tools/bazar/lang/bazar_en.inc.php +++ b/tools/bazar/lang/bazar_en.inc.php @@ -1,4 +1,5 @@ 'Forms', 'BAZ_LISTES' => 'Lists', @@ -438,8 +439,8 @@ 'BAZAR_SEMANTIC_TYPE_MISSING' => 'The semantic type of this form hasn\'t been defined, consequently it cannot be displayed in JSON-LD', 'BAZ_ACTIVATE_COMMENTS_HINT' => 'Updated rights when registering the entry', 'BAZ_EXTERNAL_SERVICE_BAD_RECEIVED_FORM' => 'incorrectly formatted received form content.', - 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => "The \"{currentName}\" identifier already exists! -Check the box to confirm that it has been replaced by \"{proposedName}\", or change your identifier in the form below.", + 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => 'The "{currentName}" identifier already exists! +Check the box to confirm that it has been replaced by "{proposedName}", or change your identifier in the form below.', 'BAZ_CONFIRM_VIDER_FORMULAIRE' => 'Please note! All the entries registered for this form will be lost, only the empty form will remain available. Are you sure you want to empty this form of its associated entries?', 'BAZ_PAS_DE_FORM_AVEC_CET_ID' => 'The form you are looking for does not exist (perhaps it has been deleted in the meantime)', 'BAZ_SUPPRIMER_FORMULAIRE' => 'Delete the form', diff --git a/tools/bazar/lang/bazar_es.inc.php b/tools/bazar/lang/bazar_es.inc.php index a81b26890..7a4f89b94 100644 --- a/tools/bazar/lang/bazar_es.inc.php +++ b/tools/bazar/lang/bazar_es.inc.php @@ -1,4 +1,5 @@ 'Formularios', 'BAZ_LISTES' => 'Listas', @@ -468,11 +469,11 @@ 'EVENT_UP_TO_DATE' => 'Hasta que:', 'EVENT_THIRD_Y_OF_MONTH' => 'La tercera Y del mes', 'EVENTS_WHEN_IN_MONTH' => '¿Cuándo fue el mes?', - 'BAZ_CORRESPONDANCE_ERROR2' => "acción baazarlista: el parámetro del partido está mal llenado. -Debe ser el formulario de coincidencia=\"identifiant_1=identifiant_2\" o la correspondencia=\"identifiant_1=identifiant_2, identifier_3=identifiant_4\"", + 'BAZ_CORRESPONDANCE_ERROR2' => 'acción baazarlista: el parámetro del partido está mal llenado. +Debe ser el formulario de coincidencia="identifiant_1=identifiant_2" o la correspondencia="identifiant_1=identifiant_2, identifier_3=identifiant_4"', 'VIDEO_LINK_FIELD' => 'Enlace al vídeo: %{link}', - 'BAZ_USER_FIELD_ALREADY_CONNECTED' => "Ya estás conectado con el identificador \"{wikiname}\" y el correo electrónico \"{email}\". -La carpeta creada se vinculará automáticamente a su cuenta. Por favor inicie sesión para crear una nueva cuenta!", + 'BAZ_USER_FIELD_ALREADY_CONNECTED' => 'Ya estás conectado con el identificador "{wikiname}" y el correo electrónico "{email}". +La carpeta creada se vinculará automáticamente a su cuenta. Por favor inicie sesión para crear una nueva cuenta!', 'BAZ_MEMBERS' => 'miembros', 'BAZ_COMMENTS_INFO_HUMHUB_EMBEDDED' => 'Los comentarios son gestionados por la plataforma social HumHub (Humhub integrado por YesWiki)', 'EDIT_CONFIG_GROUP_BAZAR' => 'Base de datos', @@ -492,8 +493,8 @@ 'BAZ_REACTIONS_DEFAULT_NOT_AGREE' => 'No estoy de acuerdo', 'BAZ_REACTIONS_DEFAULT_NOT_UNDERSTOOD' => 'No entendí', 'EDIT_CONFIG_HINT_BAZ_ENVOI_MAIL_ADMIN' => 'Enviar un correo electrónico a los administradores en cada cambio de archivo (verdadero o falso)', - 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => "El identificador \"{currentName}\" ya existe! -Compruebe la casilla para confirmar su reemplazo por \"{proposedName}\" o cambiar de otro modo su identificador en el siguiente formulario.", + 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => 'El identificador "{currentName}" ya existe! +Compruebe la casilla para confirmar su reemplazo por "{proposedName}" o cambiar de otro modo su identificador en el siguiente formulario.', 'EVENT_REPETITION_FOR_DAYS' => 'todos los días', 'EVENT_ACTIVATE_CUSTOM' => 'Ver opciones adicionales', 'EVENT_EVERY_DAYS' => 'Cada día', diff --git a/tools/bazar/lang/bazar_fr.inc.php b/tools/bazar/lang/bazar_fr.inc.php index 7c4ec0921..daeddc26b 100755 --- a/tools/bazar/lang/bazar_fr.inc.php +++ b/tools/bazar/lang/bazar_fr.inc.php @@ -434,4 +434,4 @@ // services/EntryManager.php 'BAZ_CORRESPONDANCE_ERROR' => 'action bazarliste : parametre correspondance mal rempli : il doit etre de la forme correspondance="identifiant_1=identifiant_2" ou correspondance="identifiant_1=identifiant_2, identifiant_3=identifiant_4"', 'BAZ_CORRESPONDANCE_ERROR2' => "action bazarliste : le paramètre correspondance est mal rempli.\nIl doit être de la forme correspondance=\"identifiant_1=identifiant_2\" ou correspondance=\"identifiant_1=identifiant_2, identifiant_3=identifiant_4\"", -]; \ No newline at end of file +]; diff --git a/tools/bazar/lang/bazar_nl.inc.php b/tools/bazar/lang/bazar_nl.inc.php index 9f7813cf1..b24a328fc 100644 --- a/tools/bazar/lang/bazar_nl.inc.php +++ b/tools/bazar/lang/bazar_nl.inc.php @@ -1,4 +1,5 @@ 'Formulieren', 'BAZ_LISTES' => 'Lijsten', @@ -507,8 +508,8 @@ 'VIDEO_LINK_FIELD' => 'Link naar video: _', 'EDIT_CONFIG_HINT_BAZ_MAP_HEIGHT' => 'Default lengte in pixels van cartografische displays', 'EDIT_CONFIG_HINT_BAZ_ADRESSE_MAIL_ADMIN' => 'E-mailadres van de afzender van de veranderingen aan de bazaar lakens', - 'BAZ_CORRESPONDANCE_ERROR2' => "baazarlist actie: de match parameter is slecht gevuld. -Het moet de overeenkomende vorm zijn", + 'BAZ_CORRESPONDANCE_ERROR2' => 'baazarlist actie: de match parameter is slecht gevuld. +Het moet de overeenkomende vorm zijn', 'BAZ_IMPORT_LISTS_FROM_URL' => 'Importeer de lijst van een andere jawiki', 'BAZ_NBLISTSFOUND' => 'Gevonden', 'BAZ_NBFORMSFOUND' => 'Nummer van formulieren', diff --git a/tools/bazar/lang/bazar_pt.inc.php b/tools/bazar/lang/bazar_pt.inc.php index ae40a7248..69052b932 100644 --- a/tools/bazar/lang/bazar_pt.inc.php +++ b/tools/bazar/lang/bazar_pt.inc.php @@ -1,4 +1,5 @@ 'Formulário', 'BAZ_LISTES' => 'Listas', @@ -488,8 +489,8 @@ 'BAZ_EXTERNAL_SERVICE_BAD_RECEIVED_ENTRIES' => 'conteúdo dos cartões recebidos mal formatado.', 'EDIT_CONFIG_HINT_BAZ_MAP_HEIGHT' => 'Altura padrão em pixels de telas cartográficas', 'EDIT_CONFIG_HINT_BAZ_ENVOI_MAIL_ADMIN' => 'Envie um e-mail para administradores em cada mudança de arquivo (verdadeiro ou falso)', - 'BAZ_USER_FIELD_ALREADY_CONNECTED' => "Você já está conectado com o identificador \"{wikiname}\" e o e-mail \"{email}\". -A pasta criada será automaticamente vinculada à sua conta. Faça login para criar uma nova conta!", + 'BAZ_USER_FIELD_ALREADY_CONNECTED' => 'Você já está conectado com o identificador "{wikiname}" e o e-mail "{email}". +A pasta criada será automaticamente vinculada à sua conta. Faça login para criar uma nova conta!', 'BAZ_LOADING' => 'A carregar', 'BAZ_USER_FIELD_FORCE_SAVE_ENTRY' => 'Como administrador, forçar a criação do arquivo para o e-mail dado (e criar uma conta apenas se ele não existir)', 'BAZ_EXPANDED' => 'Desdobrado', @@ -506,8 +507,8 @@ 'EVENT_EVERY_YEARS' => 'Todos os anos', 'EDIT_CONFIG_HINT_BAZ_MAP_ZOOM' => 'Nível de zoom padrão de mapas (1:world = acordado 15:commune)', 'EDIT_CONFIG_HINT_BAZARIGNOREACLS' => 'Permitir a criação de arquivos mesmo se a wiki estiver fechada por escrito (verdadeiro ou falso)', - 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => "O identificador \"{currentName}\" já existe! -Marque a caixa para confirmar sua substituição por \"{proposedName}\" ou altere o identificador no formulário abaixo.", + 'BAZ_USER_FIELD_EXISTING_USER_BY_NAME' => 'O identificador "{currentName}" já existe! +Marque a caixa para confirmar sua substituição por "{proposedName}" ou altere o identificador no formulário abaixo.', 'BAZ_USER_FIELD_EXISTING_USER_BY_EMAIL' => 'O e-mail fornecido já está associado a uma conta YesWiki! Digite outro endereço de e-mail ou inicie sessão nesta conta.', 'BAZ_MORE_INFOS' => 'Mais informações', 'BAZ_NO_ENTRY_FOR_THIS_PERIOD' => 'Não há registo para este período.', diff --git a/tools/bazar/lang/bazarjs_en.inc.php b/tools/bazar/lang/bazarjs_en.inc.php index b3da19f33..2ddcace8c 100644 --- a/tools/bazar/lang/bazarjs_en.inc.php +++ b/tools/bazar/lang/bazarjs_en.inc.php @@ -1,4 +1,5 @@ 'Calculations', @@ -318,7 +319,7 @@ 'BAZ_REACTIONS_FIELD_LABELS_HINT' => 'Leave empty or separated by commas', 'BAZ_REACTIONS_FIELD_IMAGES_PLACEHOLDER' => 'mikone-top-gratitude.svg,j-aime,j-ai-appris,pas-compris,pas-d-accord,idee-noire', 'LIST_ADD_CHILD_NODE' => 'Add a sub-value', - 'LIST_ERROR_MISSING_IDS' => "Some values have no associated key", + 'LIST_ERROR_MISSING_IDS' => 'Some values have no associated key', 'LIST_ERROR_DUPLICATES_IDS' => 'Each key must be unique. These keys are used several times: ', 'BAZ_FORM_EDIT_LISTEFICHES_TEMPLATE_PLACEHOLDER' => 'Ex : template="liste_liens.tpl.html (by default = accordon)"', 'BAZ_FORM_EDIT_IMAGE_WIDTH' => 'Thumbnail width', diff --git a/tools/bazar/lang/bazarjs_ta.inc.php b/tools/bazar/lang/bazarjs_ta.inc.php index 270cababd..d5a603df7 100644 --- a/tools/bazar/lang/bazarjs_ta.inc.php +++ b/tools/bazar/lang/bazarjs_ta.inc.php @@ -1,4 +1,5 @@ 'கால்குலச்', diff --git a/tools/bazar/presentation/javascripts/inputs/image-field.js b/tools/bazar/presentation/javascripts/inputs/image-field.js index a267686da..b39899ae9 100644 --- a/tools/bazar/presentation/javascripts/inputs/image-field.js +++ b/tools/bazar/presentation/javascripts/inputs/image-field.js @@ -60,7 +60,12 @@ function handleFileSelect(evt) { css = '' // Render thumbnail. const span = document.createElement('span') - span.innerHTML = `${escape(theFile.name)}` + span.innerHTML = `` document.getElementById(`img-${id}`).innerHTML = span.innerHTML }) } @@ -72,6 +77,6 @@ function handleFileSelect(evt) { } const imageinputs = document.getElementsByClassName('yw-image-upload') -for (let i = 0; i < imageinputs.length; i++) { +for (let i = 0; i < imageinputs.length; i += 1) { imageinputs.item(i).addEventListener('change', handleFileSelect, false) } diff --git a/tools/bazar/presentation/javascripts/jquery.photobox.js b/tools/bazar/presentation/javascripts/jquery.photobox.js index 4c0f9c7e0..dc53a4358 100644 --- a/tools/bazar/presentation/javascripts/jquery.photobox.js +++ b/tools/bazar/presentation/javascripts/jquery.photobox.js @@ -980,4 +980,4 @@ history, defaults } -}(jQuery, document, window)) \ No newline at end of file +}(jQuery, document, window)) diff --git a/tools/bazar/services/EntryManager.php b/tools/bazar/services/EntryManager.php index b6b4330a8..e7c29b808 100644 --- a/tools/bazar/services/EntryManager.php +++ b/tools/bazar/services/EntryManager.php @@ -1180,4 +1180,12 @@ function ($attributeName) { return $entriesIds; } + + private function duplicate($sourceTag, $destinationTag): bool + { + $result = false; + $this->wiki->LogAdministrativeAction($this->authController->getLoggedUserName(), 'Duplication de la fiche ""' . $sourceTag . '"" vers la fiche ""' . $destinationTag . '""'); + + return $result; + } } diff --git a/tools/bazar/services/ListManager.php b/tools/bazar/services/ListManager.php index 091a29597..7317b5db0 100644 --- a/tools/bazar/services/ListManager.php +++ b/tools/bazar/services/ListManager.php @@ -44,6 +44,11 @@ public function __construct( $this->cachedLists = []; } + public function isList($id): bool + { + return boolval($this->tripleStore->exist($id, TripleStore::TYPE_URI, self::TRIPLES_LIST_ID, '', '')); + } + public function getOne($id): ?array { if (isset($this->cachedLists[$id])) { @@ -94,13 +99,12 @@ public function getAll(): array return $result; } - public function create($title, $nodes) + public function create($title, $nodes, $id = null) { if ($this->securityController->isWikiHibernated()) { throw new \Exception(_t('WIKI_IN_HIBERNATION')); } - - $id = genere_nom_wiki('List' . $title); + $id = $id ?? genere_nom_wiki('List' . $title); $this->pageManager->save($id, json_encode([ 'title' => $title, 'nodes' => $this->sanitizeHMTL($nodes), diff --git a/tools/bazar/services/SearchManager.php b/tools/bazar/services/SearchManager.php index 6e37d07fd..02db5c99a 100644 --- a/tools/bazar/services/SearchManager.php +++ b/tools/bazar/services/SearchManager.php @@ -133,4 +133,4 @@ private function prepareNeedleForRegexp(string $needle): string return $needle; } -} \ No newline at end of file +} diff --git a/tools/bazar/templates/entries/view.twig b/tools/bazar/templates/entries/view.twig index 7d09e2d01..928a8ab8d 100644 --- a/tools/bazar/templates/entries/view.twig +++ b/tools/bazar/templates/entries/view.twig @@ -63,6 +63,36 @@ {{ _t('BAZ_MODIFIER') }} {% endif %} + + + {% if canDelete %} 'Acció {{abonnement ...}}', @@ -84,29 +85,29 @@ 'EDIT_CONFIG_HINT_CONTACT_DISABLE_EMAIL_FOR_PASSWORD' => 'Desactiva el correu electrònic per tornar a introduir una contrasenya (ex: LDAP, SSO)', 'EDIT_CONFIG_HINT_CONTACT_SMTP_HOST' => 'Preguntes Freqüents - FAQ', 'EDIT_CONFIG_HINT_CONTACT_SMTP_PORT' => 'Port SMTP (generalment 465 o 587)', - 'EDIT_CONFIG_HINT_CONTACT_DEBUG' => 'Mode vertical per desconnectar (a posar 2 per obtenir informació)', - 'CONTACT_REPLY' => 'Pots escriure un missatge', - 'CONTACT_TO_PLACEHOLDER' => 'Adreça electrònica del destinatari', - 'CONTACT_SENDMAIL_ERROR' => 'El període no s’ha omplert ni té cap valor estàndard (mes, setmana o dia).', - 'CONTACT_DELETED_LIST' => 'llista esborrada', - 'CONTACT_WELCOME_ON' => 'Benvinguts', - 'CONTACT_HELP_IN_NOTIFICATION' => 'vés al contingut', - 'CONTACT_NEW_USER_SUBJECT' => 'Els vostres nous identificadors al lloc', - 'AB_contact_group_label' => "Correu electrònic", - 'AB_abonnement_action_label' => "Subscriure's a una llista de discussió", - 'AB_abonnement_template_label' => 'plantilla', + 'EDIT_CONFIG_HINT_CONTACT_DEBUG' => 'Mode verbós per a débugguer (posar 2 per tenir informacions)', + 'CONTACT_REPLY' => 'Podeu escriure-li un missatge a', + 'CONTACT_TO_PLACEHOLDER' => 'Adreça correu del destinatari', + 'CONTACT_SENDMAIL_ERROR' => 'El període no ha estat informada o no té valor estàndard (month, week o day).', + 'CONTACT_DELETED_LIST' => 'llista supprimee', + 'CONTACT_WELCOME_ON' => 'Benvinguda sobre', + 'CONTACT_HELP_IN_NOTIFICATION' => 'aneu en el web per gestionar la vostra inscripció', + 'CONTACT_NEW_USER_SUBJECT' => 'Els vostres nous identificadors en el web', + 'AB_contact_group_label' => "Accions d'enviament d'e-mail/llistes", + 'AB_abonnement_action_label' => 'Abonar-se a una llista de discussió', + 'AB_abonnement_template_label' => 'template', 'AB_abonnement_class_label' => 'classe', 'AB_abonnement_mailinglist_label' => 'Llista de discussió', - 'AB_deabonnement_action_label' => "Subscriure's a una llista de discussió", - 'AB_contact_action_label' => 'Formulari de contacte', - 'AB_contact_action_entete_default' => 'Enviat del lloc...', - 'AB_contact_action_template_label' => 'Plantilla personalitzada', - 'AB_contact_action_template_hint' => 'Ex.: complet-contact-form.tpl.html', - 'AB_contact_action_class_label' => 'cs', - 'AB_listsubscription_action_label' => 'llista', - 'AB_mailperiod_action_label' => "Subscriu-te per rebre el contingut d'una pàgina periòdicament per correu electrònic", - 'AB_mailperiod_action_hint' => 'Per a aquesta acció de treball cal comprovar certs paràmetres del servidor. Veure documents a https://yeswiki.net/?MailPeriod', - 'AB_mailinglist_action_label' => 'Correu electrònic massiu a un butlletí', - 'AB_mailinglist_action_description' => "Acció per donar-se d'alta o donar-se de baixa massivament de correus electrònics", - 'EDIT_CONFIG_HINT_CONTACT_USE_LONG_WIKI_URLS_IN_EMAILS' => "Afegir 'wiki=' als enllaços d'aquest wiki en correus electrònics", + 'AB_deabonnement_action_label' => "Donar-se de baixa d'una llista de discussió", + 'AB_contact_action_label' => 'Anunciar un formulari de contacte', + 'AB_contact_action_entete_default' => 'Enviat des del lloc...', + 'AB_contact_action_template_label' => 'Template personalitzat', + 'AB_contact_action_template_hint' => 'Ex.: complete-contacte-form.tpl.html', + 'AB_contact_action_class_label' => 'classifica css', + 'AB_listsubscription_action_label' => 'listsubscription', + 'AB_mailperiod_action_label' => "Abonar-se per rebre periòdicament el contingut d'una pàgina per email", + 'AB_mailperiod_action_hint' => 'Perquè aquesta acció funcioni heu de verificar certs paràmetres sobre el vostre servidor. Veure la documentació sobre https://yeswiki.net/?MailPeriod', + 'AB_mailinglist_action_label' => 'Inscriure massivament correus a un butlletí informatiu', + 'AB_mailinglist_action_description' => 'Acció permetent inscriure o désinscrire massivament dels correus a un butlletí informatiu', + 'EDIT_CONFIG_HINT_CONTACT_USE_LONG_WIKI_URLS_IN_EMAILS' => "Afegir 'wiki=' als enllaços cap a aquest wiki en els e-mails", ]; diff --git a/tools/contact/lang/contact_en.inc.php b/tools/contact/lang/contact_en.inc.php index a4f3b97f0..c991678ed 100644 --- a/tools/contact/lang/contact_en.inc.php +++ b/tools/contact/lang/contact_en.inc.php @@ -1,4 +1,5 @@ 'Action {{abonnement ...}}', @@ -71,21 +72,21 @@ 'CONTACT_WELCOME_ON' => 'Welcome to', 'CONTACT_HELP_IN_NOTIFICATION' => 'go to the site to manage your registration', 'AB_abonnement_action_mail_label' => 'E-mail from the discussion list', - 'AB_abonnement_action_label' => "Subscribe to a discussion list", + 'AB_abonnement_action_label' => 'Subscribe to a discussion list', 'AB_abonnement_class_label' => 'class', 'AB_abonnement_mailinglist_label' => 'List of discussion', 'AB_contact_action_mail_label' => 'E-mail address', 'AB_contact_action_class_label' => 'css', 'AB_mailperiod_action_hint' => 'For this action to work you need to check certain parameters on your server. See documents on https://yeswiki.net/?MailPeriod', 'AB_mailinglist_action_label' => 'Massively write emails to a newsletter', - 'AB_mailinglist_action_description' => "Action to register or unsubscribe massively emails to a newsletter", + 'AB_mailinglist_action_description' => 'Action to register or unsubscribe massively emails to a newsletter', 'CONTACT_SENDMAIL_ERROR' => 'The period has not been filled or has no standard value (month, week or day).', 'CONTACT_DAILY_REPORT' => 'daily report of the', 'CONTACT_WEEKLY_REPORT' => 'weekly report', 'CONTACT_MONTHLY_REPORT' => 'monthly report', 'CONTACT_ENTRY_ADDED' => 'new plug adds', - 'AB_deabonnement_action_label' => "Unsubscribe from a discussion list", - 'AB_contact_action_entete_label' => "Automatic prefix of the mail object", + 'AB_deabonnement_action_label' => 'Unsubscribe from a discussion list', + 'AB_contact_action_entete_label' => 'Automatic prefix of the mail object', 'AB_contact_action_template_hint' => 'Ex.: complete-contact-form.tpl.html', 'AB_listsubscription_action_label' => 'listsubscription', 'EDIT_CONFIG_HINT_CONTACT_USE_LONG_WIKI_URLS_IN_EMAILS' => "Add 'wiki=' to the links to this wiki in e-mails", diff --git a/tools/contact/lang/contact_es.inc.php b/tools/contact/lang/contact_es.inc.php index cda0f782a..c727556bf 100644 --- a/tools/contact/lang/contact_es.inc.php +++ b/tools/contact/lang/contact_es.inc.php @@ -1,4 +1,5 @@ 'Acción {{suscripción ...}}', @@ -54,35 +55,35 @@ 'EDIT_CONFIG_HINT_CONTACT_SMTP_PORT' => 'Puerto SMTP (generalmente 465 o 587)', 'EDIT_CONFIG_HINT_CONTACT_SMTP_USER' => 'Usuario SMTP (a menudo correo)', 'EDIT_CONFIG_HINT_CONTACT_SMTP_PASS' => 'Contraseña SMTP', - 'EDIT_CONFIG_HINT_CONTACT_REPLY_TO' => 'Usuario a quien se enviará la respuesta de correo electrónico', - 'EDIT_CONFIG_HINT_CONTACT_DEBUG' => 'Modo vertical para desconectar (put 2 para obtener información)', - 'CONTACT_TEMPLATE_NOT_FOUND' => 'Plantilla de archivo no encontrada', - 'CONTACT_MESSAGE_SENT_FROM' => 'Mensaje enviado desde', - 'CONTACT_SUCCESS_UNSUBSCRIBE' => 'No has sido suscrito', - 'CONTACT_WEEKLY_REPORT' => 'informe semanal', - 'CONTACT_MONTHLY_REPORT' => 'informe mensual', - 'CONTACT_WELCOME_ON' => 'Bienvenido a', - 'AB_contact_group_label' => "Enviar correo electrónico/listas", + 'EDIT_CONFIG_HINT_CONTACT_REPLY_TO' => 'Usuario al cual la respuesta mail estará enviada', + 'EDIT_CONFIG_HINT_CONTACT_DEBUG' => 'Modo verbeux para débugguer (poner 2 para tener informaciones)', + 'CONTACT_TEMPLATE_NOT_FOUND' => 'Fichero de template no encontrado', + 'CONTACT_MESSAGE_SENT_FROM' => 'Mensaje enviado a marchar de', + 'CONTACT_SUCCESS_UNSUBSCRIBE' => 'Habéis sido bien dado de baja', + 'CONTACT_WEEKLY_REPORT' => 'informe semanal del', + 'CONTACT_MONTHLY_REPORT' => 'informe mensual del', + 'CONTACT_WELCOME_ON' => 'Bienvenida sobre', + 'AB_contact_group_label' => 'Acciones de envío de e-mail/listas', 'AB_abonnement_action_mail_label' => 'E-mail de la lista de discusión', - 'AB_abonnement_mailinglist_label' => 'Lista de debate', - 'AB_deabonnement_action_label' => "Suscripción de una lista de discusión", - 'AB_contact_action_label' => 'Mostrar formulario de contacto', - 'AB_contact_action_entete_label' => "Prefijo automático del objeto de correo", - 'AB_contact_action_entete_default' => 'Enviado desde el sitio...', - 'AB_contact_action_template_label' => 'Plantilla personalizada', - 'AB_contact_action_template_hint' => 'Ex.: full-contact-form.tpl.html', - 'AB_contact_action_class_label' => 'css', - 'AB_listsubscription_action_label' => 'lista de suscripción', - 'AB_mailperiod_action_label' => "Suscribirse para recibir el contenido de una página periódicamente por correo electrónico", - 'AB_mailperiod_action_hint' => 'Para que esta acción funcione es necesario verificar ciertos parámetros en su servidor. See documents on https://yeswiki.net/?MailPeriod', - 'AB_mailinglist_action_label' => 'Escribir correos electrónicos masivamente a un boletín informativo', - 'EDIT_CONFIG_HINT_CONTACT_USE_LONG_WIKI_URLS_IN_EMAILS' => "Añadir 'wiki=' a los enlaces a este wiki en e-mails", - 'EDIT_CONFIG_GROUP_CONTACT' => 'Enviar correos electrónicos', - 'EDIT_CONFIG_HINT_CONTACT_DISABLE_EMAIL_FOR_PASSWORD' => 'Desactivar el correo electrónico para reintroducir una contraseña (ex: LDAP, SSO)', - 'EDIT_CONFIG_HINT_CONTACT_FROM' => 'Usuario indicado como un transmisor de correo electrónico (para evitar los spams debe ser el mismo que el usuario smtp)', - 'CONTACT_HANDLER_MAIL_FOR_CONNECTED' => 'El correo electrónico es dimitido; sereno; a la gente identificada.', - 'CONTACT_LOGIN_IF_CONNECTED' => 'Si tiene un identificador, por favor identítese.', - 'CONTACT_PERIOD' => 'Recibir el contenido de esta página por correo electrónico de una manera', + 'AB_abonnement_mailinglist_label' => 'Lista de discusión', + 'AB_deabonnement_action_label' => 'Darse de baja de una lista de discusión', + 'AB_contact_action_label' => 'Anunciar un formulario de contacto', + 'AB_contact_action_entete_label' => 'Préfixe automático del objeto del mail', + 'AB_contact_action_entete_default' => 'Enviado desde el website...', + 'AB_contact_action_template_label' => 'Template personalizado', + 'AB_contact_action_template_hint' => 'Ex. : complete-contact-form.tpl.html', + 'AB_contact_action_class_label' => 'clase css', + 'AB_listsubscription_action_label' => 'listsubscription', + 'AB_mailperiod_action_label' => 'Abonarse para recibir periódicamente el contenido de una página por email', + 'AB_mailperiod_action_hint' => 'Para que esta acción funcionas tenéis que verificar ciertos parámetros sobre vuestro servidor. Ver la documentación sobre https://yeswiki.net/?mailperiod', + 'AB_mailinglist_action_label' => 'Inscribir masivamente mails a un newsletter', + 'EDIT_CONFIG_HINT_CONTACT_USE_LONG_WIKI_URLS_IN_EMAILS' => "Añadir 'wiki=' a los vínculos hacia este wiki en los e-mails", + 'EDIT_CONFIG_GROUP_CONTACT' => 'Envío de los e-mails', + 'EDIT_CONFIG_HINT_CONTACT_DISABLE_EMAIL_FOR_PASSWORD' => 'Désactiver #enviar de email para re-initaliser una contraseña (ex: LDAP, SSO)', + 'EDIT_CONFIG_HINT_CONTACT_FROM' => 'Usuario indicado como emisor del mail (para evitar los spams tiene que ser el mismo que el usuario smtp)', + 'CONTACT_HANDLER_MAIL_FOR_CONNECTED' => 'El envío de mail está reservado a las personas identificadas.', + 'CONTACT_LOGIN_IF_CONNECTED' => 'Si tenéis uno identificando, quered.', + 'CONTACT_PERIOD' => 'Recibir el contenido de esta página por email de manera', 'CONTACT_DAILY' => 'Journalière', 'CONTACT_WEEKLY' => 'Semanal', 'CONTACT_MONTHLY' => 'Mensual', @@ -96,17 +97,17 @@ 'CONTACT_SENDMAIL_INFO' => 'Enviamos los correos para el período', 'CONTACT_SENDMAIL_ERROR' => 'El período no se ha llenado ni tiene ningún valor estándar (mes, semana o día).', 'CONTACT_DAILY_REPORT' => 'informe diario del', - 'CONTACT_ENTRY_ADDED' => 'nuevos complementos de plug', - 'CONTACT_ENTRY_CHANGED' => 'archivo modificado', - 'CONTACT_IN_FORM' => 'en la forma', - 'CONTACT_DELETED_LIST' => 'lista eliminada', - 'CONTACT_USED_IP' => 'Usos IP', - 'CONTACT_YOUR_ENTRY' => 'Su tarjeta', - 'CONTACT_HELP_IN_NOTIFICATION' => 'ir al sitio para gestionar su registro', - 'CONTACT_NEW_USER_SUBJECT' => 'Sus nuevos identificadores en el sitio', - 'AB_abonnement_action_label' => "Suscríbete a una lista de discusión", - 'AB_abonnement_template_label' => 'plantilla', + 'CONTACT_ENTRY_ADDED' => 'nueva ficha ajoutee', + 'CONTACT_ENTRY_CHANGED' => 'ficha modifiee', + 'CONTACT_IN_FORM' => 'en el formulario', + 'CONTACT_DELETED_LIST' => 'lista supprimee', + 'CONTACT_USED_IP' => 'IP utilisee', + 'CONTACT_YOUR_ENTRY' => 'Vuestra ficha', + 'CONTACT_HELP_IN_NOTIFICATION' => 'id sobre el website para gestionar vuestra inscripción', + 'CONTACT_NEW_USER_SUBJECT' => 'Vuestros nuevos identifiants sobre el website', + 'AB_abonnement_action_label' => 'Abonarse a una lista de discusión', + 'AB_abonnement_template_label' => 'template', 'AB_abonnement_class_label' => 'clase', - 'AB_contact_action_mail_label' => 'Dirección de correo electrónico', - 'AB_mailinglist_action_description' => "Acción para registrar o cancelar correos electrónicos masivos a un boletín informativo", + 'AB_contact_action_mail_label' => 'E-mail del destinatario', + 'AB_mailinglist_action_description' => 'Acción que permite inscribir o désinscrire masivamente de los mails a un newsletter', ]; diff --git a/tools/contact/lang/contact_nl.inc.php b/tools/contact/lang/contact_nl.inc.php index d2a465f52..a9cda7b41 100644 --- a/tools/contact/lang/contact_nl.inc.php +++ b/tools/contact/lang/contact_nl.inc.php @@ -1,4 +1,5 @@ 'Actie {{inschrijven...}}', diff --git a/tools/contact/lang/contact_pt.inc.php b/tools/contact/lang/contact_pt.inc.php index 594c17384..745ec255e 100644 --- a/tools/contact/lang/contact_pt.inc.php +++ b/tools/contact/lang/contact_pt.inc.php @@ -1,4 +1,5 @@ 'Ação {{abonnement ...}}', diff --git a/tools/helloworld/lang/helloworld_it.inc.php b/tools/helloworld/lang/helloworld_it.inc.php index ee49795bb..921620553 100644 --- a/tools/helloworld/lang/helloworld_it.inc.php +++ b/tools/helloworld/lang/helloworld_it.inc.php @@ -1,4 +1,5 @@ 'Il mio messaggio', 'HELLOWORD_NO_MSG_PARAM' => 'Nessun parametro \'message\' definito nell\'azione {{greeting ...}}', diff --git a/tools/lang/actions/translation.php b/tools/lang/actions/translation.php index 13200bd16..2d946be36 100755 --- a/tools/lang/actions/translation.php +++ b/tools/lang/actions/translation.php @@ -42,4 +42,4 @@ } } else { echo _t(LANG_FLAG_FILE_MISSING); -} \ No newline at end of file +} diff --git a/tools/login/actions/LoginAction.php b/tools/login/actions/LoginAction.php index 2578162c4..18ec776fb 100644 --- a/tools/login/actions/LoginAction.php +++ b/tools/login/actions/LoginAction.php @@ -77,7 +77,7 @@ public function formatArguments($arg) : $incomingurl ), - 'lostpasswordurl' => ! boolval($this->params->get('contact_disable_email_for_password')) ? (! empty($arg['lostpasswordurl']) ? $this->wiki->generateLink($arg['lostpasswordurl']) : + 'lostpasswordurl' => !boolval($this->params->get('contact_disable_email_for_password')) ? (!empty($arg['lostpasswordurl']) ? $this->wiki->generateLink($arg['lostpasswordurl']) : // TODO : check page name for other languages $this->wiki->Href('', 'MotDePassePerdu')) : '', @@ -150,7 +150,7 @@ private function renderForm(string $action): string 'email' => ((isset($user['email'])) ? $user['email'] : ((isset($_POST['email'])) ? $_POST['email'] : '')), 'incomingurl' => $this->arguments['incomingurl'], 'signupurl' => $this->arguments['signupurl'], - 'lostpasswordurl' => ! boolval($this->params->get('contact_disable_email_for_password')) ? $this->arguments['lostpasswordurl'] : '', + 'lostpasswordurl' => !boolval($this->params->get('contact_disable_email_for_password')) ? $this->arguments['lostpasswordurl'] : '', 'profileurl' => $this->arguments['profileurl'], 'userpage' => $this->arguments['userpage'], 'PageMenuUser' => $pageMenuUserContent, @@ -180,8 +180,7 @@ private function login() if (empty($name)) { throw new LoginException(_t('LOGIN_WRONG_USER')); } - if (strpos($name, '@') !== false) { - // si le nomWiki est un mail + if (filter_var($name, FILTER_VALIDATE_EMAIL)) { $user = $this->userManager->getOneByEmail($name); } else { $user = $this->userManager->getOneByName($name); diff --git a/tools/login/actions/LostPasswordAction.php b/tools/login/actions/LostPasswordAction.php index fde97cbe4..7bbb3f691 100644 --- a/tools/login/actions/LostPasswordAction.php +++ b/tools/login/actions/LostPasswordAction.php @@ -13,7 +13,6 @@ class LostPasswordAction extends YesWikiAction { - protected $authController; protected $errorType; protected $typeOfRendering; diff --git a/tools/login/actions/UserSettingsAction.php b/tools/login/actions/UserSettingsAction.php index d4385f82b..5ba8a8c56 100644 --- a/tools/login/actions/UserSettingsAction.php +++ b/tools/login/actions/UserSettingsAction.php @@ -165,7 +165,7 @@ private function displayForm(?User $user = null) 'referrer' => $this->referrer, 'user' => $user, 'userLoggedIn' => $this->userLoggedIn, - 'userlink' => $this->userlink + 'userlink' => $this->userlink, ]); } else { $captcha = $this->securityController->renderCaptchaField(); @@ -185,7 +185,7 @@ private function displayForm(?User $user = null) 'name' => $this->wantedUserName, 'email' => $this->wantedEmail, 'captcha' => $captcha, - 'userlink' => '' + 'userlink' => '', ]); } } @@ -291,7 +291,7 @@ private function changePassword(?User $user, array $post) $this->wiki->Redirect($this->wiki->href()); } catch (TokenNotFoundException $th) { $this->errorPasswordChange = _t('USERSETTINGS_PASSWORD_NOT_CHANGED') . ' ' . $th->getMessage(); - } catch (BadFormatPasswordException | Throwable $ex) { + } catch (BadFormatPasswordException|Throwable $ex) { // Something when wrong when updating the user in DB $this->errorPasswordChange = _t('USERSETTINGS_PASSWORD_NOT_CHANGED') . ' ' . $ex->getMessage(); } @@ -362,4 +362,4 @@ private function checklogged(array $post) { $this->error = _t('USER_MUST_ACCEPT_COOKIES_TO_GET_CONNECTED') . '.'; } -} \ No newline at end of file +} diff --git a/tools/login/controllers/ApiController.php b/tools/login/controllers/ApiController.php index b19ef1f54..e04737a74 100644 --- a/tools/login/controllers/ApiController.php +++ b/tools/login/controllers/ApiController.php @@ -2,30 +2,81 @@ namespace YesWiki\Login\Controller; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use YesWiki\Core\ApiResponse; +use YesWiki\Core\Controller\AuthController; +use YesWiki\Core\Service\UserManager; use YesWiki\Core\YesWikiController; class ApiController extends YesWikiController { /** - * Get all users or one user's information. + * Attempt to login user. * - * @param string $username specify username + * @return string json + * + * @Route("/api/login",methods={"POST"}, options={"acl":{"public"}}) + */ + public function login() + { + if (filter_var($_POST['username'], FILTER_VALIDATE_EMAIL)) { + $user = $this->wiki->services->get(UserManager::class)->getOneByEmail($_POST['username']); + } else { + $user = $this->wiki->services->get(UserManager::class)->getOneByName($_POST['username']); + } + if (!$user) { + return new ApiResponse(['error' => _t('LOGIN_WRONG_USER')], Response::HTTP_UNAUTHORIZED); + } + $isRightPassword = $this->wiki->services->get(AuthController::class)->checkPassword($_POST['password'], $user); + if (!$isRightPassword) { + return new ApiResponse(['error' => _t('LOGIN_WRONG_PASSWORD')], Response::HTTP_UNAUTHORIZED); + } else { + $this->wiki->services->get(AuthController::class)->login($user); + + return new ApiResponse([ + 'user' => $user->getName(), + 'isAdmin' => $this->wiki->UserIsAdmin(), + ]); + } + } + + /** + * Return basic information if user is authenticated. * * @return string json + * + * @Route("/api/auth/me", options={"acl":{"public"}}) */ + public function getMyAuth() + { + $loggedUser = $this->wiki->services->get(AuthController::class)->getLoggedUser(); + if (!$loggedUser) { + return new ApiResponse(['error' => _t('LOGIN_NO_CONNECTED_USER')], Response::HTTP_UNAUTHORIZED); + } else { + return new ApiResponse([ + 'user' => $loggedUser['name'], + 'isAdmin' => $this->wiki->UserIsAdmin(), + ]); + } + } /** - * @Route("/api/auth/{username}") + * Get all users or one user's information. + * + * @param string $username specify username + * + * @return string json + * + * @Route("/api/auth/{username}",options={"acl":{"public"}}) */ public function getAuth($username = '') { $this->denyAccessUnlessAdmin(); $wiki = $this->wiki; if (!empty($username[0])) { - if ($wiki->UserIsAdmin() or $wiki->GetUserName() == $username[0]) { - $user = $wiki->LoadUser($username[0]); + if ($wiki->UserIsAdmin() || $wiki->services->get(AuthController::class)->getLoggedUserName() == $username[0]) { + $user = $wiki->services->get(UserManager::class)->getOneByName($username[0]); if ($user) { $response = $user; } else { @@ -35,7 +86,7 @@ public function getAuth($username = '') $response = ['error' => ['Unauthorized']]; } } else { - $users = $wiki->LoadUsers(); + $users = $wiki->services->get(UserManager::class)->getOneByName($username[0]); $response = $users; } @@ -43,7 +94,7 @@ public function getAuth($username = '') } /** - * @Route("/api/auth/") + * @Route("/api/auth/",options={"acl":{"public"}}) */ public function getAuthAll() { @@ -60,8 +111,12 @@ public function getAuthAll() public function getDocumentation() { $urlAuth = $this->wiki->href('', 'api/auth'); - $output = '

Extension login

' . "\n" . - '

GET ' . $urlAuth . '

'; + $output = '

Extension Login

' . "\n" . + '

GET ' . $urlAuth . ' Get all users (admin only)

' . + '

GET ' . $urlAuth . '/{user} Get indicated user (admin only)

' . + '

GET ' . $urlAuth . '/me Get basic info (username, isAdmin) for connected user (needs authenticated user)

' . + '

POST ' . $urlAuth . '/login login user with param user and password

' . + '

POST ' . $urlAuth . '/logout logout current connected user

'; return $output; } diff --git a/tools/login/lang/login_ca.inc.php b/tools/login/lang/login_ca.inc.php index 9344b2f06..a9fe81ae0 100644 --- a/tools/login/lang/login_ca.inc.php +++ b/tools/login/lang/login_ca.inc.php @@ -1,4 +1,5 @@ 'Registrar-se', 'LOGIN_LOGIN' => 'Connectar-se', diff --git a/tools/login/lang/login_en.inc.php b/tools/login/lang/login_en.inc.php index 74b2255c7..19e744c38 100644 --- a/tools/login/lang/login_en.inc.php +++ b/tools/login/lang/login_en.inc.php @@ -1,4 +1,5 @@ 'Signup', 'LOGIN_LOGIN' => 'Login', diff --git a/tools/login/lang/login_es.inc.php b/tools/login/lang/login_es.inc.php index 51cf6e503..a8d9f2f71 100644 --- a/tools/login/lang/login_es.inc.php +++ b/tools/login/lang/login_es.inc.php @@ -1,4 +1,5 @@ 'Inscribirse', 'LOGIN_LOGIN' => 'Conectarse', diff --git a/tools/login/lang/login_nl.inc.php b/tools/login/lang/login_nl.inc.php index 828e65b36..7e80d2f2e 100644 --- a/tools/login/lang/login_nl.inc.php +++ b/tools/login/lang/login_nl.inc.php @@ -1,4 +1,5 @@ 'Inschrijven', 'LOGIN_LOGIN' => 'Aanmelden', diff --git a/tools/login/lang/login_pt.inc.php b/tools/login/lang/login_pt.inc.php index bc89c0aed..d2127e3b3 100644 --- a/tools/login/lang/login_pt.inc.php +++ b/tools/login/lang/login_pt.inc.php @@ -1,4 +1,5 @@ 'Registrar', 'LOGIN_LOGIN' => 'Entrar', diff --git a/tools/security/lang/security_ca.inc.php b/tools/security/lang/security_ca.inc.php index 2cb89f66d..7a19eb610 100644 --- a/tools/security/lang/security_ca.inc.php +++ b/tools/security/lang/security_ca.inc.php @@ -1,4 +1,5 @@ 'No s\'ha pogut desar la pàgina. Potser heu clicat dues vegades el botó "desa" en un interval massa curt, o heu deixat la pàgina oberta en mode d\'edició massa estona. Per desar aquesta pàgina, copieu-ne sisplau el contingut, actualitzeu el vostre navegador i enganxeu el contingut abans de desar de nou.', 'HASHCASH_ANTISPAM_ACTIVATED' => 'Protecció contra el contingut no desitjat activada', diff --git a/tools/security/lang/security_en.inc.php b/tools/security/lang/security_en.inc.php index e66af561f..1448c32b0 100644 --- a/tools/security/lang/security_en.inc.php +++ b/tools/security/lang/security_en.inc.php @@ -1,4 +1,5 @@ 'This page could not be saved.
You may have clicked two times on the "Save" button, making two saved in an interval consired as too short, or leaved the page opened in edit mode for a too long period.
To save this page, please copy your content, refresh your browser, and paste the content before saving again.', 'HASHCASH_ANTISPAM_ACTIVATED' => 'Antispam protection activated', diff --git a/tools/security/lang/security_es.inc.php b/tools/security/lang/security_es.inc.php index ff15be08d..4b6cf655c 100644 --- a/tools/security/lang/security_es.inc.php +++ b/tools/security/lang/security_es.inc.php @@ -1,4 +1,5 @@ 'La página no se puede registrar.
Quizas has hecho clic dos veces al botón "Guardar" en un intervalo demasiado corto, o has dejado la página abierta en modo edición demasiado tiempo.
Para guardar tus modificaciones, copia su contenido, actualiza la página en tu navigador y pega tu página modificada de nuevo.', 'HASHCASH_ANTISPAM_ACTIVATED' => 'Protección anti-spam activada', diff --git a/tools/security/lang/security_nl.inc.php b/tools/security/lang/security_nl.inc.php index 1563494e3..f3644e2b4 100644 --- a/tools/security/lang/security_nl.inc.php +++ b/tools/security/lang/security_nl.inc.php @@ -1,4 +1,5 @@ 'De pagina kan niet worden opgeslagen.
Misschien hebt u dubbel geklikt op de toets "Opslaan", waardoor de pagina twee maal te snel na elkaar werd opgeslagen, of misschien hebt u de pagina te lang open laten staan in de bewerkingsmodus.
Om uw wijzigingen op te slaan, dient u de inhoud te kopiëren, de pagina te vernieuwen en uw gewijzigde pagina opnieuw te plakken.', 'HASHCASH_ANTISPAM_ACTIVATED' => 'Actieve anti-spambescherming', diff --git a/tools/security/lang/security_pt.inc.php b/tools/security/lang/security_pt.inc.php index 5a817f387..37cf37ec2 100644 --- a/tools/security/lang/security_pt.inc.php +++ b/tools/security/lang/security_pt.inc.php @@ -1,4 +1,5 @@ 'A página não pode ser salvo.
Talvez você clicou duas vezes no botão "Salvar", resultando em dois backups consecutivos demasiado perto, ou deixou a página em aberto no modo de edição demasiado tempo.
Para salvar suas alterações, por favor, copie o conteúdo, atualize a página e cole sua página editada novamente.', 'HASHCASH_ANTISPAM_ACTIVATED' => 'Proteção anti-spam ativa', diff --git a/tools/syndication/lang/syndication_ca.inc.php b/tools/syndication/lang/syndication_ca.inc.php index 1651fa2ab..9483dfda9 100644 --- a/tools/syndication/lang/syndication_ca.inc.php +++ b/tools/syndication/lang/syndication_ca.inc.php @@ -1,4 +1,5 @@ 'Acció {{syndication ...}}', diff --git a/tools/syndication/lang/syndication_en.inc.php b/tools/syndication/lang/syndication_en.inc.php index fcea295dc..a42c81097 100644 --- a/tools/syndication/lang/syndication_en.inc.php +++ b/tools/syndication/lang/syndication_en.inc.php @@ -1,4 +1,5 @@ 'Action {{syndication ...}}', diff --git a/tools/syndication/lang/syndication_es.inc.php b/tools/syndication/lang/syndication_es.inc.php index 484a07f0d..c348b9714 100644 --- a/tools/syndication/lang/syndication_es.inc.php +++ b/tools/syndication/lang/syndication_es.inc.php @@ -1,4 +1,5 @@ 'Acción {{syndication ...}}', diff --git a/tools/syndication/lang/syndication_nl.inc.php b/tools/syndication/lang/syndication_nl.inc.php index 5920a390e..27f3a7f53 100644 --- a/tools/syndication/lang/syndication_nl.inc.php +++ b/tools/syndication/lang/syndication_nl.inc.php @@ -1,4 +1,5 @@ 'Actie {{syndication ...}}', diff --git a/tools/syndication/lang/syndication_pt.inc.php b/tools/syndication/lang/syndication_pt.inc.php index 270383f73..340a99ff4 100644 --- a/tools/syndication/lang/syndication_pt.inc.php +++ b/tools/syndication/lang/syndication_pt.inc.php @@ -1,4 +1,5 @@ 'Ação {{syndication ...}}', diff --git a/tools/tags/lang/tags_ca.inc.php b/tools/tags/lang/tags_ca.inc.php index da9746503..06b5ff13f 100644 --- a/tools/tags/lang/tags_ca.inc.php +++ b/tools/tags/lang/tags_ca.inc.php @@ -1,4 +1,5 @@ 'Mots clés', 'TAGS_ACTION_ADMINTAGS' => 'Acció {{admintags ...}}', @@ -21,7 +22,7 @@ 'TAGS_SEE_ALL_PAGES_WITH_THIS_TAGS' => 'Mostra totes les pàgines que contenen aquest mot clau', 'TAGS_ALERT_PAGE_ALREADY_MODIFIED' => 'COMPTE: aquesta pàgina ha estat modificada per algú altre mentre l\'estàveu editant.
Copieu els vostres canvis i torneu a iniciar l\'edició.', 'TAGS_ANSWER_THIS_COMMENT' => 'Respon a aquest comentari', - 'TAGS_DATE_FORMAT' => "le d.m.Y a les H:i:s", + 'TAGS_DATE_FORMAT' => 'le d.m.Y a les H:i:s', 'TAGS_WRITE_YOUR_COMMENT_HERE' => 'Escriviu el vostre comentari aquí:', 'TAGS_ADD_YOUR_COMMENT' => 'Afegiu-hi el vostre comentari', 'TAGS_ACTION_FILTERTAGS' => 'Acció {{filtertags ...}}', diff --git a/tools/tags/lang/tags_en.inc.php b/tools/tags/lang/tags_en.inc.php index c1396e0ab..b31ac9504 100644 --- a/tools/tags/lang/tags_en.inc.php +++ b/tools/tags/lang/tags_en.inc.php @@ -1,4 +1,5 @@ 'Tags', 'TAGS_ACTION_ADMINTAGS' => 'Action {{admintags ...}}', diff --git a/tools/tags/lang/tags_es.inc.php b/tools/tags/lang/tags_es.inc.php index eaf8260fd..ee9461863 100644 --- a/tools/tags/lang/tags_es.inc.php +++ b/tools/tags/lang/tags_es.inc.php @@ -1,4 +1,5 @@ 'Mots clés', 'TAGS_ACTION_ADMINTAGS' => 'Acción {{admintags ...}}', @@ -21,7 +22,7 @@ 'TAGS_SEE_ALL_PAGES_WITH_THIS_TAGS' => 'Ver todas las páginas con la palabra clave', 'TAGS_ALERT_PAGE_ALREADY_MODIFIED' => 'Atención : Esta página ha sido modificada por otra persona mientras la estabas modificando tu.
Por favor, copia tus cambios y vuelve a editar esta página.', 'TAGS_ANSWER_THIS_COMMENT' => 'Responder a este comentario', - 'TAGS_DATE_FORMAT' => "le d.m.Y a les H:i:s", + 'TAGS_DATE_FORMAT' => 'le d.m.Y a les H:i:s', 'TAGS_WRITE_YOUR_COMMENT_HERE' => 'Escribir tu comentario aquí...', 'TAGS_ADD_YOUR_COMMENT' => 'Añadir tu comentario', 'TAGS_ACTION_FILTERTAGS' => 'Acción {{filtertags ...}}', diff --git a/tools/tags/lang/tags_nl.inc.php b/tools/tags/lang/tags_nl.inc.php index f26341bde..257d79462 100644 --- a/tools/tags/lang/tags_nl.inc.php +++ b/tools/tags/lang/tags_nl.inc.php @@ -1,4 +1,5 @@ 'Mots clés', 'TAGS_ACTION_ADMINTAGS' => 'Actie {{admintags ...}}', diff --git a/tools/tags/lang/tags_pt.inc.php b/tools/tags/lang/tags_pt.inc.php index 8be7a5594..52d34dc9c 100644 --- a/tools/tags/lang/tags_pt.inc.php +++ b/tools/tags/lang/tags_pt.inc.php @@ -1,4 +1,5 @@ 'Ação {{admintags ...}}', 'TAGS_ACTION_ADMINTAGS_ONLY_FOR_ADMINS' => 'a ação é restrita ao grupo de administradores', diff --git a/tools/tags/libs/tags.functions.php b/tools/tags/libs/tags.functions.php index 2fbe19775..e18273787 100755 --- a/tools/tags/libs/tags.functions.php +++ b/tools/tags/libs/tags.functions.php @@ -269,4 +269,4 @@ function filter_by_value($array, $index, $value) } return $newarray; -} \ No newline at end of file +} diff --git a/tools/templates/actions/barreredaction.php b/tools/templates/actions/barreredaction.php index a77979d02..4de1f2acd 100755 --- a/tools/templates/actions/barreredaction.php +++ b/tools/templates/actions/barreredaction.php @@ -21,8 +21,8 @@ $content = $this->LoadPage($page); $time = $content['time']; } - $barreredactionelements['page'] = $page; - $barreredactionelements['linkpage'] = $this->href('', $page); + $options['page'] = $page; + $options['linkpage'] = $this->href('', $page); // on choisit le template utilisé $template = $this->GetParameter('template'); @@ -30,20 +30,20 @@ $template = 'barreredaction_basic.twig'; } - // on peut ajouter des classes - $barreredactionelements['class'] = $this->GetParameter('class') || ''; + // on peut ajouter des classes, la classe par défaut est .footer + $options['class'] = ($this->GetParameter('class') ? 'footer ' . $this->GetParameter('class') : 'footer'); if ($this->HasAccess('write')) { // on ajoute le lien d'édition si l'action est autorisée if ($this->HasAccess('write', $page) && !$this->services->get(SecurityController::class)->isWikiHibernated()) { - $barreredactionelements['linkedit'] = $this->href('edit', $page); + $options['linkedit'] = $this->href('edit', $page); } if ($time) { // hack to hide E_STRICT error if no timezone set date_default_timezone_set(@date_default_timezone_get()); - $barreredactionelements['linkrevisions'] = $this->href('revisions', $page); - $barreredactionelements['time'] = date(_t('TEMPLATE_DATE_FORMAT'), strtotime($time)); + $options['linkrevisions'] = $this->href('revisions', $page); + $options['time'] = date(_t('TEMPLATE_DATE_FORMAT'), strtotime($time)); } // if this page exists @@ -51,48 +51,49 @@ $owner = $this->GetPageOwner($page); // message if ($this->UserIsOwner($page)) { - $barreredactionelements['owner'] = _t('TEMPLATE_OWNER') . ' : ' . _t('TEMPLATE_YOU'); + $options['owner'] = _t('TEMPLATE_OWNER') . ' : ' . _t('TEMPLATE_YOU'); } elseif ($owner) { - $barreredactionelements['owner'] = _t('TEMPLATE_OWNER') . ' : ' . $owner; + $options['owner'] = _t('TEMPLATE_OWNER') . ' : ' . $owner; } else { - $barreredactionelements['owner'] = _t('TEMPLATE_NO_OWNER'); + $options['owner'] = _t('TEMPLATE_NO_OWNER'); } // if current user is owner or admin if ($this->UserIsOwner($page) || $this->UserIsAdmin()) { - $barreredactionelements['owner'] .= ' - ' . _t('TEMPLATE_PERMISSIONS'); + $options['owner'] .= ' - ' . _t('TEMPLATE_PERMISSIONS'); if (!$this->services->get(SecurityController::class)->isWikiHibernated()) { - $barreredactionelements['linkacls'] = $this->href('acls', $page); - $barreredactionelements['linkdeletepage'] = $this->href('deletepage', $page); + $options['linkacls'] = $this->href('acls', $page); + $options['linkdeletepage'] = $this->href('deletepage', $page); } $aclsService = $this->services->get(AclService::class); $hasAccessComment = $aclsService->hasAccess('comment'); - $barreredactionelements['wikigroups'] = $this->GetGroupsList(); + $options['wikigroups'] = $this->GetGroupsList(); if ($this->services->get(ParameterBagInterface::class)->get('comments_activated')) { if ($hasAccessComment && $hasAccessComment !== 'comments-closed') { - $barreredactionelements['linkclosecomments'] = $this->href('claim', $page, ['action' => 'closecomments'], false); + $options['linkclosecomments'] = $this->href('claim', $page, ['action' => 'closecomments'], false); } else { - $barreredactionelements['linkopencomments'] = $this->href('claim', $page, ['action' => 'opencomments'], false); + $options['linkopencomments'] = $this->href('claim', $page, ['action' => 'opencomments'], false); } } } elseif (!$owner && $this->GetUser()) { - $barreredactionelements['owner'] .= ' - ' . _t('TEMPLATE_CLAIM'); + $options['owner'] .= ' - ' . _t('TEMPLATE_CLAIM'); if (!$this->services->get(SecurityController::class)->isWikiHibernated()) { - $barreredactionelements['linkacls'] = $this->href('claim', $page); + $options['linkacls'] = $this->href('claim', $page); } } } } - $barreredactionelements['linkshare'] = $this->href('share', $page); - $barreredactionelements['userIsOwner'] = $this->UserIsOwner($page); - $barreredactionelements['userIsAdmin'] = $this->UserIsAdmin(); - $barreredactionelements['userIsAdminOrOwner'] = $this->UserIsAdmin() || $this->UserIsOwner($page); + $options['linkduplicate'] = $this->href('duplicate', $page); + $options['linkshare'] = $this->href('share', $page); + $options['userIsOwner'] = $this->UserIsOwner($page); + $options['userIsAdmin'] = $this->UserIsAdmin(); + $options['userIsAdminOrOwner'] = $this->UserIsAdmin() || $this->UserIsOwner($page); $favoritesManager = $this->services->get(FavoritesManager::class); if (!empty($user) && $favoritesManager->areFavoritesActivated()) { - $barreredactionelements['currentuser'] = $user['name']; - $barreredactionelements['isUserFavorite'] = $favoritesManager->isUserFavorite($user['name'], $page); + $options['currentuser'] = $user['name']; + $options['isUserFavorite'] = $favoritesManager->isUserFavorite($user['name'], $page); } - echo $this->render("@templates/$template", $barreredactionelements); + echo $this->render("@templates/$template", $options); echo ' ' . "\n"; -} \ No newline at end of file +} diff --git a/tools/templates/actions/nav.php b/tools/templates/actions/nav.php index 1fe00d1a8..114198084 100644 --- a/tools/templates/actions/nav.php +++ b/tools/templates/actions/nav.php @@ -90,4 +90,4 @@ if (!empty($listlinks)) { echo ' ' . "\n"; -} \ No newline at end of file +} diff --git a/tools/templates/handlers/page/share.php b/tools/templates/handlers/page/share.php index e489ec5ab..0f4ef9b85 100755 --- a/tools/templates/handlers/page/share.php +++ b/tools/templates/handlers/page/share.php @@ -5,12 +5,12 @@ exit('accès direct interdit'); } -$html = '
' . _t('TEMPLATE_SHARE_FACEBOOK') . '' . "\n"; +$html = '' . _t('TEMPLATE_SHARE_FACEBOOK') . '' . "\n"; $html .= '' . _t('TEMPLATE_SHARE_TWITTER') . '' . "\n"; $html .= '' . _t('TEMPLATE_SHARE_NETVIBES') . '' . "\n"; $html .= '' . _t('TEMPLATE_SHARE_DELICIOUS') . '' . "\n"; $html .= '' . _t('TEMPLATE_SHARE_GOOGLEREADER') . '' . "\n"; -$html .= '' . _t('TEMPLATE_SHARE_MAIL') . '' . "\n"; +$html .= '' . _t('TEMPLATE_SHARE_MAIL') . '' . "\n"; $html .= '

' . "\n"; $html .= '
' . _t('TEMPLATE_SHARE_INCLUDE_CODE') . '
' . "\n"; $html .= "
\n";
@@ -36,4 +36,4 @@
     echo $this->Header();
     echo "
\n

" . _t('TEMPLATE_SEE_SHARING_OPTIONS') . ' ' . $this->GetPageTag() . "

\n$html\n
\n
\n"; echo $this->Footer(); -} \ No newline at end of file +} diff --git a/tools/templates/lang/templates_ca.inc.php b/tools/templates/lang/templates_ca.inc.php index a218cf15b..d55f3c946 100644 --- a/tools/templates/lang/templates_ca.inc.php +++ b/tools/templates/lang/templates_ca.inc.php @@ -1,4 +1,5 @@ 'Acció', // 'TEMPLATE_FILE_NOT_FOUND' => 'Template non trouvé', @@ -127,7 +128,7 @@ 'GERERTHEMES_PAGE' => 'Pàgina', 'AB_templates_tabs_bottom_nav_no' => 'No', 'AB_templates_tabs_counter_on_bottom_nav_no' => 'No', - 'AB_templates_nav_label' => "Tabs amb diferents pàgines", + 'AB_templates_nav_label' => 'Tabs amb diferents pàgines', 'AB_templates_section_textcolor_black' => 'Frozen', 'AB_templates_tabs_counter_on_bottom_nav_label' => 'Botons de navegació de número', 'ACLS_SELECT_PAGES_FILTER_ON_PAGES' => 'només pàgines', @@ -180,7 +181,7 @@ 'TEMPLATE_PRESET_FILENAME' => 'Nom del preestablert', 'TEMPLATE_THEME_NOT_SAVE' => 'Tema sense garantia', 'TEMPLATE_PRESETS' => 'Configuració gràfica', - 'TEMPLATE_PRESET_ERROR' => "No es pot aplicar aquest preestablert, hi ha un error!", + 'TEMPLATE_PRESET_ERROR' => 'No es pot aplicar aquest preestablert, hi ha un error!', 'TEMPLATE_CREATE_PRESET' => 'Crea una nova configuració gràfica', 'TEMPLATE_CUSTOMIZE_PRESET' => 'Configuració gràfica', 'AB_template_group_label' => 'Formal', @@ -257,7 +258,7 @@ 'AB_templates_section_visible_owner' => 'Titular de la pàgina', 'AB_templates_section_visible_no_container' => 'No posar un contenidor', 'AB_templates_tabs_label' => 'Tabs amb parts de la pàgina', - 'AB_templates_tabs_titles_label' => "Títols de pestanyes", + 'AB_templates_tabs_titles_label' => 'Títols de pestanyes', 'AB_templates_tabs_titles_hint' => 'Separa cada títol per una coma', 'AB_templates_tabs_titles_default' => 'Pestanya 1, Pestanya 2, Pestanya 3', 'AB_templates_tabs_btnsize_label' => 'Mida del botó', diff --git a/tools/templates/lang/templates_en.inc.php b/tools/templates/lang/templates_en.inc.php index 0c58c66b1..d1bb74ab0 100644 --- a/tools/templates/lang/templates_en.inc.php +++ b/tools/templates/lang/templates_en.inc.php @@ -1,4 +1,5 @@ 'Action', 'TEMPLATE_FILE_NOT_FOUND' => 'Template not found', @@ -361,7 +362,7 @@ 'TEMPLATE_ADD_CSS_PRESET_API_HINT' => 'Save a custom preset file', 'TEMPLATE_DELETE_CSS_PRESET_API_HINT' => 'Deletes a custom preset file', 'TEMPLATE_FILE_ALREADY_EXISTING' => 'The file is already existing! Change preset name or connect to admin!', - 'AB_template_action_ariane_label' => "Arane yarn", + 'AB_template_action_ariane_label' => 'Arane yarn', 'AB_template_action_col_size_total' => 'You have 12 virtual columns to be distributed', 'AB_template_action_col_example' => 'Text of your column to be changed later', 'AB_templates_nav_titles_label' => 'Title of your pages', diff --git a/tools/templates/lang/templates_es.inc.php b/tools/templates/lang/templates_es.inc.php index a59fd581c..130dd784d 100644 --- a/tools/templates/lang/templates_es.inc.php +++ b/tools/templates/lang/templates_es.inc.php @@ -1,4 +1,5 @@ 'Acción', // 'TEMPLATE_FILE_NOT_FOUND' => 'Template non trouvé', @@ -143,11 +144,11 @@ 'AB_template_actions_success' => 'Éxito', 'AB_template_actions_danger' => 'Peligro', 'AB_template_action_accordion_label' => 'Ver cajas en acordeón', - 'AB_template_action_ariane_label' => "Arane hilo", + 'AB_template_action_ariane_label' => 'Arane hilo', 'AB_template_action_col_label' => 'Columna', 'AB_template_action_col_size_total' => 'Usted tiene 12 columnas virtuales para ser distribuidas', 'AB_template_action_grid_label' => 'Mostrar múltiples columnas', - 'AB_templates_nav_label' => "Tabs con diferentes páginas", + 'AB_templates_nav_label' => 'Tabs con diferentes páginas', 'AB_templates_nav_description' => 'Generar un menú', 'AB_templates_nav_class_justified' => 'Justificado horizontal', 'AB_templates_panel_title_default' => 'Título de mi caja', @@ -194,7 +195,7 @@ 'TEMPLATE_LIGHT_COLOR' => 'Color claro', 'TEMPLATE_MAIN_TEXT_SIZE' => 'Tamaño del texto', 'TEMPLATE_FILE_ALREADY_EXISTING' => '¡El archivo ya está disponible! Cambiar el nombre predefinido o conectarse a admin!', - 'TEMPLATE_PRESET_ERROR' => "¡No puedes aplicar este preset, hay un error!", + 'TEMPLATE_PRESET_ERROR' => '¡No puedes aplicar este preset, hay un error!', 'AB_template_group_label' => 'Formal', 'AB_template_action_label_label' => 'Etiquette', 'AB_template_action_label_example' => 'Texto de su etiqueta para cambiar más tarde', @@ -299,7 +300,7 @@ 'AB_templates_section_visible_admins' => 'Admins only', 'AB_templates_section_visible_no_container' => 'No ponga un contenedor', 'AB_templates_tabs_label' => 'Tabs con partes de la página', - 'AB_templates_tabs_titles_label' => "Títulos de fichas", + 'AB_templates_tabs_titles_label' => 'Títulos de fichas', 'AB_templates_tabs_titles_hint' => 'Separar cada título por coma', 'AB_templates_tabs_titles_default' => 'Uñas 1, clavo 2, clavo 3', 'ACLS_SELECT_PAGES_FILTER_FORM' => 'formularios : {name} ({id})', diff --git a/tools/templates/lang/templates_fr.inc.php b/tools/templates/lang/templates_fr.inc.php index 46553cba3..baa7bdf46 100644 --- a/tools/templates/lang/templates_fr.inc.php +++ b/tools/templates/lang/templates_fr.inc.php @@ -1,4 +1,5 @@ 'Action', 'TEMPLATE_FILE_NOT_FOUND' => 'Template non trouvé', @@ -49,7 +50,14 @@ 'TEMPLATE_CLOSE_COMMENTS' => 'Fermer les commentaires', 'TEMPLATE_FOR_CONNECTED_PEOPLE' => 'Pour les personnes connectées', 'TEMPLATE_FOR_MEMBERS_OF_GROUP' => 'Pour les membres du groupe', - 'TEMPLATES_SEE_ATTACHED_FILES' => 'Voir les fichiers attachés à la page', + 'TEMPLATE_SEE_ATTACHED_FILES' => 'Voir les fichiers attachés à la page', + 'TEMPLATE_DUPLICATE' => 'Dupliquer', + 'TEMPLATE_DUPLICATE_PAGE' => 'Dupliquer la page', + 'TEMPLATE_DUPLICATE_LIST' => 'Dupliquer la liste', + 'TEMPLATE_DUPLICATE_ENTRY' => 'Dupliquer la fiche', + 'TEMPLATE_DUPLICATE_LOCALLY' => 'Dans ce YesWiki', + 'TEMPLATE_DUPLICATE_IN_ANOTHER_WIKI' => 'Dans un autre YesWiki', + // action/diaporama 'DIAPORAMA_PAGE_PARAM_MISSING' => 'Action diaporama : paramêtre "page" obligatoire.', 'DIAPORAMA_TEMPLATE_PARAM_ERROR' => 'Action diaporama : le paramêtre "template" pointe sur un fichier inexistant ou illisible. Le template par défaut sera utilisé.', @@ -172,7 +180,7 @@ 'AB_template_action_col_example' => 'Texte de votre colonne à changer par la suite', 'AB_template_col_size_label' => 'Largeur de la colonne', 'AB_template_action_grid_label' => 'Afficher plusieurs colonnes', - 'AB_templates_nav_label' => "Onglets avec des pages différentes", + 'AB_templates_nav_label' => 'Onglets avec des pages différentes', 'AB_templates_nav_description' => 'Générer un menu', 'AB_templates_nav_hint' => 'LeNomDeVotrePage doit être le nom de la page dans laquelle vous mettrez cette action. Pensez à coller le code obtenu dans chacune des pages des onglets.', 'AB_templates_nav_links_label' => 'Liens vers vos pages wiki', @@ -266,7 +274,7 @@ 'AB_templates_tabs_label' => 'Onglets avec des parties de la page', 'AB_templates_tabs_description' => 'Générer des onglets avec des parties de la page', 'AB_templates_tabs_hint' => 'Chaque contenu d\'onglet se trouve dans une action {{tab}}Contenu de l\'onglet.{{end elem="tab"}}', - 'AB_templates_tabs_titles_label' => "Titres des onglets", + 'AB_templates_tabs_titles_label' => 'Titres des onglets', 'AB_templates_tabs_titles_hint' => 'Séparer chaque titre par une virgule', 'AB_templates_tabs_titles_default' => 'Onglet 1, Onglet 2, Onglet 3', 'AB_templates_tabs_btnsize_label' => 'Taille de bouton', diff --git a/tools/templates/lang/templates_nl.inc.php b/tools/templates/lang/templates_nl.inc.php index 061ee5649..e33dd0c3e 100644 --- a/tools/templates/lang/templates_nl.inc.php +++ b/tools/templates/lang/templates_nl.inc.php @@ -1,4 +1,5 @@ 'Actie', // 'TEMPLATE_FILE_NOT_FOUND' => 'Template non trouvé', @@ -139,7 +140,7 @@ 'AB_templates_section_pattern_reverse' => 'Omkeren de kleuren van de textuur', 'AB_templates_section_shape_circ' => 'Circle', 'AB_templates_tabs_description' => 'Genereerde tabs met delen van de pagina', - 'AB_templates_tabs_titles_label' => "Titels", + 'AB_templates_tabs_titles_label' => 'Titels', 'AB_templates_tabs_titles_default' => 'Nagel 1, nagel 2, nagel 3', 'AB_templates_tabs_btnsize_label' => 'Button maat', 'AB_templates_tabs_btnsize_small' => 'Klein', @@ -181,7 +182,7 @@ 'TEMPLATE_DELETE_CSS_PRESET_API_HINT' => 'Verwijder een aangepaste dossier', 'TEMPLATE_CUSTOMIZE_PRESET' => 'Grafische configuratie', 'TEMPLATE_FILE_NOT_DELETED' => ' niet gewist!', - 'TEMPLATE_PRESET_ERROR' => "Je kunt dit preset niet toepassen, er is een fout!", + 'TEMPLATE_PRESET_ERROR' => 'Je kunt dit preset niet toepassen, er is een fout!', 'AB_template_group_label' => 'Formal', 'AB_template_action_label_label' => 'Etiquette', 'AB_template_action_label_example' => 'Sms je label later', @@ -193,7 +194,7 @@ 'AB_template_action_accordion_label' => 'View dozen in accordeon', 'AB_template_action_col_label' => 'Column', 'AB_template_action_col_size_total' => 'Je hebt 12 virtuele kolommen te verspreiden', - 'AB_template_action_ariane_label' => "Arane yarn", + 'AB_template_action_ariane_label' => 'Arane yarn', 'AB_templates_nav_links_default' => 'Pagina Name, LaSecondPage, LaTroisieme Pagina', 'AB_templates_nav_hint' => 'The Naame Pagina moet de naam van de pagina zijn waarin je deze actie zal plaatsen. Onthoud dat je de code in elke pagina van de tabs hebt.', 'AB_templates_nav_links_label' => 'Vertaling:', diff --git a/tools/templates/lang/templates_pt.inc.php b/tools/templates/lang/templates_pt.inc.php index 7eee68741..3eedf7ba8 100644 --- a/tools/templates/lang/templates_pt.inc.php +++ b/tools/templates/lang/templates_pt.inc.php @@ -1,4 +1,5 @@ 'Ação', // 'TEMPLATE_FILE_NOT_FOUND' => 'Template non trouvé', @@ -197,7 +198,7 @@ 'AB_templates_section_visible_connected_user' => 'Usuário conectado', 'AB_templates_section_visible_owner' => 'Proprietário da página', 'AB_templates_tabs_hint' => 'Cada conteúdo da aba está em uma ação {tab}}}Conteúdo da aba.{end elem="tab"}}', - 'AB_templates_tabs_titles_label' => "Títulos das abas", + 'AB_templates_tabs_titles_label' => 'Títulos das abas', 'AB_templates_tabs_counter_on_bottom_nav_yes' => 'Sim', 'ACLS_SELECT_PAGES_FILTER_ON_PAGES' => 'páginas somente', 'ACLS_SELECT_PAGES_FILTER_FORM' => 'formulários : {name} ({id})', @@ -216,7 +217,7 @@ 'TEMPLATE_PRIMARY_COLOR' => 'Primário', 'TEMPLATE_ADD_CSS_PRESET_API_HINT' => 'Salvar um arquivo predefinido personalizado', 'AB_template_actions_primary' => 'Primário', - 'AB_templates_nav_label' => "Tabs com páginas diferentes", + 'AB_templates_nav_label' => 'Tabs com páginas diferentes', 'AB_templates_nav_description' => 'Gerar um menu', 'AB_templates_nav_hint' => 'O teu nome A página deve ser o nome da página em que você vai colocar esta ação. Lembre-se de colar o código obtido em cada página das abas.', 'AB_templates_panel_type_collapsible' => 'Acordo aberto', @@ -251,7 +252,7 @@ 'TEMPLATE_MAIN_TITLE_FONT' => 'Polícia des titres', 'TEMPLATE_DELETE_CSS_PRESET' => 'Quer remover a predefinição personalizada', 'TEMPLATE_PRESET_FILENAME' => 'Nome da predefinição', - 'TEMPLATE_PRESET_ERROR' => "Não podes aplicar esta predefinição, há um erro!", + 'TEMPLATE_PRESET_ERROR' => 'Não podes aplicar esta predefinição, há um erro!', 'TEMPLATE_PRESETS' => 'Configurações gráficas', 'TEMPLATE_CUSTOMIZE_PRESET' => 'Configuração gráfica', 'AB_template_action_label_example' => 'Envie seu rótulo para mudar mais tarde', @@ -262,7 +263,7 @@ 'AB_template_actions_info' => 'Info', 'AB_template_actions_warning' => 'Atenção', 'AB_template_actions_danger' => 'Perigo', - 'AB_template_action_ariane_label' => "Fio de Arane", + 'AB_template_action_ariane_label' => 'Fio de Arane', 'AB_template_action_col_label' => 'Coluna', 'AB_template_action_col_size_total' => 'Você tem 12 colunas virtuais a serem distribuídas', 'AB_templates_nav_links_default' => 'Nome da Página, LaSecondPage, LaTroisieme Página', diff --git a/tools/templates/lang/templates_ta.inc.php b/tools/templates/lang/templates_ta.inc.php index fe52f28ce..e17b6e72d 100644 --- a/tools/templates/lang/templates_ta.inc.php +++ b/tools/templates/lang/templates_ta.inc.php @@ -1,4 +1,5 @@ 'செயல்', 'TEMPLATE_FILE_NOT_FOUND' => 'வார்ப்புரு அல்ல', diff --git a/tools/templates/templates/barreredaction_basic.twig b/tools/templates/templates/barreredaction_basic.twig index 9750869a9..e347d65ec 100644 --- a/tools/templates/templates/barreredaction_basic.twig +++ b/tools/templates/templates/barreredaction_basic.twig @@ -1,89 +1,137 @@ - +
+ {% if linkedit is defined %} + + {{ _t('TEMPLATE_EDIT_THIS_PAGE') }} + + {% endif %} + {% if userIsAdminOrOwner %} + + + + {% endif %} + + + + + {% if linkdeletepage is defined %} + + {{ _t('TEMPLATE_DELETE') }} + + {% endif %} + {% if time is defined %} + + {{ _t('TEMPLATE_LAST_UPDATE') }} {{ time }} + + {% endif %} + {% if linkacls is defined %} + + {{ owner ?? ''}} + + {% endif %} + {% if linkclosecomments is defined %} + + {{ _t('TEMPLATE_CLOSE_COMMENTS') }} + + {% endif %} + {% if linkopencomments is defined %} + + + + + {% endif %} + + {{ _t('TEMPLATE_SHARE') }} + + {% if currentuser is not empty %} + {{ include_javascript('javascripts/favorites.js') }} + + + {{ (isUserFavorite) ? _t('FAVORITES_REMOVE') : _t('FAVORITES_ADD') }} + + {% endif %} +