Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a440583691 | |||
| 6486d377b2 | |||
| 6c842ebe7f | |||
| 89c9771a84 |
+3
-2
@@ -1,5 +1,6 @@
|
|||||||
/plugins/
|
/plugins/*
|
||||||
!/plugins/
|
!/plugins/.gitkeep
|
||||||
!/plugins/cache-on-save/
|
!/plugins/cache-on-save/
|
||||||
|
!/plugins/story-blocks/
|
||||||
/data/
|
/data/
|
||||||
/pages/01.trips/italy-2026-demo/
|
/pages/01.trips/italy-2026-demo/
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ admin_next:
|
|||||||
accentHue: 271
|
accentHue: 271
|
||||||
accentSaturation: 91
|
accentSaturation: 91
|
||||||
fontFamily: inter
|
fontFamily: inter
|
||||||
|
pagesViewMode: tree
|
||||||
access:
|
access:
|
||||||
admin:
|
admin:
|
||||||
login: true
|
login: true
|
||||||
|
|||||||
+2
-3
@@ -1,10 +1,9 @@
|
|||||||
title: 'Into the East'
|
title: 'Into the East'
|
||||||
description: 'A travel blog by Mischa'
|
|
||||||
author:
|
author:
|
||||||
name: Mischa
|
name: Mischa
|
||||||
email: mischa@gorinskat.nl
|
email: mischa@gorinskat.nl
|
||||||
taxonomies: [category, tag]
|
|
||||||
metadata:
|
metadata:
|
||||||
description: 'Into the East — travel journal'
|
description: 'Into the East — travel journal'
|
||||||
active_trip: /trips/italy-2026-demo
|
description: 'A travel blog by Mischa'
|
||||||
|
active_trip: /trips/us-canada-mex-2024
|
||||||
travelling: true
|
travelling: true
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-08-28 07:49'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.png'
|
hero_image: 'photo-1.png'
|
||||||
lat: ''
|
lat: '52.5200'
|
||||||
lng: ''
|
lng: '13.4050'
|
||||||
location_city: 'Berlin'
|
location_city: 'Berlin'
|
||||||
location_country: 'Germany'
|
location_country: 'Germany'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '24'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Welcome to my picture diary of my 2023 adventure through Central Asia! Get ready for a visual journey through breathtaking landscapes and unforgettable moments! Join me as I explore the winding roads of Kazakhstan, Kyrgyzstan, Tajikistan, and Uzbekistan. Follow along as I share one picture per day, capturing unique experiences and adding stories to bring them to life. Get inspired and come along on this exciting adventure with me!
|
Welcome to my picture diary of my 2023 adventure through Central Asia! Get ready for a visual journey through breathtaking landscapes and unforgettable moments! Join me as I explore the winding roads of Kazakhstan, Kyrgyzstan, Tajikistan, and Uzbekistan. Follow along as I share one picture per day, capturing unique experiences and adding stories to bring them to life. Get inspired and come along on this exciting adventure with me!
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-08-29 10:29'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '52.36402'
|
||||||
lng: ''
|
lng: '13.50745'
|
||||||
location_city: 'Berlin'
|
location_city: 'Berlin'
|
||||||
location_country: 'Germany'
|
location_country: 'Germany'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '24'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Today the trip has become a reality, passed through security and waiting at the gate... A strange feeling, the months of anticipation are changing into a reality that so far only has lived in fantasy and bank statements... A last German beer to sooth that anxious feeling of knowing that for the next few months everything will be different!
|
Today the trip has become a reality, passed through security and waiting at the gate... A strange feeling, the months of anticipation are changing into a reality that so far only has lived in fantasy and bank statements... A last German beer to sooth that anxious feeling of knowing that for the next few months everything will be different!
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-08-30 18:06'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '51.140108'
|
||||||
lng: ''
|
lng: '71.429747'
|
||||||
location_city: ''
|
location_city: 'Astana'
|
||||||
location_country: ''
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '15'
|
||||||
weather_desc: ''
|
weather_desc: 'rainy'
|
||||||
---
|
---
|
||||||
|
|
||||||
A simple van, quite boring even if I'd say to myself after all I've seen today. Though this is not just some van, it's a UAZ "Buchanka". I do have a special and weird relationship with these cars, the little UAZ 469 brother as well. Within first 50 meters of my Hostel i saw this one and i couldn't resist capturing it on my camera... so far this is Number 2 i spotted during my trip! I'll keep the counter running...
|
A simple van, quite boring even if I'd say to myself after all I've seen today. Though this is not just some van, it's a UAZ "Buchanka". I do have a special and weird relationship with these cars, the little UAZ 469 brother as well. Within first 50 meters of my Hostel i saw this one and i couldn't resist capturing it on my camera... so far this is Number 2 i spotted during my trip! I'll keep the counter running...
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-08-31 16:45'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '51.128246'
|
||||||
lng: ''
|
lng: '71.430466'
|
||||||
location_city: 'Astana'
|
location_city: 'Astana'
|
||||||
location_country: 'Kazakhstan'
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '15'
|
||||||
weather_desc: ''
|
weather_desc: 'cloudy'
|
||||||
---
|
---
|
||||||
|
|
||||||
After finishing my Beshbarmak I was thinking it would be today's picture. Even though it's Kazakhstans main dish, it doesn't represent my day which was about Kazakhstans history and culture ... So.... Бәйтерек (Baïterek) a monument built to support the moving of the capital from Almaty to Astana. It symbolizes the mythical tree of live in which Samruk, the bird of happiness, has laid it's egg. A new beginning for Kazakhstan after its independence.
|
After finishing my Beshbarmak I was thinking it would be today's picture. Even though it's Kazakhstans main dish, it doesn't represent my day which was about Kazakhstans history and culture ... So.... Бәйтерек (Baïterek) a monument built to support the moving of the capital from Almaty to Astana. It symbolizes the mythical tree of live in which Samruk, the bird of happiness, has laid it's egg. A new beginning for Kazakhstan after its independence.
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-09-02 15:47'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '43.2220'
|
||||||
lng: ''
|
lng: '76.8512'
|
||||||
location_city: 'Almaty'
|
location_city: 'Almaty'
|
||||||
location_country: 'Kazakhstan'
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '25'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Last night I took a 15 hour train ride from Astana to Almaty. A modern train with a bar and self prepared Doshirak noodles.
|
Last night I took a 15 hour train ride from Astana to Almaty. A modern train with a bar and self prepared Doshirak noodles.
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-09-03 16:38'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '43.2220'
|
||||||
lng: ''
|
lng: '76.8512'
|
||||||
location_city: 'Almaty'
|
location_city: 'Almaty'
|
||||||
location_country: 'Kazakhstan'
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '24'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Almaty, a wonderful city in which I realise will not be able to spend enough time. Its more modern (it has so many bikelanes), has more character than Astana, but also is on the border with beautiful nature...
|
Almaty, a wonderful city in which I realise will not be able to spend enough time. Its more modern (it has so many bikelanes), has more character than Astana, but also is on the border with beautiful nature...
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-04 15:50'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '43.35102'
|
||||||
lng: ''
|
lng: '79.08010'
|
||||||
location_city: ''
|
location_city: 'Charyn Canyon'
|
||||||
location_country: ''
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '18'
|
||||||
weather_desc: ''
|
weather_desc: 'cloudy with showers'
|
||||||
---
|
---
|
||||||
|
|
||||||
The adventure started, a big jeep, few adventurous tourists and our guide Aybek.
|
The adventure started, a big jeep, few adventurous tourists and our guide Aybek.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-05 15:50'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '43.068370'
|
||||||
lng: ''
|
lng: '78.412857'
|
||||||
location_city: ''
|
location_city: 'Kaindy / Kolsai'
|
||||||
location_country: ''
|
location_country: 'Kazakhstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '20'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
The planned focus of today was nature! Seeing Kaindy and Kolsai lakes. They are amazingly beautiful.
|
The planned focus of today was nature! Seeing Kaindy and Kolsai lakes. They are amazingly beautiful.
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-09-07 17:00'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '42.4900'
|
||||||
lng: ''
|
lng: '78.3936'
|
||||||
location_city: 'Karakol'
|
location_city: 'Karakol'
|
||||||
location_country: 'Kyrgyzstan'
|
location_country: 'Kyrgyzstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '0'
|
||||||
weather_desc: ''
|
weather_desc: 'partly cloudy'
|
||||||
---
|
---
|
||||||
|
|
||||||
Via the border at Kegen, I made it to Karakol. Ala Kol is the most beautiful of all Kyrgyz lakes! In a good mood I set out and after taking a drive with a UAZ 469B 😎 I started going up. 500 meters upward and 15km further I found a camp to spend the night. Next I planned to go to the lake and take the same route back. This track is not for inexperienced hikers. After a 300 meter incline I decided to go back and not get stuck with 0 energy. Im proud of my achievement as a first time hiker!
|
Via the border at Kegen, I made it to Karakol. Ala Kol is the most beautiful of all Kyrgyz lakes! In a good mood I set out and after taking a drive with a UAZ 469B 😎 I started going up. 500 meters upward and 15km further I found a camp to spend the night. Next I planned to go to the lake and take the same route back. This track is not for inexperienced hikers. After a 300 meter incline I decided to go back and not get stuck with 0 energy. Im proud of my achievement as a first time hiker!
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-10 06:16'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '42.876640'
|
||||||
lng: ''
|
lng: '74.603745'
|
||||||
location_city: ''
|
location_city: 'Bishkek'
|
||||||
location_country: ''
|
location_country: 'Kyrgyzstan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '16'
|
||||||
weather_desc: ''
|
weather_desc: 'partly cloudy'
|
||||||
---
|
---
|
||||||
|
|
||||||
Kyrgyzstan is a beautiful country with many mountains, beautiful lakes, friendly people and no seatbelts. I definitely did not get a full grasp of it all... Just a brief morning in Karakol half a day in Bishkek, room with a view, and a quick flight to OSU for just half an evening... I did however start to explore the many different teas they serve here. Now the adventure continuous toward the Pamir mountains in Tajikistan!
|
Kyrgyzstan is a beautiful country with many mountains, beautiful lakes, friendly people and no seatbelts. I definitely did not get a full grasp of it all... Just a brief morning in Karakol half a day in Bishkek, room with a view, and a quick flight to OSU for just half an evening... I did however start to explore the many different teas they serve here. Now the adventure continuous toward the Pamir mountains in Tajikistan!
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-18 03:20'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '39.384414'
|
||||||
lng: ''
|
lng: '73.322529'
|
||||||
location_city: ''
|
location_city: 'Akbaital Pass'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '16'
|
||||||
weather_desc: ''
|
weather_desc: 'partly cloudy'
|
||||||
---
|
---
|
||||||
|
|
||||||
10-09 - The day marks an end to being a guest in Kyrgyzstan and a beginning of being welcomed by Tajik hospitality. We drive from Osh to Karakul (TJ) and climb from about 1000 meters to nearly 4000 meters altitude. We cross the Akbaital Pass (4655m) and try to leave Kyrgyzstan.
|
10-09 - The day marks an end to being a guest in Kyrgyzstan and a beginning of being welcomed by Tajik hospitality. We drive from Osh to Karakul (TJ) and climb from about 1000 meters to nearly 4000 meters altitude. We cross the Akbaital Pass (4655m) and try to leave Kyrgyzstan.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-19 05:50'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '39.01250'
|
||||||
lng: ''
|
lng: '73.55978'
|
||||||
location_city: ''
|
location_city: 'Karakul'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '15'
|
||||||
weather_desc: ''
|
weather_desc: 'windy'
|
||||||
---
|
---
|
||||||
|
|
||||||
10-09 - In the middle of no mans land, right on the actual border, our new driver was waiting and we started our tour through Tajikistan. The epic and harsh nature of the Pamirs is spectacular and makes it unimaginable how people can survive here, especially In winter. We ended in Karakul, not Karakol where I was before. Kara means black, kul means lake. The lake has beautiful.colours depending on the sunlight, but its name comes from the fact thats its fed with ground (black) water.
|
10-09 - In the middle of no mans land, right on the actual border, our new driver was waiting and we started our tour through Tajikistan. The epic and harsh nature of the Pamirs is spectacular and makes it unimaginable how people can survive here, especially In winter. We ended in Karakul, not Karakol where I was before. Kara means black, kul means lake. The lake has beautiful.colours depending on the sunlight, but its name comes from the fact thats its fed with ground (black) water.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-19 06:04'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '37.755579'
|
||||||
lng: ''
|
lng: '73.271513'
|
||||||
location_city: ''
|
location_city: 'Alichur'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '15'
|
||||||
weather_desc: ''
|
weather_desc: 'windy'
|
||||||
---
|
---
|
||||||
|
|
||||||
11-09 - In this village live just a few hundred people and there is a small military base. There is a school and a mosque, a very hard to find shop (we did not succeed) and some water wells. People drive old, rugged, Soviet UAZs, its the only affordable machine that can survive the rocky roads.
|
11-09 - In this village live just a few hundred people and there is a small military base. There is a school and a mosque, a very hard to find shop (we did not succeed) and some water wells. People drive old, rugged, Soviet UAZs, its the only affordable machine that can survive the rocky roads.
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-09-20 16:19'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '38.5598'
|
||||||
lng: ''
|
lng: '68.7870'
|
||||||
location_city: 'Dushanbe'
|
location_city: 'Dushanbe'
|
||||||
location_country: 'Tajikistan'
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '28'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Dushanbe, a warm welcome back into civilization after the Pamirs. Another kind of weird modern city, the central park is beautiful and they have a huge flag. The pole was the largest in the world, till recently. Its over 150 meters and the flag weighs more than 700 kgs.
|
Dushanbe, a warm welcome back into civilization after the Pamirs. Another kind of weird modern city, the central park is beautiful and they have a huge flag. The pole was the largest in the world, till recently. Its over 150 meters and the flag weighs more than 700 kgs.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-23 08:41'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '37.032071'
|
||||||
lng: ''
|
lng: '72.630602'
|
||||||
location_city: ''
|
location_city: 'Zong'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '28'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
PMU14-9 - Zong (what a name, huh). We descended from the harsh Pamir Plateau into the greener Wakhan valley. Epic views and epic roads (our driver is a hero) we past in our study Toyota Landcruiser. To finally meet another mysterious land, that became an obsession in our group...
|
PMU14-9 - Zong (what a name, huh). We descended from the harsh Pamir Plateau into the greener Wakhan valley. Epic views and epic roads (our driver is a hero) we past in our study Toyota Landcruiser. To finally meet another mysterious land, that became an obsession in our group...
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-09-23 08:29'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '37.755660'
|
||||||
lng: ''
|
lng: '73.271591'
|
||||||
location_city: ''
|
location_city: 'Alichur'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '15'
|
||||||
weather_desc: ''
|
weather_desc: 'windy'
|
||||||
---
|
---
|
||||||
|
|
||||||
PMU13-9 - Alichur, slightly less harsh than Karakul, there is grass for yaks and sheep.
|
PMU13-9 - Alichur, slightly less harsh than Karakul, there is grass for yaks and sheep.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-10-01 10:40'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '36.983527'
|
||||||
lng: ''
|
lng: '72.264250'
|
||||||
location_city: ''
|
location_city: 'Ishkashim / Bibi Fatima'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '18'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
PMU15-9 - Along the way we visited a traditional Pamiri house. We've slept in quite a few with a similar design. The guide gave us insights in how people lived. Usually three/four generations shared a single house with usually two rooms. They were multipurpose rooms for cooking, living and sleeping.
|
PMU15-9 - Along the way we visited a traditional Pamiri house. We've slept in quite a few with a similar design. The guide gave us insights in how people lived. Usually three/four generations shared a single house with usually two rooms. They were multipurpose rooms for cooking, living and sleeping.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-10-01 10:51'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '37.49046'
|
||||||
lng: ''
|
lng: '71.53921'
|
||||||
location_city: ''
|
location_city: 'Khorog'
|
||||||
location_country: ''
|
location_country: 'Tajikistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '25'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Recap - When travelling to new places, I always wonder what is their "normal" and how much do i perceive this as "weird".
|
Recap - When travelling to new places, I always wonder what is their "normal" and how much do i perceive this as "weird".
|
||||||
|
|||||||
+7
-7
@@ -1,15 +1,15 @@
|
|||||||
---
|
---
|
||||||
title: 'Millionaires and Minarets in Bukhara'
|
title: 'Millionaires and Minarets in Bukhara'
|
||||||
date: '2023-09-23 08:14'
|
date: '2023-10-02 00:00'
|
||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '39.775957'
|
||||||
lng: ''
|
lng: '64.416693'
|
||||||
location_city: ''
|
location_city: 'Bukhara'
|
||||||
location_country: ''
|
location_country: 'Uzbekistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '25'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
In Uzbekistan everyone can be a millionaire, it only costs about €80. A handmade magnet costs 25k and a beer 30k. Definitely the hardest currency to convert in my mind this trip.
|
In Uzbekistan everyone can be a millionaire, it only costs about €80. A handmade magnet costs 25k and a beer 30k. Definitely the hardest currency to convert in my mind this trip.
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-10-03 07:58'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '40.37660'
|
||||||
lng: ''
|
lng: '49.84752'
|
||||||
location_city: 'Tbilisi'
|
location_city: 'Baku'
|
||||||
location_country: 'Georgia'
|
location_country: 'Azerbaijan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '24'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
The holiday adventure is over. 4 weeks of central Asia was just enough to scratch the surface on most countries and I definitely went to go back!
|
The holiday adventure is over. 4 weeks of central Asia was just enough to scratch the surface on most countries and I definitely went to go back!
|
||||||
|
|||||||
+6
-6
@@ -4,12 +4,12 @@ date: '2023-10-03 07:38'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '39.65841'
|
||||||
lng: ''
|
lng: '66.98542'
|
||||||
location_city: ''
|
location_city: 'Samarkand'
|
||||||
location_country: ''
|
location_country: 'Uzbekistan'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '25'
|
||||||
weather_desc: ''
|
weather_desc: 'sunny'
|
||||||
---
|
---
|
||||||
|
|
||||||
Samarkand, Amir Timur made this city great again as the capital of his vast empire. It sparked a wave of Islamic art inspired by the styles in Persia. The buildings are beautifully restored, sometimes with a little imagination. It gives however a great feeling of how these buildings must have looked like, simply beautiful!
|
Samarkand, Amir Timur made this city great again as the capital of his vast empire. It sparked a wave of Islamic art inspired by the styles in Persia. The buildings are beautifully restored, sometimes with a little imagination. It gives however a great feeling of how these buildings must have looked like, simply beautiful!
|
||||||
|
|||||||
+4
-4
@@ -4,12 +4,12 @@ date: '2023-10-18 07:38'
|
|||||||
template: entry
|
template: entry
|
||||||
published: true
|
published: true
|
||||||
hero_image: 'photo-1.jpg'
|
hero_image: 'photo-1.jpg'
|
||||||
lat: ''
|
lat: '41.6938'
|
||||||
lng: ''
|
lng: '44.8015'
|
||||||
location_city: 'Tbilisi'
|
location_city: 'Tbilisi'
|
||||||
location_country: 'Georgia'
|
location_country: 'Georgia'
|
||||||
weather_temp_c: ''
|
weather_temp_c: '20'
|
||||||
weather_desc: ''
|
weather_desc: 'partly cloudy'
|
||||||
---
|
---
|
||||||
|
|
||||||
Past weekend. I was fit enougto exploe more of Tbilisi. A hike in the nearby mountains gave great views of the city and the backside of the Mother of Georgia statue. So I went on a mission to capture her majestic front.... not so easy in a hily city, but I managed.
|
Past weekend. I was fit enougto exploe more of Tbilisi. A hike in the nearby mountains gave great views of the city and the backside of the Mother of Georgia statue. So I went on a mission to capture her majestic front.... not so easy in a hily city, but I managed.
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
title: 'Into the East'
|
||||||
|
visible: false
|
||||||
|
routable: true
|
||||||
|
routes:
|
||||||
|
default: /
|
||||||
|
---
|
||||||
|
|
||||||
|
Dispatches from foreign lands and places closer by. A few moments worth remembering, collected here while I'm between trips.
|
||||||
|
|
||||||
|
-- Mischa
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
# v3.3.0
|
|
||||||
## 09/14/2023
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
- Added support multiple slug_fields to form unique slug, either as comma separated list or as array. Many thanks to walkload for the [pull request](https://github.com/bleutzinn/grav-plugin-add-page-by-form/pull/65)
|
|
||||||
|
|
||||||
# v3.2.0
|
|
||||||
## 02/17/2023
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
- Fixed a problem when `pagefrontmatter.content` was set (issue [#63](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/63))
|
|
||||||
1. [](#bugfix)
|
|
||||||
- Fixed incorrect handling of using `pageconfig.parent: /` (issue [#59](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/59))
|
|
||||||
1. [](#improved)
|
|
||||||
- Added composer
|
|
||||||
|
|
||||||
# v3.1.0
|
|
||||||
## 12/13/2022
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
- Tested with PHP version 8 (8.1.10)
|
|
||||||
- Fixed some incorrect variable types in PHPDoc Comments
|
|
||||||
1. [](#bugfix)
|
|
||||||
- Changed the declaration of the function `sanitize` to "static". [#62](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/62)). Thanks to masetto for raising this issue.
|
|
||||||
|
|
||||||
# v3.0.4
|
|
||||||
## 03/28/2022
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
- A title containing diacritic characters prevented a form submit (issues [#56](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/56) and [#60](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/60)). Thanks goes to davay for the pull request.
|
|
||||||
|
|
||||||
# v3.0.3
|
|
||||||
## 05/29/2020
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
- Fixed not handling overwrite_mode setting properly, issue [#54](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/54), thanks to mooomooo for reporting and testing
|
|
||||||
|
|
||||||
# v3.0.2
|
|
||||||
## 05/17/2020
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
- Yet another release. This time just to synchronize the versioning number in 'bleuprints.yaml' and this Changelog. For interesting changes see v3.0.0.
|
|
||||||
|
|
||||||
# v3.0.1
|
|
||||||
## 05/17/2020
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
- Removed a newline between the version number and the date in this Changelog file in an attempt to restore the correct display of this file in the Grav repository
|
|
||||||
|
|
||||||
# v3.0.0
|
|
||||||
## 05/03/2020
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
- New 'overwrite_mode' option 'edit' allows for editing a page. Note: yet undocumented.
|
|
||||||
- Removing upload files is now handled
|
|
||||||
1. [](#bugfix)
|
|
||||||
- Switched to Laravel str_slug function to remedy problems with hyphens on some Windows systems
|
|
||||||
1. [](#improved)
|
|
||||||
* (Possibly breaking change:) Changed uploaded files data structure from numeric array to associative array
|
|
||||||
* (Possibly breaking change:) Changed default setting of 'physical_template_name' to 'true'
|
|
||||||
* Minimum Grav version is set to 1.6
|
|
||||||
|
|
||||||
# v2.4.1
|
|
||||||
## 04/12/2020
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Fixed a bug ([issue #52](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/52)) where an empty value for the 'slug' variable would delete folder(s). Thanks to [anton-mellit](https://github.com/anton-mellit) for reporting this.
|
|
||||||
|
|
||||||
# v2.4.0
|
|
||||||
## 01/28/2020
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added a new config variable 'physical_template_name' to make using the new page template name as the new page's file name optional.
|
|
||||||
1. [](#improved)
|
|
||||||
* Removed the Changelog entry that was included in [https://github.com/bleutzinn/grav-plugin-add-page-by-form/pull/47](PR #47) from this file as it was not in the Grav Changelog format and prevented changes showing up correctly in the Grav Plugins download section.
|
|
||||||
|
|
||||||
# v2.3.5
|
|
||||||
## 01/25/2020
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Add option to suppress loading of simpleMDE assets (reduces overhead if its known it will not be used)
|
|
||||||
|
|
||||||
# v2.3.4
|
|
||||||
## 01/20/2020
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Prepared a new release to mainly consolidate the fix "Use moveTo method not native copy to move uploaded files to final destination" and to bring this changelog format back in line with Grav requirements. Thanks to Dave Nichols (pd-giz-dave).
|
|
||||||
1. [](#improved)
|
|
||||||
* Also included the ability to use the new page template name as the new page's folder name. Thanks to Dave Nichols (pd-giz-dave).
|
|
||||||
|
|
||||||
# v2.3.3
|
|
||||||
## 12/05/2019
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Fixed inconsistancies in version numbering which prevented the addition of the latest updates in the Grav Plugin repository.
|
|
||||||
|
|
||||||
# v2.3.2
|
|
||||||
## 11/24/2019
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Prepared a new release to fix a bug in version numbering. The letter "v" appears to be case sensitive. The versions 2.3.0 and 2.3.1 were tagged with a capital "V" as V2.3.0 and V2.3.1 respectively. Previous versions were tagged using a lowercase "v". This difference causes the Grav Repository to think these are two different plugins.
|
|
||||||
|
|
||||||
# v2.3.1
|
|
||||||
## 10/10/2019
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Fixed a subsequent failure to save file uploads to new page folder (form field File with `destination: @self`) introduced with Grav version 1.6.11 ([issue #44](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/44)). Thanks goes to mahagr for tips and to tranduyhung for the fix itself.
|
|
||||||
|
|
||||||
# v2.3.0
|
|
||||||
## 06/06/2019
|
|
||||||
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Fixed the failure to save file uploads to new page folder (form field File with `destination: @self`) introduced with Grav version 1.6 ([issue #40](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/40))
|
|
||||||
|
|
||||||
# v2.2.0
|
|
||||||
## 04/15/2018
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added support for `process.redirect: @self-admin` ([issue #13](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/31))
|
|
||||||
1. [](#improved)
|
|
||||||
* Fixed a problem with uploading files
|
|
||||||
|
|
||||||
# v2.1.0
|
|
||||||
## 09/18/2017
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added support for taxonomy types and tags
|
|
||||||
|
|
||||||
# v2.0.0
|
|
||||||
## 06/18/2017
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added support for multiple textarea editors ([issue #21](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/21))
|
|
||||||
* Added support for `process.redirect: @self` ([issue #23](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/23))
|
|
||||||
* Added the `overwrite_mode` configuration frontmatter variable
|
|
||||||
* Added the `subroute` configuration frontmatter variable
|
|
||||||
* Added the `slug_field` configuration frontmatter variable
|
|
||||||
* Added filename sanitizing of uploaded files
|
|
||||||
1. [](#improved)
|
|
||||||
* In the form page frontmatter configuration variables are separated from variables which main purpose it is to get passed on to the new page
|
|
||||||
* Uploaded file properties are now included in the new page frontmatter
|
|
||||||
* Improved safe slug generator
|
|
||||||
* Removed "use editor" option from `blueprints.yaml` (to allow [issue #21](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/21))
|
|
||||||
* Extended `blueprints.yaml` to set "fallback" configuration values
|
|
||||||
1. [](#bugfix)
|
|
||||||
* Fixed an issue with form pages outside the web root ([issue #20](https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues/20))
|
|
||||||
* Fixed a problem that prevented having different destinations for file uploads
|
|
||||||
|
|
||||||
# v1.4.2
|
|
||||||
## 03/22/2017
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Cleaned up code for release.
|
|
||||||
|
|
||||||
# v1.4.1
|
|
||||||
## 02/16/2017
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Simplified YAML frontmatter formatting as suggested in
|
|
||||||
https://github.com/getgrav/grav/issues/1287#issuecomment-279965492
|
|
||||||
|
|
||||||
# v1.4.0
|
|
||||||
## 02/12/2017
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added the ability to include the File field in the form. When `destination` is `@self` uploaded files are stored in the new page folder.
|
|
||||||
|
|
||||||
# v1.3.2
|
|
||||||
## 01/31/2017
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Removed the spyc.php class dependency; the page creation and YAML frontmatter handling is now done "the Grav way".
|
|
||||||
|
|
||||||
# v1.3.1
|
|
||||||
## 01/15/2017
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Added jQuery as an asset.
|
|
||||||
|
|
||||||
# v1.3.0
|
|
||||||
## 12/31/2016
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added the SimpleMDE Markdown Editor.
|
|
||||||
|
|
||||||
# v1.2.2
|
|
||||||
## 12/29/2016
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Removed note about the (previous) test release in the ReadMe.
|
|
||||||
|
|
||||||
# v1.2.1
|
|
||||||
## 12/29/2016
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Improved the usage explanation in the ReadMe.
|
|
||||||
* Removed debug messages.
|
|
||||||
|
|
||||||
# v1.2.0
|
|
||||||
## 12/23/2016
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Improved new page route handling.
|
|
||||||
|
|
||||||
# v1.1.1
|
|
||||||
## 11/17/2016
|
|
||||||
|
|
||||||
1. [](#improved)
|
|
||||||
* Removed dependency of PECL YAML function yaml_emit() in favor of using vendor/spyc.php class.
|
|
||||||
|
|
||||||
# v1.1.0
|
|
||||||
## 11/16/2016
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Settings in the pagefrontmatter block in the form page frontmatter now are merged with values from form fields. Form field values ovverride the pagefrontmatter settings.
|
|
||||||
|
|
||||||
# v1.0.0
|
|
||||||
## 11/15/2016
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Added an extra form field: 'author'
|
|
||||||
* Added copying an (optional) frontmatter block from the form page frontmatter to the newly added page's frontmatter
|
|
||||||
|
|
||||||
# v0.2.0
|
|
||||||
## 11/13/2016
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* Plugin name changed to Add Page By Form (add-page-by-form)
|
|
||||||
* Added timestamp as date in page header (date format is taken from plugin config)
|
|
||||||
* Pages with identical titles are saved by adding a incremental number to the page slug (e.g. 'my-page\_2', 'my-page\_2', etc.)
|
|
||||||
* Added error handling
|
|
||||||
|
|
||||||
# v0.1.0
|
|
||||||
## 11/08/2016
|
|
||||||
|
|
||||||
1. [](#new)
|
|
||||||
* ChangeLog started...
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Ron Wardenier
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,444 +0,0 @@
|
|||||||
# Add Page By Form Plugin
|
|
||||||
|
|
||||||
The **Add Page By Form** Plugin is for [Grav CMS](http://github.com/getgrav/grav). It allows users to add a new page by filling in a form.
|
|
||||||
|
|
||||||
This plugin uses the possibilities of [custom frontmatter](https://learn.getgrav.org/content/headers#custom-page-headers). By setting your own variables in the form page frontmatter a priori and optionally letting users override these variable values by filling in corresponding form fields you can transport these data into the new page frontmatter.
|
|
||||||
|
|
||||||
The passing on of both the default settings and form field values entered by the end user to the new page frontmatter makes for an extremely configurable solution.
|
|
||||||
By mixing default settings and configuring the page form you can to a large extent control the appearence and behaviour of the newly added page by using the frontmatter variables present in the new page in a Twig template.
|
|
||||||
|
|
||||||
For example, a new page can act as a new blog post simply by setting the appropriate template variable in the form page definition (with the AntiMatter theme, this is `template: item`). That template value is inserted in the new page frontmatter and, so, will be used by Grav to display the new page.
|
|
||||||
|
|
||||||
|
|
||||||
## Security Warning
|
|
||||||
|
|
||||||
Allowing anonymous visitors to create pages is a potential website security risk. It is **strongly advised** to use the [Grav Login Plugin](https://github.com/getgrav/grav-plugin-login) or the [Private Grav Plugin](https://github.com/Diyzzuf/grav-plugin-private) **to restrict the page creation to logged in users only**.
|
|
||||||
|
|
||||||
This plugin itself does not provide any security measures. Please take this in consideration before using this plugin.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation and Configuration
|
|
||||||
|
|
||||||
Typically the plugin should be installed via [GPM](http://learn.getgrav.org/advanced/grav-gpm) (Grav Package Manager):
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/gpm install add-page-by-form
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively it can be installed via the [Admin Plugin](http://learn.getgrav.org/admin-panel/plugins).
|
|
||||||
|
|
||||||
Another option is to manualy install the plugin by [downloading](https://github.com/bleutzinn/grav-plugin-add-page-by-form/archive/master.zip) the plugin as a zip file. Copy the zip file to your `/user/plugins` directory, unzip it there and rename the folder to `add-page-by-form`.
|
|
||||||
|
|
||||||
### Configuration Defaults
|
|
||||||
|
|
||||||
Here is the default configuration in the configuration file `add-page-by-form.yaml` plus an explanation of the settings:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
enabled: true
|
|
||||||
date_display_format: 'd-m-Y g:ia'
|
|
||||||
default_title: 'My New Page'
|
|
||||||
default_content: 'No content.'
|
|
||||||
overwrite_mode: false
|
|
||||||
include_username: false
|
|
||||||
auto_taxonomy_types: false
|
|
||||||
use_editor_class: true
|
|
||||||
physical_template_name: true
|
|
||||||
```
|
|
||||||
- `enabled` determines whether the plugin is active or not;
|
|
||||||
- `date_display_format` sets a default date and time format;
|
|
||||||
- `default_title` will be used as a fallback for the new page title when no other value is set;
|
|
||||||
|
|
||||||
- `default_content` will be used as the page content for the new page when no other value is set;
|
|
||||||
- `include_username` sets whether or not the username of the currently logged in frontend user is included in the new page frontmatter;
|
|
||||||
- `overwrite_mode` determines how to act when a page with the same name or slug already exists;
|
|
||||||
- `auto_taxonomy_types` saves any new taxonomy types that were input by the user to the site configuration file `site.yaml`;
|
|
||||||
- `use_editor_class` determines whether or not to change a textarea field into a Markdown editor when the texture field includes the class "editor" (`classes: editor`);
|
|
||||||
- `physical_template_name` should normally not be used. For more information see the description in the section 'pageconfig' block variables.
|
|
||||||
|
|
||||||
|
|
||||||
### Customizing the default configuration
|
|
||||||
|
|
||||||
To keep your custom configuration when updating the plugin you need to use a configuration file which is stored in the `user/config/plugins` folder.
|
|
||||||
|
|
||||||
Simply edit the plugin options in the Admin panel and the changes will be saved to the configuration file in that location. If you don't use the Admin panel, copy the `add-page-by-form.yaml` default file to your `user/config/plugins` folder and use that copy to change configuration settings.
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Using this plugin requires:
|
|
||||||
|
|
||||||
- a normal page containing a Grav Form with a unique name that starts with "add_page";
|
|
||||||
- optionally, but required for usefulness, one or two blocks of extra page frontmatter variables in that page being:
|
|
||||||
- a 'pageconfig' block with variables that are used in the new page creation process;
|
|
||||||
- a 'pagefrontmatter' block with variables that are passed on to the new page frontmatter and can be processed by Twig along the way.
|
|
||||||
|
|
||||||
### Modifying frontmatter variables
|
|
||||||
|
|
||||||
Every frontmatter variable value can be changed by the user when an input field with the same name as the variable is included in the form.
|
|
||||||
|
|
||||||
The basic method of modifying is overriding or replacing an initial value. An extreme case of overriding a variable which is quite uncommon but illustrates the process well:
|
|
||||||
|
|
||||||
1. `overwrite_mode` is set in `add-page-by-form.yaml`
|
|
||||||
2. and can be changed in the Plugin configuration in the Admin Panel
|
|
||||||
3. can be set in the `pageconfig` block
|
|
||||||
4. and finally may be changed again by the end user when the form contains an `overwrite_mode` field.
|
|
||||||
|
|
||||||
### Page Headers / Frontmatter
|
|
||||||
This plugin makes extensive use of [Custom Page Headers](https://learn.getgrav.org/content/headers#custom-page-headers). Unfortunately the Grav documentation mixes the terms "frontmatter", "page headers" and simply "headers". This may be confusing at first. They [all](https://learn.getgrav.org/content/headers) refer to the optional top part of a Grav page which contains data in [YAML syntax](https://learn.getgrav.org/advanced/yaml).
|
|
||||||
|
|
||||||
|
|
||||||
## Form page Frontmatter
|
|
||||||
|
|
||||||
The frontmatter in the form page and the way it is handled by the plugin is where the flexibility of this plugin originates.
|
|
||||||
|
|
||||||
The form page frontmatter is divided into three sections or blocks:
|
|
||||||
|
|
||||||
1. So called 'root level' variables are intended to act upon the form page itself. They are not passed on to the new page;
|
|
||||||
2. the `pageconfig` block contains variables that are used by the plugin in the new page creation process and do get passed on to the new page frontmatter;
|
|
||||||
3. the `pagefrontmatter` block holds all other variables that must be passed on to the new page frontmatter.
|
|
||||||
|
|
||||||
### Root level variables
|
|
||||||
|
|
||||||
In the examples above the root level configuration options are:
|
|
||||||
|
|
||||||
- `title` sets the title of the page containing the form;
|
|
||||||
- `template: form` activates the form on this page (not required when the form page is named `form.md`);
|
|
||||||
- `form` defines the form.
|
|
||||||
|
|
||||||
From version 2, the use of `parent` in the, what is now called, root level block is deprecated. It is however still supported for backwards compatibility.
|
|
||||||
|
|
||||||
### 'pageconfig' block variables
|
|
||||||
|
|
||||||
In the optional pageconfig block you can set these, and only these, variables (other variables will be ignored):
|
|
||||||
|
|
||||||
- `parent` sets the parent page for the new page. This variable may be an absolute route (for example `parent: /user_contributions`) or a relative route (e.g. `parent: articles`. In case of an absolute route this route starts from the pages root. A relative route is regarded to start from the form page, so the new page will be a child page of the form page. The form page is also used as the parent page when the set parent page does not exist;
|
|
||||||
- `subroute` defines a route from the (initial) parent value. If one or more folders in the route do not exist they will be created;
|
|
||||||
- `slug_field` tells the plugin what field or fields to use as the new page's slug or folder name. Multiple form field names may be specified either using a comma separated string or as an array. When `slug_field` is missing the plugin tries to use the value of `title`;
|
|
||||||
- `overwrite_mode: true|false|edit` (default `false`) tells the plugin what to do when a page with the same name already exists. With `overwrite_mode: true` the existing page is overwritten. Any additional (media) files besides the page itself which are stored in the existing page folder are deleted as well. With `overwite_mode: false` the new page slug gets a sequential number attached at the end (for example "my-new-page-1" in case "my-new-page" exists).
|
|
||||||
Using `overwite_mode: edit` allows for the page being saved to it's existing folder respecting any already present uploaded files;
|
|
||||||
- `include_username: true|false` (default `false`) determines whether or not to include the username of a logged in frontend user in the new page frontmatter;
|
|
||||||
- `physical_template_name: true|false` (default `true`) does or does not cause the plugin to use the template name of the new page as that new page's filesystem filename. Defaults to "default" when no template is set in the 'pagefrontmatter' block. When set to `true` to avoid future confusion the frontmatter variable `template` is removed from the new page frontmatter.
|
|
||||||
|
|
||||||
#### A note on parent and subroute
|
|
||||||
|
|
||||||
Together the variables `parent` and `subroute` define the new page's destination. Or, in other words, together they set the path or route of the new page filesystem folder in the page structure.
|
|
||||||
|
|
||||||
The difference between parent and subroute worded in another way:
|
|
||||||
|
|
||||||
- Parent: works on a page level; when there is no page at the parent route, the form page is used as the parent;
|
|
||||||
- Subroute: works on a folder level; a subroute may consist of empty folders and if a folder in the subroute does not exist it gets created.
|
|
||||||
|
|
||||||
### 'pagefrontmatter' block variables
|
|
||||||
|
|
||||||
The content of the optional `pagefrontmatter` block will be included in the new page frontmatter.
|
|
||||||
|
|
||||||
|
|
||||||
## Form usage
|
|
||||||
|
|
||||||
The form page needs to use a [simple single form](https://learn.getgrav.org/forms/forms#create-a-simple-single-form).
|
|
||||||
|
|
||||||
Two examples are included at the end of this ReadMe file.
|
|
||||||
|
|
||||||
### Mandatory fields and values
|
|
||||||
|
|
||||||
#### Form Name
|
|
||||||
It is always a good thing to give each form a unique name, especially when multiple forms are used.
|
|
||||||
|
|
||||||
To pre fill form fields with default values the Form name must include the string "add_page". Valid names are for example `add_page.blogpost`, `add_page_profile`.
|
|
||||||
|
|
||||||
###Form Actions
|
|
||||||
|
|
||||||
**Custom Form processing** ( Important ! )
|
|
||||||
|
|
||||||
To let the plugin process the form after a Submit a custom process action must be set like so:
|
|
||||||
|
|
||||||
```
|
|
||||||
process:
|
|
||||||
-
|
|
||||||
add_page: true
|
|
||||||
```
|
|
||||||
|
|
||||||
**Redirect to the new page**
|
|
||||||
|
|
||||||
|
|
||||||
To show the new page to the user set the `redirect` action to the custom value `@self` or `@self-admin`.
|
|
||||||
|
|
||||||
When using `redirect: '@self'` the page will be shown as a regular web page, for example:
|
|
||||||
|
|
||||||
```
|
|
||||||
process:
|
|
||||||
-
|
|
||||||
add_page: true
|
|
||||||
-
|
|
||||||
redirect: '@self'
|
|
||||||
```
|
|
||||||
|
|
||||||
To open the new page in the Admin panel use `redirect: '@self-admin'`.
|
|
||||||
Note that this plugin does not handle the admin user authentication. If the Admin plugin is not installed or is inactive redirection occurs as if `@self` was used.
|
|
||||||
|
|
||||||
> Tip: using `@self-admin` is a very convenient way to learn how to use this plugin as it is easy to view and examine the source of the resulting new page including it's frontmatter in the Admin panel.
|
|
||||||
|
|
||||||
### Using a Markdown editor in textarea fields
|
|
||||||
When a `textarea` field is given the class `editor` it will use the [SimpleMDE Markdown Editor](https://simplemde.com).
|
|
||||||
|
|
||||||
|
|
||||||
## Value overrides
|
|
||||||
|
|
||||||
The variables which are defined and given a value in the `pageconfig` and `pagefrontmatter` blocks may be 'overridden' or in other words replaced by form input fields. In that respect these variables can be seen to hold a set of default values.
|
|
||||||
|
|
||||||
There is only one exception to the default variable override behaviour and that is the handling of `taxonomy` types. Extra taxonomy types and values (for example tags) which are entered via form fields are added to the new page taxonomy.
|
|
||||||
|
|
||||||
To override a default value by user input is simply a matter of including a form field by the same name in the page form.
|
|
||||||
For example in the example 2 - _create a new blog post_, the default title is set to "My new Blog post". The form contains a form field of type text with `name: title`. Thus the user is prompted to enter a title for the new page in the form but does not need to do so because filling in the title field is not mandatory. If the user enters a title that value is used as the title for the new page. If he or she does not, the default title "My new Blog post" will be used.
|
|
||||||
|
|
||||||
|
|
||||||
## Setting taxonomy categories and tags
|
|
||||||
|
|
||||||
The Add Blog Post example shows how to let the user add extra tags via the form.
|
|
||||||
Extra categories may be added in the same way.
|
|
||||||
|
|
||||||
|
|
||||||
## Handling extra taxonomy types
|
|
||||||
|
|
||||||
By default Grav 'knows' two taxonomy types, `category` and `tag`. Extra taxonomy types may be defined and added just like with any other variables you can include a form field. The new type is then added to the list of taxonomy types instead of replacing the existing types.
|
|
||||||
|
|
||||||
This can be done in the `pagefrontmatter` block. For example, to define a new taxonomy type named 'department':
|
|
||||||
|
|
||||||
```
|
|
||||||
pagefrontmatter:
|
|
||||||
taxonomy:
|
|
||||||
- department
|
|
||||||
```
|
|
||||||
And/or in the form:
|
|
||||||
|
|
||||||
```
|
|
||||||
form:
|
|
||||||
name: my_form
|
|
||||||
fields:
|
|
||||||
-
|
|
||||||
name: taxonomy
|
|
||||||
label: Taxonomy type
|
|
||||||
type: text
|
|
||||||
```
|
|
||||||
|
|
||||||
This is a feature which calls for a solid look-before-you-leap approach because of it's side effects. Using a new taxonomy type requires it to be included in the list of known taxonomy types. This list is in the site configuration file `site.yaml`.
|
|
||||||
|
|
||||||
By setting the plugin configuration option `auto_taxonomy_types: true` new types get automatically saved and can then be used in a collection.
|
|
||||||
|
|
||||||
The side effect and possibly downside is that every modification of the site configuration file causes Grav to rebuild the cache, so this may not be desirable with larger sites.
|
|
||||||
Use with caution!
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
The least error prone way to test and play with the examples is to set up a fresh Grav site and using it's default theme Antimatter.
|
|
||||||
|
|
||||||
### Form page example 1: create a normal page
|
|
||||||
|
|
||||||
The goal of this example is to show how to let a user create a new page where uploaded images and files are saved along the page (in the same folder). After the user clicked Submit he or she will be shown the new page.
|
|
||||||
|
|
||||||
Suppose this minimal Grav website structure in `user/pages/`:
|
|
||||||
|
|
||||||
```
|
|
||||||
03.submit-assignment/
|
|
||||||
default.md
|
|
||||||
04.assignments/
|
|
||||||
cmpt363-e100/
|
|
||||||
default.md
|
|
||||||
drafts/
|
|
||||||
modular.md
|
|
||||||
reviewed/
|
|
||||||
modular.md
|
|
||||||
```
|
|
||||||
|
|
||||||
BTW both modular pages are not required but are mentioned as they could be used to display a collection of draft and reviewed assignments.
|
|
||||||
|
|
||||||
Then the 'Submit assignment for review' page (with slug `submit-assignment`) full content (both frontmatter and content) could look like:
|
|
||||||
|
|
||||||
```
|
|
||||||
---
|
|
||||||
routable: true
|
|
||||||
title: 'Submit assignment for review'
|
|
||||||
template: form
|
|
||||||
visible: true
|
|
||||||
pageconfig:
|
|
||||||
parent: /submitted-assignments/cmpt363-e100/drafts
|
|
||||||
pagefrontmatter:
|
|
||||||
visible: true
|
|
||||||
status: draft
|
|
||||||
template: default
|
|
||||||
course:
|
|
||||||
assignment: 'CMPT363 E100'
|
|
||||||
instructor:
|
|
||||||
name: 'Jane Doe'
|
|
||||||
form:
|
|
||||||
name: addpage-assignment-cmpt363-e100
|
|
||||||
fields:
|
|
||||||
-
|
|
||||||
name: name
|
|
||||||
label: Name
|
|
||||||
type: text
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
-
|
|
||||||
name: title
|
|
||||||
label: Title
|
|
||||||
type: text
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
-
|
|
||||||
name: content
|
|
||||||
label: 'Assignment text'
|
|
||||||
type: textarea
|
|
||||||
size: long
|
|
||||||
classes: editor
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
-
|
|
||||||
name: attachments
|
|
||||||
label: 'Attachment (PDF only)'
|
|
||||||
type: file
|
|
||||||
multiple: true
|
|
||||||
accept:
|
|
||||||
- application/pdf
|
|
||||||
validate:
|
|
||||||
required: false
|
|
||||||
-
|
|
||||||
name: honeypot
|
|
||||||
type: honeypot
|
|
||||||
buttons:
|
|
||||||
-
|
|
||||||
type: submit
|
|
||||||
value: Submit
|
|
||||||
process:
|
|
||||||
-
|
|
||||||
addpage: null
|
|
||||||
-
|
|
||||||
redirect: '@self'
|
|
||||||
---
|
|
||||||
|
|
||||||
Please write your assignment and attach any images and/or files.
|
|
||||||
```
|
|
||||||
|
|
||||||
Supposing the user has not changed the pre filled title field, has entered his name "Paul Walker", has entered a simple "q.e.d." as the assignment content and uploaded one PDF document, then the full new page will be:
|
|
||||||
|
|
||||||
```
|
|
||||||
---
|
|
||||||
visible: true
|
|
||||||
status: draft
|
|
||||||
course:
|
|
||||||
assignment: 'CMPT363 E100'
|
|
||||||
instructor:
|
|
||||||
name: 'Jane Doe'
|
|
||||||
name: 'Paul Walker'
|
|
||||||
title: 'CMPT363 E100'
|
|
||||||
attachments:
|
|
||||||
/Users/rwgc/devroot/repos/grav-test/htdocs/user/pages/assignments/cmpt363-e100/drafts/cmpt363-e100-1/scrum-guide-sept-2013.pdf
|
|
||||||
name: scrum-guide-sept-2013.pdf
|
|
||||||
type: application/pdf
|
|
||||||
size: 273 KB
|
|
||||||
path: /Users/rwgc/devroot/repos/grav-test/htdocs/user/pages/assignments/cmpt363-e100/drafts/cmpt363-e100-1/scrum-guide-sept-2013.pdf
|
|
||||||
---
|
|
||||||
|
|
||||||
q.e.d.
|
|
||||||
```
|
|
||||||
|
|
||||||
On the file system level the file structure will be:
|
|
||||||
|
|
||||||
```
|
|
||||||
01.home/
|
|
||||||
default.md
|
|
||||||
02.add-new-article/
|
|
||||||
default.md
|
|
||||||
03.assignments/
|
|
||||||
cmpt363-e100/
|
|
||||||
default.md
|
|
||||||
drafts/
|
|
||||||
cmpt363-e100-1/
|
|
||||||
default.md
|
|
||||||
scrum-guide-sept-2013.pdf
|
|
||||||
modular.md
|
|
||||||
reviewed/
|
|
||||||
modular.md
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Form page example 2: create a blog post
|
|
||||||
|
|
||||||
In this example the user can add a blog post. To ensure the new page will be treated as a blog post simply set the `template` variable to be used by the new page to `item`. BTW the active theme must include the corresponding template `item.html.twig`. This is why it is best to start with Grav's default theme Antimatter.
|
|
||||||
|
|
||||||
```
|
|
||||||
---
|
|
||||||
title: 'Add Blog Post'
|
|
||||||
template: form
|
|
||||||
pageconfig:
|
|
||||||
parent: '/blog'
|
|
||||||
include_username: true
|
|
||||||
overwrite_mode: true
|
|
||||||
pagefrontmatter:
|
|
||||||
template: item
|
|
||||||
title: My new Blog post
|
|
||||||
taxonomy:
|
|
||||||
category: blog
|
|
||||||
tag: [journal, guest]
|
|
||||||
form:
|
|
||||||
name: add_page.blogpost
|
|
||||||
fields:
|
|
||||||
-
|
|
||||||
name: author
|
|
||||||
label: 'Author'
|
|
||||||
type: text
|
|
||||||
-
|
|
||||||
name: title
|
|
||||||
label: 'Post Title'
|
|
||||||
type: text
|
|
||||||
-
|
|
||||||
name: taxonomy.tag
|
|
||||||
label: 'Tags (comma separated)'
|
|
||||||
type: text
|
|
||||||
-
|
|
||||||
name: content
|
|
||||||
label: 'Post Content'
|
|
||||||
type: textarea
|
|
||||||
size: long
|
|
||||||
classes: editor
|
|
||||||
-
|
|
||||||
name: images
|
|
||||||
label: 'Images to upload'
|
|
||||||
type: file
|
|
||||||
multiple: true
|
|
||||||
accept:
|
|
||||||
- 'image/*'
|
|
||||||
-
|
|
||||||
name: honeypot
|
|
||||||
type: honeypot
|
|
||||||
buttons:
|
|
||||||
-
|
|
||||||
type: submit
|
|
||||||
value: Submit
|
|
||||||
process:
|
|
||||||
-
|
|
||||||
add_page: true
|
|
||||||
-
|
|
||||||
redirect: '/blog'
|
|
||||||
---
|
|
||||||
|
|
||||||
## New Blog Post
|
|
||||||
|
|
||||||
Write your blog post:
|
|
||||||
```
|
|
||||||
After the form has been submitted the user is taken to the blog main page where the new post should show up.
|
|
||||||
|
|
||||||
|
|
||||||
## Issues
|
|
||||||
|
|
||||||
|
|
||||||
### Grav Form issue
|
|
||||||
|
|
||||||
The form on the form page is a standard Grav form. Please note that the Grav Form Plugin currently (latest test using version 4.0.1) has an issue which prevents the form to be submitted when a form field of type `file` is set to `required: true`(see issue [#106](https://github.com/getgrav/grav-plugin-form/issues/106)).
|
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
- Team Grav and everyone who contributes to Grav;
|
|
||||||
- Wes Cossick for [SimpleMDE Markdown Editor](https://simplemde.com);
|
|
||||||
- All [contributors](https://github.com/bleutzinn/grav-plugin-add-page-by-form/graphs/contributors) who've helped me out on things.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
|||||||
enabled: true
|
|
||||||
date_display_format: 'd-m-Y H:i'
|
|
||||||
default_title: 'My New Page'
|
|
||||||
default_content: 'No content.'
|
|
||||||
overwrite_mode: false
|
|
||||||
include_username: false
|
|
||||||
auto_taxonomy_types: false
|
|
||||||
use_editor_class: true
|
|
||||||
physical_template_name: true
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
.editor-toolbar a.active, .editor-toolbar a:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror, .CodeMirror-scroll {
|
|
||||||
min-height: 70px;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
$(function () {
|
|
||||||
$(".editor").each(function(){
|
|
||||||
var simplemde = new SimpleMDE({
|
|
||||||
element: this,
|
|
||||||
forceSync: true,
|
|
||||||
hideIcons: ["side-by-side", "fullscreen"],
|
|
||||||
spellChecker: false,
|
|
||||||
toolbar: ["bold", "italic", "heading", "|",
|
|
||||||
"quote", "unordered-list", "ordered-list", "|",
|
|
||||||
"link", "table", "|",
|
|
||||||
"undo", "redo", "|",
|
|
||||||
"preview", "guide"
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
name: Add Page By Form
|
|
||||||
version: 3.3.0
|
|
||||||
description: Adds a page by means of a form
|
|
||||||
icon: plus-square-o
|
|
||||||
author:
|
|
||||||
name: Ron Wardenier
|
|
||||||
email: ron@wardenier.com
|
|
||||||
homepage: https://github.com/bleutzinn/grav-plugin-add-page-by-form
|
|
||||||
keywords: grav, plugin, page, form, frontmatter
|
|
||||||
bugs: https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues
|
|
||||||
docs: https://github.com/bleutzinn/grav-plugin-add-page-by-form/blob/master/README.md
|
|
||||||
license: MIT
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- { name: grav, version: '>=1.6.0' }
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: strict
|
|
||||||
fields:
|
|
||||||
enabled:
|
|
||||||
type: toggle
|
|
||||||
label: Plugin status
|
|
||||||
highlight: 1
|
|
||||||
default: 0
|
|
||||||
options:
|
|
||||||
1: Enabled
|
|
||||||
0: Disabled
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
default_title:
|
|
||||||
type: text
|
|
||||||
size: large
|
|
||||||
label: Default Page Title
|
|
||||||
help: Will be used for the new page folder name when no other value is set
|
|
||||||
default_content:
|
|
||||||
type: text
|
|
||||||
size: large
|
|
||||||
label: Default Page Content
|
|
||||||
help: Will be used as the page content for the new page when no other value is set
|
|
||||||
include_username:
|
|
||||||
type: toggle
|
|
||||||
label: Include username
|
|
||||||
help: Include the logged in user username in the new page frontmatter
|
|
||||||
highlight: 0
|
|
||||||
default: 0
|
|
||||||
options:
|
|
||||||
1: Enabled
|
|
||||||
0: Disabled
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
overwrite_mode:
|
|
||||||
type: select
|
|
||||||
label: Overwrite mode
|
|
||||||
help: Overwrite existing page
|
|
||||||
highlight: 0
|
|
||||||
default: false
|
|
||||||
options:
|
|
||||||
0: Disabled
|
|
||||||
1: Enabled
|
|
||||||
edit: Edit
|
|
||||||
auto_taxonomy_types:
|
|
||||||
type: toggle
|
|
||||||
label: Add new taxonomy types
|
|
||||||
help: Automatically add new taxonomy types to site configuration. May have performance impact on large sites.
|
|
||||||
highlight: 0
|
|
||||||
default: 0
|
|
||||||
options:
|
|
||||||
1: Enabled
|
|
||||||
0: Disabled
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
use_editor_class:
|
|
||||||
type: toggle
|
|
||||||
label: Use the editor class
|
|
||||||
help: When set, adding class=editor to a textarea provides the simpleMDE editor on that area
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: Enabled
|
|
||||||
0: Disabled
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
date_display_format:
|
|
||||||
type: select
|
|
||||||
size: medium
|
|
||||||
classes: fancy
|
|
||||||
label: Date Format
|
|
||||||
default: 'd-m-Y H:i'
|
|
||||||
options:
|
|
||||||
'F jS Y': "February 1st 2014"
|
|
||||||
'l jS of F': "Saturday 1st of February"
|
|
||||||
'D, m M Y': "Sat, 01 Feb 2014"
|
|
||||||
'd-m-y': "01-02-14"
|
|
||||||
'd-m-Y': "01-02-2014"
|
|
||||||
'jS M Y': "1st Feb 2014"
|
|
||||||
'F Y': "Feb 2014"
|
|
||||||
'Y-m-d': "2014-02-01"
|
|
||||||
'd-m-Y H:i': "01-02-2014 09:30"
|
|
||||||
physical_template_name:
|
|
||||||
type: toggle
|
|
||||||
label: Physical template name
|
|
||||||
help: Use the template name in the filename of the new page
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: Enabled
|
|
||||||
0: Disabled
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "bleutzinn/grav-plugin-add-page-by-form",
|
|
||||||
"type": "grav-plugin",
|
|
||||||
"description": "Adds a page by means of a form",
|
|
||||||
"keywords": ["grav", "plugin", "page", "form", "frontmatter"],
|
|
||||||
"homepage": "https://github.com/bleutzinn/grav-plugin-add-page-by-form",
|
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Ron Wardenier",
|
|
||||||
"email": "bleutzinn@rwgc.nl",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/bleutzinn/grav-plugin-add-page-by-form/issues",
|
|
||||||
"docs": "https://github.com/bleutzinn/grav-plugin-add-page-by-form/blob/master/README.md"
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=7.1.3"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Grav\\Plugin\\AddPageByFormPlugin\\": "classes/"
|
|
||||||
},
|
|
||||||
"classmap": [
|
|
||||||
"add-page-by-form.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"platform": {
|
|
||||||
"php": "7.1.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
-23
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"_readme": [
|
|
||||||
"This file locks the dependencies of your project to a known state",
|
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
|
||||||
"This file is @generated automatically"
|
|
||||||
],
|
|
||||||
"content-hash": "3d1383f8c010e20d78cbeeba97140c36",
|
|
||||||
"packages": [],
|
|
||||||
"packages-dev": [],
|
|
||||||
"aliases": [],
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"stability-flags": [],
|
|
||||||
"prefer-stable": false,
|
|
||||||
"prefer-lowest": false,
|
|
||||||
"platform": {
|
|
||||||
"php": ">=7.1.3"
|
|
||||||
},
|
|
||||||
"platform-dev": [],
|
|
||||||
"platform-overrides": {
|
|
||||||
"php": "7.1.3"
|
|
||||||
},
|
|
||||||
"plugin-api-version": "2.2.0"
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload.php @generated by Composer
|
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
|
||||||
|
|
||||||
return ComposerAutoloaderInit0206cd2f5513395c6d5551a767d5c39f::getLoader();
|
|
||||||
@@ -1,572 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of Composer.
|
|
||||||
*
|
|
||||||
* (c) Nils Adermann <naderman@naderman.de>
|
|
||||||
* Jordi Boggiano <j.boggiano@seld.be>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer\Autoload;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
|
||||||
*
|
|
||||||
* $loader = new \Composer\Autoload\ClassLoader();
|
|
||||||
*
|
|
||||||
* // register classes with namespaces
|
|
||||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
|
||||||
* $loader->add('Symfony', __DIR__.'/framework');
|
|
||||||
*
|
|
||||||
* // activate the autoloader
|
|
||||||
* $loader->register();
|
|
||||||
*
|
|
||||||
* // to enable searching the include path (eg. for PEAR packages)
|
|
||||||
* $loader->setUseIncludePath(true);
|
|
||||||
*
|
|
||||||
* In this example, if you try to use a class in the Symfony\Component
|
|
||||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
|
||||||
* the autoloader will first look for the class under the component/
|
|
||||||
* directory, and it will then fallback to the framework/ directory if not
|
|
||||||
* found before giving up.
|
|
||||||
*
|
|
||||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
|
||||||
*
|
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
|
||||||
* @see https://www.php-fig.org/psr/psr-0/
|
|
||||||
* @see https://www.php-fig.org/psr/psr-4/
|
|
||||||
*/
|
|
||||||
class ClassLoader
|
|
||||||
{
|
|
||||||
/** @var ?string */
|
|
||||||
private $vendorDir;
|
|
||||||
|
|
||||||
// PSR-4
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, array<string, int>>
|
|
||||||
*/
|
|
||||||
private $prefixLengthsPsr4 = array();
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, array<int, string>>
|
|
||||||
*/
|
|
||||||
private $prefixDirsPsr4 = array();
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, string>
|
|
||||||
*/
|
|
||||||
private $fallbackDirsPsr4 = array();
|
|
||||||
|
|
||||||
// PSR-0
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, array<string, string[]>>
|
|
||||||
*/
|
|
||||||
private $prefixesPsr0 = array();
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, string>
|
|
||||||
*/
|
|
||||||
private $fallbackDirsPsr0 = array();
|
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
private $useIncludePath = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
* @psalm-var array<string, string>
|
|
||||||
*/
|
|
||||||
private $classMap = array();
|
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
private $classMapAuthoritative = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool[]
|
|
||||||
* @psalm-var array<string, bool>
|
|
||||||
*/
|
|
||||||
private $missingClasses = array();
|
|
||||||
|
|
||||||
/** @var ?string */
|
|
||||||
private $apcuPrefix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var self[]
|
|
||||||
*/
|
|
||||||
private static $registeredLoaders = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ?string $vendorDir
|
|
||||||
*/
|
|
||||||
public function __construct($vendorDir = null)
|
|
||||||
{
|
|
||||||
$this->vendorDir = $vendorDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getPrefixes()
|
|
||||||
{
|
|
||||||
if (!empty($this->prefixesPsr0)) {
|
|
||||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return array<string, array<int, string>>
|
|
||||||
*/
|
|
||||||
public function getPrefixesPsr4()
|
|
||||||
{
|
|
||||||
return $this->prefixDirsPsr4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return array<string, string>
|
|
||||||
*/
|
|
||||||
public function getFallbackDirs()
|
|
||||||
{
|
|
||||||
return $this->fallbackDirsPsr0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return array<string, string>
|
|
||||||
*/
|
|
||||||
public function getFallbackDirsPsr4()
|
|
||||||
{
|
|
||||||
return $this->fallbackDirsPsr4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[] Array of classname => path
|
|
||||||
* @psalm-return array<string, string>
|
|
||||||
*/
|
|
||||||
public function getClassMap()
|
|
||||||
{
|
|
||||||
return $this->classMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string[] $classMap Class to filename map
|
|
||||||
* @psalm-param array<string, string> $classMap
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function addClassMap(array $classMap)
|
|
||||||
{
|
|
||||||
if ($this->classMap) {
|
|
||||||
$this->classMap = array_merge($this->classMap, $classMap);
|
|
||||||
} else {
|
|
||||||
$this->classMap = $classMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a set of PSR-0 directories for a given prefix, either
|
|
||||||
* appending or prepending to the ones previously set for this prefix.
|
|
||||||
*
|
|
||||||
* @param string $prefix The prefix
|
|
||||||
* @param string[]|string $paths The PSR-0 root directories
|
|
||||||
* @param bool $prepend Whether to prepend the directories
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function add($prefix, $paths, $prepend = false)
|
|
||||||
{
|
|
||||||
if (!$prefix) {
|
|
||||||
if ($prepend) {
|
|
||||||
$this->fallbackDirsPsr0 = array_merge(
|
|
||||||
(array) $paths,
|
|
||||||
$this->fallbackDirsPsr0
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->fallbackDirsPsr0 = array_merge(
|
|
||||||
$this->fallbackDirsPsr0,
|
|
||||||
(array) $paths
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$first = $prefix[0];
|
|
||||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
|
||||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($prepend) {
|
|
||||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
|
||||||
(array) $paths,
|
|
||||||
$this->prefixesPsr0[$first][$prefix]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
|
||||||
$this->prefixesPsr0[$first][$prefix],
|
|
||||||
(array) $paths
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a set of PSR-4 directories for a given namespace, either
|
|
||||||
* appending or prepending to the ones previously set for this namespace.
|
|
||||||
*
|
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
|
||||||
* @param string[]|string $paths The PSR-4 base directories
|
|
||||||
* @param bool $prepend Whether to prepend the directories
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function addPsr4($prefix, $paths, $prepend = false)
|
|
||||||
{
|
|
||||||
if (!$prefix) {
|
|
||||||
// Register directories for the root namespace.
|
|
||||||
if ($prepend) {
|
|
||||||
$this->fallbackDirsPsr4 = array_merge(
|
|
||||||
(array) $paths,
|
|
||||||
$this->fallbackDirsPsr4
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->fallbackDirsPsr4 = array_merge(
|
|
||||||
$this->fallbackDirsPsr4,
|
|
||||||
(array) $paths
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
|
||||||
// Register directories for a new namespace.
|
|
||||||
$length = strlen($prefix);
|
|
||||||
if ('\\' !== $prefix[$length - 1]) {
|
|
||||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
|
||||||
}
|
|
||||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
|
||||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
|
||||||
} elseif ($prepend) {
|
|
||||||
// Prepend directories for an already registered namespace.
|
|
||||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
|
||||||
(array) $paths,
|
|
||||||
$this->prefixDirsPsr4[$prefix]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Append directories for an already registered namespace.
|
|
||||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
|
||||||
$this->prefixDirsPsr4[$prefix],
|
|
||||||
(array) $paths
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a set of PSR-0 directories for a given prefix,
|
|
||||||
* replacing any others previously set for this prefix.
|
|
||||||
*
|
|
||||||
* @param string $prefix The prefix
|
|
||||||
* @param string[]|string $paths The PSR-0 base directories
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function set($prefix, $paths)
|
|
||||||
{
|
|
||||||
if (!$prefix) {
|
|
||||||
$this->fallbackDirsPsr0 = (array) $paths;
|
|
||||||
} else {
|
|
||||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a set of PSR-4 directories for a given namespace,
|
|
||||||
* replacing any others previously set for this namespace.
|
|
||||||
*
|
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
|
||||||
* @param string[]|string $paths The PSR-4 base directories
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setPsr4($prefix, $paths)
|
|
||||||
{
|
|
||||||
if (!$prefix) {
|
|
||||||
$this->fallbackDirsPsr4 = (array) $paths;
|
|
||||||
} else {
|
|
||||||
$length = strlen($prefix);
|
|
||||||
if ('\\' !== $prefix[$length - 1]) {
|
|
||||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
|
||||||
}
|
|
||||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
|
||||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns on searching the include path for class files.
|
|
||||||
*
|
|
||||||
* @param bool $useIncludePath
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setUseIncludePath($useIncludePath)
|
|
||||||
{
|
|
||||||
$this->useIncludePath = $useIncludePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be used to check if the autoloader uses the include path to check
|
|
||||||
* for classes.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function getUseIncludePath()
|
|
||||||
{
|
|
||||||
return $this->useIncludePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns off searching the prefix and fallback directories for classes
|
|
||||||
* that have not been registered with the class map.
|
|
||||||
*
|
|
||||||
* @param bool $classMapAuthoritative
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
|
||||||
{
|
|
||||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should class lookup fail if not found in the current class map?
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isClassMapAuthoritative()
|
|
||||||
{
|
|
||||||
return $this->classMapAuthoritative;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
|
||||||
*
|
|
||||||
* @param string|null $apcuPrefix
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setApcuPrefix($apcuPrefix)
|
|
||||||
{
|
|
||||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
|
||||||
*
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
public function getApcuPrefix()
|
|
||||||
{
|
|
||||||
return $this->apcuPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers this instance as an autoloader.
|
|
||||||
*
|
|
||||||
* @param bool $prepend Whether to prepend the autoloader or not
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function register($prepend = false)
|
|
||||||
{
|
|
||||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
|
||||||
|
|
||||||
if (null === $this->vendorDir) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($prepend) {
|
|
||||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
|
||||||
} else {
|
|
||||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
|
||||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters this instance as an autoloader.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function unregister()
|
|
||||||
{
|
|
||||||
spl_autoload_unregister(array($this, 'loadClass'));
|
|
||||||
|
|
||||||
if (null !== $this->vendorDir) {
|
|
||||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the given class or interface.
|
|
||||||
*
|
|
||||||
* @param string $class The name of the class
|
|
||||||
* @return true|null True if loaded, null otherwise
|
|
||||||
*/
|
|
||||||
public function loadClass($class)
|
|
||||||
{
|
|
||||||
if ($file = $this->findFile($class)) {
|
|
||||||
includeFile($file);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the path to the file where the class is defined.
|
|
||||||
*
|
|
||||||
* @param string $class The name of the class
|
|
||||||
*
|
|
||||||
* @return string|false The path if found, false otherwise
|
|
||||||
*/
|
|
||||||
public function findFile($class)
|
|
||||||
{
|
|
||||||
// class map lookup
|
|
||||||
if (isset($this->classMap[$class])) {
|
|
||||||
return $this->classMap[$class];
|
|
||||||
}
|
|
||||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (null !== $this->apcuPrefix) {
|
|
||||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
|
||||||
if ($hit) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = $this->findFileWithExtension($class, '.php');
|
|
||||||
|
|
||||||
// Search for Hack files if we are running on HHVM
|
|
||||||
if (false === $file && defined('HHVM_VERSION')) {
|
|
||||||
$file = $this->findFileWithExtension($class, '.hh');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $this->apcuPrefix) {
|
|
||||||
apcu_add($this->apcuPrefix.$class, $file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === $file) {
|
|
||||||
// Remember that this class does not exist.
|
|
||||||
$this->missingClasses[$class] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
|
||||||
*
|
|
||||||
* @return self[]
|
|
||||||
*/
|
|
||||||
public static function getRegisteredLoaders()
|
|
||||||
{
|
|
||||||
return self::$registeredLoaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $class
|
|
||||||
* @param string $ext
|
|
||||||
* @return string|false
|
|
||||||
*/
|
|
||||||
private function findFileWithExtension($class, $ext)
|
|
||||||
{
|
|
||||||
// PSR-4 lookup
|
|
||||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
|
||||||
|
|
||||||
$first = $class[0];
|
|
||||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
|
||||||
$subPath = $class;
|
|
||||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
|
||||||
$subPath = substr($subPath, 0, $lastPos);
|
|
||||||
$search = $subPath . '\\';
|
|
||||||
if (isset($this->prefixDirsPsr4[$search])) {
|
|
||||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
|
||||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
|
||||||
if (file_exists($file = $dir . $pathEnd)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSR-4 fallback dirs
|
|
||||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSR-0 lookup
|
|
||||||
if (false !== $pos = strrpos($class, '\\')) {
|
|
||||||
// namespaced class name
|
|
||||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
|
||||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
|
||||||
} else {
|
|
||||||
// PEAR-like class name
|
|
||||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($this->prefixesPsr0[$first])) {
|
|
||||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
|
||||||
if (0 === strpos($class, $prefix)) {
|
|
||||||
foreach ($dirs as $dir) {
|
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSR-0 fallback dirs
|
|
||||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PSR-0 include paths.
|
|
||||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scope isolated include.
|
|
||||||
*
|
|
||||||
* Prevents access to $this/self from included files.
|
|
||||||
*
|
|
||||||
* @param string $file
|
|
||||||
* @return void
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function includeFile($file)
|
|
||||||
{
|
|
||||||
include $file;
|
|
||||||
}
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of Composer.
|
|
||||||
*
|
|
||||||
* (c) Nils Adermann <naderman@naderman.de>
|
|
||||||
* Jordi Boggiano <j.boggiano@seld.be>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
use Composer\Autoload\ClassLoader;
|
|
||||||
use Composer\Semver\VersionParser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is copied in every Composer installed project and available to all
|
|
||||||
*
|
|
||||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
|
||||||
*
|
|
||||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
|
||||||
*/
|
|
||||||
class InstalledVersions
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var mixed[]|null
|
|
||||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
|
||||||
*/
|
|
||||||
private static $installed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool|null
|
|
||||||
*/
|
|
||||||
private static $canGetVendors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array[]
|
|
||||||
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
|
||||||
*/
|
|
||||||
private static $installedByVendor = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
|
||||||
*
|
|
||||||
* @return string[]
|
|
||||||
* @psalm-return list<string>
|
|
||||||
*/
|
|
||||||
public static function getInstalledPackages()
|
|
||||||
{
|
|
||||||
$packages = array();
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
$packages[] = array_keys($installed['versions']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (1 === \count($packages)) {
|
|
||||||
return $packages[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all package names with a specific type e.g. 'library'
|
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @return string[]
|
|
||||||
* @psalm-return list<string>
|
|
||||||
*/
|
|
||||||
public static function getInstalledPackagesByType($type)
|
|
||||||
{
|
|
||||||
$packagesByType = array();
|
|
||||||
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
foreach ($installed['versions'] as $name => $package) {
|
|
||||||
if (isset($package['type']) && $package['type'] === $type) {
|
|
||||||
$packagesByType[] = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $packagesByType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the given package is installed
|
|
||||||
*
|
|
||||||
* This also returns true if the package name is provided or replaced by another package
|
|
||||||
*
|
|
||||||
* @param string $packageName
|
|
||||||
* @param bool $includeDevRequirements
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (isset($installed['versions'][$packageName])) {
|
|
||||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the given package satisfies a version constraint
|
|
||||||
*
|
|
||||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
|
||||||
*
|
|
||||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
|
||||||
*
|
|
||||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
|
||||||
* @param string $packageName
|
|
||||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
|
||||||
{
|
|
||||||
$constraint = $parser->parseConstraints($constraint);
|
|
||||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
|
||||||
|
|
||||||
return $provided->matches($constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
|
||||||
*
|
|
||||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
|
||||||
* whether a given version of a package is installed, and not just whether it exists
|
|
||||||
*
|
|
||||||
* @param string $packageName
|
|
||||||
* @return string Version constraint usable with composer/semver
|
|
||||||
*/
|
|
||||||
public static function getVersionRanges($packageName)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (!isset($installed['versions'][$packageName])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ranges = array();
|
|
||||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
|
||||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
|
||||||
}
|
|
||||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
|
||||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
|
||||||
}
|
|
||||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
|
||||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
|
||||||
}
|
|
||||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
|
||||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode(' || ', $ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $packageName
|
|
||||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
|
||||||
*/
|
|
||||||
public static function getVersion($packageName)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (!isset($installed['versions'][$packageName])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $installed['versions'][$packageName]['version'];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $packageName
|
|
||||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
|
||||||
*/
|
|
||||||
public static function getPrettyVersion($packageName)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (!isset($installed['versions'][$packageName])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $installed['versions'][$packageName]['pretty_version'];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $packageName
|
|
||||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
|
||||||
*/
|
|
||||||
public static function getReference($packageName)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (!isset($installed['versions'][$packageName])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $installed['versions'][$packageName]['reference'];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $packageName
|
|
||||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
|
||||||
*/
|
|
||||||
public static function getInstallPath($packageName)
|
|
||||||
{
|
|
||||||
foreach (self::getInstalled() as $installed) {
|
|
||||||
if (!isset($installed['versions'][$packageName])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
|
||||||
*/
|
|
||||||
public static function getRootPackage()
|
|
||||||
{
|
|
||||||
$installed = self::getInstalled();
|
|
||||||
|
|
||||||
return $installed[0]['root'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the raw installed.php data for custom implementations
|
|
||||||
*
|
|
||||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
|
||||||
*/
|
|
||||||
public static function getRawData()
|
|
||||||
{
|
|
||||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
|
||||||
|
|
||||||
if (null === self::$installed) {
|
|
||||||
// only require the installed.php file if this file is loaded from its dumped location,
|
|
||||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
|
||||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
|
||||||
self::$installed = include __DIR__ . '/installed.php';
|
|
||||||
} else {
|
|
||||||
self::$installed = array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$installed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
|
||||||
*
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
|
||||||
*/
|
|
||||||
public static function getAllRawData()
|
|
||||||
{
|
|
||||||
return self::getInstalled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lets you reload the static array from another file
|
|
||||||
*
|
|
||||||
* This is only useful for complex integrations in which a project needs to use
|
|
||||||
* this class but then also needs to execute another project's autoloader in process,
|
|
||||||
* and wants to ensure both projects have access to their version of installed.php.
|
|
||||||
*
|
|
||||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
|
||||||
* the data it needs from this class, then call reload() with
|
|
||||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
|
||||||
* the project in which it runs can then also use this class safely, without
|
|
||||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
|
||||||
*
|
|
||||||
* @param array[] $data A vendor/composer/installed.php data set
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
|
||||||
*/
|
|
||||||
public static function reload($data)
|
|
||||||
{
|
|
||||||
self::$installed = $data;
|
|
||||||
self::$installedByVendor = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array[]
|
|
||||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
|
||||||
*/
|
|
||||||
private static function getInstalled()
|
|
||||||
{
|
|
||||||
if (null === self::$canGetVendors) {
|
|
||||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
|
||||||
}
|
|
||||||
|
|
||||||
$installed = array();
|
|
||||||
|
|
||||||
if (self::$canGetVendors) {
|
|
||||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
|
||||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
|
||||||
$installed[] = self::$installedByVendor[$vendorDir];
|
|
||||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
|
||||||
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
|
||||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
|
||||||
self::$installed = $installed[count($installed) - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === self::$installed) {
|
|
||||||
// only require the installed.php file if this file is loaded from its dumped location,
|
|
||||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
|
||||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
|
||||||
self::$installed = require __DIR__ . '/installed.php';
|
|
||||||
} else {
|
|
||||||
self::$installed = array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$installed[] = self::$installed;
|
|
||||||
|
|
||||||
return $installed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is furnished
|
|
||||||
to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload_classmap.php @generated by Composer
|
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
|
||||||
$baseDir = dirname($vendorDir);
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
|
||||||
'Grav\\Plugin\\AddPageByFormPlugin' => $baseDir . '/add-page-by-form.php',
|
|
||||||
);
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload_namespaces.php @generated by Composer
|
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
|
||||||
$baseDir = dirname($vendorDir);
|
|
||||||
|
|
||||||
return array(
|
|
||||||
);
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload_psr4.php @generated by Composer
|
|
||||||
|
|
||||||
$vendorDir = dirname(dirname(__FILE__));
|
|
||||||
$baseDir = dirname($vendorDir);
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'Grav\\Plugin\\AddPageByFormPlugin\\' => array($baseDir . '/classes'),
|
|
||||||
);
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload_real.php @generated by Composer
|
|
||||||
|
|
||||||
class ComposerAutoloaderInit0206cd2f5513395c6d5551a767d5c39f
|
|
||||||
{
|
|
||||||
private static $loader;
|
|
||||||
|
|
||||||
public static function loadClassLoader($class)
|
|
||||||
{
|
|
||||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
|
||||||
require __DIR__ . '/ClassLoader.php';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return \Composer\Autoload\ClassLoader
|
|
||||||
*/
|
|
||||||
public static function getLoader()
|
|
||||||
{
|
|
||||||
if (null !== self::$loader) {
|
|
||||||
return self::$loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
require __DIR__ . '/platform_check.php';
|
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInit0206cd2f5513395c6d5551a767d5c39f', 'loadClassLoader'), true, true);
|
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInit0206cd2f5513395c6d5551a767d5c39f', 'loadClassLoader'));
|
|
||||||
|
|
||||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
|
||||||
if ($useStaticLoader) {
|
|
||||||
require __DIR__ . '/autoload_static.php';
|
|
||||||
|
|
||||||
call_user_func(\Composer\Autoload\ComposerStaticInit0206cd2f5513395c6d5551a767d5c39f::getInitializer($loader));
|
|
||||||
} else {
|
|
||||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
|
||||||
foreach ($map as $namespace => $path) {
|
|
||||||
$loader->set($namespace, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
$map = require __DIR__ . '/autoload_psr4.php';
|
|
||||||
foreach ($map as $namespace => $path) {
|
|
||||||
$loader->setPsr4($namespace, $path);
|
|
||||||
}
|
|
||||||
|
|
||||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
|
||||||
if ($classMap) {
|
|
||||||
$loader->addClassMap($classMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$loader->register(true);
|
|
||||||
|
|
||||||
return $loader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// autoload_static.php @generated by Composer
|
|
||||||
|
|
||||||
namespace Composer\Autoload;
|
|
||||||
|
|
||||||
class ComposerStaticInit0206cd2f5513395c6d5551a767d5c39f
|
|
||||||
{
|
|
||||||
public static $prefixLengthsPsr4 = array (
|
|
||||||
'G' =>
|
|
||||||
array (
|
|
||||||
'Grav\\Plugin\\AddPageByFormPlugin\\' => 32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
public static $prefixDirsPsr4 = array (
|
|
||||||
'Grav\\Plugin\\AddPageByFormPlugin\\' =>
|
|
||||||
array (
|
|
||||||
0 => __DIR__ . '/../..' . '/classes',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
public static $classMap = array (
|
|
||||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
|
||||||
'Grav\\Plugin\\AddPageByFormPlugin' => __DIR__ . '/../..' . '/add-page-by-form.php',
|
|
||||||
);
|
|
||||||
|
|
||||||
public static function getInitializer(ClassLoader $loader)
|
|
||||||
{
|
|
||||||
return \Closure::bind(function () use ($loader) {
|
|
||||||
$loader->prefixLengthsPsr4 = ComposerStaticInit0206cd2f5513395c6d5551a767d5c39f::$prefixLengthsPsr4;
|
|
||||||
$loader->prefixDirsPsr4 = ComposerStaticInit0206cd2f5513395c6d5551a767d5c39f::$prefixDirsPsr4;
|
|
||||||
$loader->classMap = ComposerStaticInit0206cd2f5513395c6d5551a767d5c39f::$classMap;
|
|
||||||
|
|
||||||
}, null, ClassLoader::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"packages": [],
|
|
||||||
"dev": false,
|
|
||||||
"dev-package-names": []
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php return array(
|
|
||||||
'root' => array(
|
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
|
||||||
'version' => '1.0.0.0',
|
|
||||||
'type' => 'grav-plugin',
|
|
||||||
'install_path' => __DIR__ . '/../../',
|
|
||||||
'aliases' => array(),
|
|
||||||
'reference' => NULL,
|
|
||||||
'name' => 'bleutzinn/grav-plugin-add-page-by-form',
|
|
||||||
'dev' => false,
|
|
||||||
),
|
|
||||||
'versions' => array(
|
|
||||||
'bleutzinn/grav-plugin-add-page-by-form' => array(
|
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
|
||||||
'version' => '1.0.0.0',
|
|
||||||
'type' => 'grav-plugin',
|
|
||||||
'install_path' => __DIR__ . '/../../',
|
|
||||||
'aliases' => array(),
|
|
||||||
'reference' => NULL,
|
|
||||||
'dev_requirement' => false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// platform_check.php @generated by Composer
|
|
||||||
|
|
||||||
$issues = array();
|
|
||||||
|
|
||||||
if (!(PHP_VERSION_ID >= 70103)) {
|
|
||||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.3". You are running ' . PHP_VERSION . '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($issues) {
|
|
||||||
if (!headers_sent()) {
|
|
||||||
header('HTTP/1.1 500 Internal Server Error');
|
|
||||||
}
|
|
||||||
if (!ini_get('display_errors')) {
|
|
||||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
|
||||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
|
||||||
} elseif (!headers_sent()) {
|
|
||||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trigger_error(
|
|
||||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
|
||||||
E_USER_ERROR
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Linguist Normalizer
|
|
||||||
*.yaml linguistic-language=PHP
|
|
||||||
*.twig linguistic-language=PHP
|
|
||||||
**/gulpfile.babel.js linguist-vendored
|
|
||||||
**/webpack.conf.js linguist-vendored
|
|
||||||
**/js/*.js linguist-vendored
|
|
||||||
**/js/*.json linguist-vendored
|
|
||||||
**/css-compiled/*.css linguist-vendored
|
|
||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
||||||
patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: grav
|
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
||||||
custom: # Replace with a single custom sponsorship URL
|
|
||||||
Vendored
-6
@@ -1,6 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
Please read the <a href="https://github.com/getgrav/grav/blob/develop/CONTRIBUTING.md" target="_blank">Contributing Guidelines of the Grav Project</a>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2017 Grav
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
# Grav Standard Administration Panel Plugin
|
|
||||||
|
|
||||||
This **admin plugin** for [Grav](https://github.com/getgrav/grav) is an HTML user interface that provides a convenient way to configure Grav and easily create and modify pages. This will remain a totally optional plugin, and is not in any way required or needed to use Grav effectively. In fact, the admin provides an intentionally limited view to ensure it remains easy to use and not overwhelming. I'm sure power users will still prefer to work with the configuration files directly.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
# Features
|
|
||||||
|
|
||||||
* User login with automatic password encryption
|
|
||||||
* Forgot password functionality
|
|
||||||
* Logged-in-user management
|
|
||||||
* One click Grav core updates
|
|
||||||
* Dashboard with maintenance status, site activity and latest page updates
|
|
||||||
* Notifications system for latest news, blogs, and announcements
|
|
||||||
* Ajax-powered backup capability
|
|
||||||
* Ajax-powered clear-cache capability
|
|
||||||
* System configuration management
|
|
||||||
* Site configuration management
|
|
||||||
* Normal and Expert modes which allow editing via forms or YAML
|
|
||||||
* Page listing with filtering and search
|
|
||||||
* Page creation, editing, moving, copying, and deleting
|
|
||||||
* Powerful syntax highlighting code editor with instant Grav-powered preview
|
|
||||||
* Editor features, hot keys, toolbar, and distraction-free fullscreen mode
|
|
||||||
* Drag-n-drop upload of page media files including drag-n-drop placement in the editor
|
|
||||||
* One click theme and plugin updates
|
|
||||||
* Plugin manager that allows listing and configuration of installed plugins
|
|
||||||
* Theme manager that allows listing and configuration of installed themes
|
|
||||||
* GPM-powered installation of new plugins and themes
|
|
||||||
|
|
||||||
# Support
|
|
||||||
|
|
||||||
#### Support
|
|
||||||
|
|
||||||
We have tested internally, but we hope to use this public beta phase to identify, isolate, and fix issues related to the plugin to ensure it is as solid and reliable as possible.
|
|
||||||
|
|
||||||
For **live chatting**, please use the dedicated [Discord Chat Room](https://getgrav.org/discord) for discussions directly related to Grav.
|
|
||||||
|
|
||||||
For **bugs, features, improvements**, please ensure you [create issues in the admin plugin GitHub repository](https://github.com/getgrav/grav-plugin-admin).
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
First ensure you are running the latest **Grav 1.6.7 or later**. This is required for the admin plugin to run properly (`-f` forces a refresh of the GPM index).
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/gpm selfupgrade -f
|
|
||||||
```
|
|
||||||
|
|
||||||
The admin plugin actually requires the help of 3 other plugins, so to get the admin plugin to work you first need to install **admin**, **login**, **forms**, and **email** plugins. These are available via GPM, and because the plugin has dependencies you just need to proceed and install the admin plugin, and agree when prompted to install the others:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/gpm install admin
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Installation
|
|
||||||
|
|
||||||
Manual installation is not the recommended method of installation, however, it is still possible to install the admin plugin manually. Basically, you need to download each of the following plugins individually:
|
|
||||||
|
|
||||||
* [admin](https://github.com/getgrav/grav-plugin-admin/archive/develop.zip)
|
|
||||||
* [login](https://github.com/getgrav/grav-plugin-login/archive/develop.zip)
|
|
||||||
* [form](https://github.com/getgrav/grav-plugin-form/archive/develop.zip)
|
|
||||||
* [email](https://github.com/getgrav/grav-plugin-email/archive/develop.zip)
|
|
||||||
|
|
||||||
Extract each archive file into your `user/plugins` folder, then ensure the folders are renamed to just `admin/`, `login/`, `form/`, and `email/`. Then proceed with the **Usage instructions below**.
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
### Create User with CLI
|
|
||||||
|
|
||||||
After this you need to create a user account with admin privileges:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bin/plugin login new-user
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create User Manually
|
|
||||||
|
|
||||||
Alternatively, you can create a user account manually, in a file called `user/accounts/admin.yaml`. This **filename** is actually the **username** that you will use to login. The contents will contain the other information for the user.
|
|
||||||
|
|
||||||
```
|
|
||||||
password: 'password'
|
|
||||||
email: 'youremail@mail.com'
|
|
||||||
fullname: 'Johnny Appleseed'
|
|
||||||
title: 'Site Administrator'
|
|
||||||
access:
|
|
||||||
admin:
|
|
||||||
login: true
|
|
||||||
super: true
|
|
||||||
```
|
|
||||||
|
|
||||||
Of course you should edit your `email`, `password`, `fullname`, and `title` to suit your needs.
|
|
||||||
|
|
||||||
> You can use any password when you manually put it in this `.yaml` file. However, when you change your password in the admin, it must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters.
|
|
||||||
|
|
||||||
# Accessing the Admin
|
|
||||||
|
|
||||||
By default, you can access the admin by pointing your browser to `http://yoursite.com/admin`. You can simply log in with the `username` and `password` set in the YAML file you configured earlier.
|
|
||||||
|
|
||||||
> After logging in, your **plaintext password** will be removed and replaced by an **encrypted** one.
|
|
||||||
|
|
||||||
# Standard Free & Paid Pro Versions
|
|
||||||
|
|
||||||
If you have been following the [blog](https://getgrav.org/blog), [Twitter](https://twitter.com/getgrav), [Discord chat](https://getgrav.org/discord), etc., you probably already know now that our intention is to provide two versions of this plugin.
|
|
||||||
|
|
||||||
The **standard free version**, is very powerful, and has more functionality than most commercial flat-file CMS systems.
|
|
||||||
|
|
||||||
We also intend to release in the near future a more feature-rich **pro version** that will include enhanced functionality, as well as some additional nice-to-have capabilities. This pro version will be a **paid** plugin the price of which is not yet 100% finalized.
|
|
||||||
|
|
||||||
# Admin Events
|
|
||||||
|
|
||||||
## General events
|
|
||||||
|
|
||||||
- onAdminRegisterPermissions - (admin)
|
|
||||||
- onAdminThemeInitialized
|
|
||||||
- onAdminPage - (page)
|
|
||||||
- onAdminMenu
|
|
||||||
- onAdminTwigTemplatePaths - (paths)
|
|
||||||
|
|
||||||
## Page specific events
|
|
||||||
|
|
||||||
- onAdminDashboard
|
|
||||||
- onAdminTools - (tools)
|
|
||||||
- onAdminLogFiles - (logs)
|
|
||||||
- onAdminGenerateReports - (reports)
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
|
|
||||||
- onAdminControllerInit - (controller)
|
|
||||||
- onAdminTaskExecute - (controller, method)
|
|
||||||
|
|
||||||
## Editing
|
|
||||||
|
|
||||||
- onAdminData
|
|
||||||
- onAdminSave - (object)
|
|
||||||
- onAdminAfterSave - (object)
|
|
||||||
|
|
||||||
## Pages
|
|
||||||
|
|
||||||
- onAdminPageTypes - (types)
|
|
||||||
- onAdminModularPageTypes
|
|
||||||
- onAdminSave - (page)
|
|
||||||
- onAdminAfterSaveAs - (path)
|
|
||||||
- onAdminAfterSave - (page)
|
|
||||||
- onAdminAfterDelete - (page)
|
|
||||||
- onAdminAfterAddMedia - (page)
|
|
||||||
- onAdminAfterDelMedia - (page)
|
|
||||||
- onAdminCreatePageFrontmatter - (header, data)
|
|
||||||
|
|
||||||
|
|
||||||
# Running Tests
|
|
||||||
|
|
||||||
First install the dev dependencies by running `composer update` from the Grav root.
|
|
||||||
Then `composer test` will run the Unit Tests, which should be always executed successfully on any site.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Upgrading to Admin 1.10
|
|
||||||
|
|
||||||
Twig:
|
|
||||||
|
|
||||||
* **Admin link**: When linking to another admin page, use `{{ admin_route('/config/site') }}` instead of any other method, such as `{{ base_url_relative }}/config/site` (fixes multi-language issues)
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
|||||||
enabled: false
|
|
||||||
route: '/admin'
|
|
||||||
cache_enabled: true
|
|
||||||
theme: grav
|
|
||||||
logo_text: ''
|
|
||||||
body_classes: ''
|
|
||||||
content_padding: true
|
|
||||||
twofa_enabled: true
|
|
||||||
sidebar:
|
|
||||||
activate: tab
|
|
||||||
hover_delay: 100
|
|
||||||
size: auto
|
|
||||||
dashboard:
|
|
||||||
days_of_stats: 7
|
|
||||||
widgets_display:
|
|
||||||
dashboard-maintenance: true
|
|
||||||
dashboard-statistics: true
|
|
||||||
dashboard-notifications: true
|
|
||||||
dashboard-feed: true
|
|
||||||
dashboard-pages: true
|
|
||||||
pages:
|
|
||||||
show_parents: both
|
|
||||||
show_modular: true
|
|
||||||
session:
|
|
||||||
timeout: 1800
|
|
||||||
keep_alive: true
|
|
||||||
edit_mode: normal
|
|
||||||
frontend_preview_target: inline
|
|
||||||
show_github_msg: true
|
|
||||||
admin_icons: line-awesome
|
|
||||||
enable_auto_updates_check: true
|
|
||||||
notifications:
|
|
||||||
feed: true
|
|
||||||
dashboard: true
|
|
||||||
plugins: true
|
|
||||||
themes: true
|
|
||||||
popularity:
|
|
||||||
enabled: true
|
|
||||||
ignore: ['/test*','/modular']
|
|
||||||
history:
|
|
||||||
daily: 30
|
|
||||||
monthly: 12
|
|
||||||
visitors: 20
|
|
||||||
whitelabel:
|
|
||||||
quicktray_recompile: false
|
|
||||||
codemirror_theme: paper
|
|
||||||
codemirror_fontsize: md
|
|
||||||
codemirror_md_font: sans
|
|
||||||
logo_custom:
|
|
||||||
logo_login:
|
|
||||||
color_scheme:
|
|
||||||
accents:
|
|
||||||
primary-accent: button
|
|
||||||
secondary-accent: notice
|
|
||||||
tertiary-accent: critical
|
|
||||||
colors:
|
|
||||||
logo-bg: '#323640'
|
|
||||||
logo-link: '#FFFFFF'
|
|
||||||
nav-bg: '#3D424E'
|
|
||||||
nav-text: '#B7B9BD'
|
|
||||||
nav-link: '#ffffff'
|
|
||||||
nav-selected-bg: '#323640'
|
|
||||||
nav-selected-link: '#ffffff'
|
|
||||||
nav-hover-bg: '#434753'
|
|
||||||
nav-hover-link: '#ffffff'
|
|
||||||
toolbar-bg: '#ffffff'
|
|
||||||
toolbar-text: '#3D424E'
|
|
||||||
page-bg: '#F6F6F6'
|
|
||||||
page-text: '#6f7b8a'
|
|
||||||
page-link: '#0090D9'
|
|
||||||
content-bg: '#ffffff'
|
|
||||||
content-text: '#6f7b8a'
|
|
||||||
content-link: '#0090D9'
|
|
||||||
content-link2: '#da4b46'
|
|
||||||
content-header: '#414147'
|
|
||||||
content-tabs-bg: '#e6e6e6'
|
|
||||||
content-tabs-text: '#808080'
|
|
||||||
button-bg: '#0090D9'
|
|
||||||
button-text: '#ffffff'
|
|
||||||
notice-bg: '#06A599'
|
|
||||||
notice-text: '#ffffff'
|
|
||||||
update-bg: '#77559D'
|
|
||||||
update-text: '#ffffff'
|
|
||||||
critical-bg: '#F45857'
|
|
||||||
critical-text: '#ffffff'
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 236 KiB |
@@ -1,792 +0,0 @@
|
|||||||
name: Admin Panel
|
|
||||||
slug: admin
|
|
||||||
type: plugin
|
|
||||||
testing: true
|
|
||||||
version: 1.11.0-beta.5
|
|
||||||
description: Adds an advanced administration panel to manage your site
|
|
||||||
icon: empire
|
|
||||||
author:
|
|
||||||
name: Team Grav
|
|
||||||
email: devs@getgrav.org
|
|
||||||
url: https://getgrav.org
|
|
||||||
homepage: https://github.com/getgrav/grav-plugin-admin
|
|
||||||
keywords: admin, plugin, manager, panel
|
|
||||||
bugs: https://github.com/getgrav/grav-plugin-admin/issues
|
|
||||||
docs: https://github.com/getgrav/grav-plugin-admin/blob/develop/README.md
|
|
||||||
license: MIT
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- { name: grav, version: '>=1.8.0-beta.1' }
|
|
||||||
- { name: form, version: '>=6.0.1' }
|
|
||||||
- { name: login, version: '>=3.7.8' }
|
|
||||||
- { name: email, version: '>=3.1.6' }
|
|
||||||
- { name: flex-objects, version: '>=1.4.0-beta.1' }
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
admin_tabs:
|
|
||||||
type: tabs
|
|
||||||
fields:
|
|
||||||
config_tab:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.CONFIGURATION
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
Basics:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.BASICS
|
|
||||||
underline: false
|
|
||||||
|
|
||||||
enabled:
|
|
||||||
type: hidden
|
|
||||||
label: PLUGIN_ADMIN.PLUGIN_STATUS
|
|
||||||
highlight: 1
|
|
||||||
default: 0
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
cache_enabled:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.ADMIN_CACHING
|
|
||||||
help: PLUGIN_ADMIN.ADMIN_CACHING_HELP
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.YES
|
|
||||||
0: PLUGIN_ADMIN.NO
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
twofa_enabled:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_LOGIN.2FA_TITLE
|
|
||||||
help: PLUGIN_LOGIN.2FA_ENABLED_HELP
|
|
||||||
default: 1
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.YES
|
|
||||||
0: PLUGIN_ADMIN.NO
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.ADMIN_PATH
|
|
||||||
size: medium
|
|
||||||
placeholder: ADMIN_PATH_PLACEHOLDER
|
|
||||||
help: ADMIN_PATH_HELP
|
|
||||||
|
|
||||||
logo_text:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.LOGO_TEXT
|
|
||||||
size: medium
|
|
||||||
placeholder: "Grav"
|
|
||||||
help: PLUGIN_ADMIN.LOGO_TEXT_HELP
|
|
||||||
|
|
||||||
content_padding:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.CONTENT_PADDING
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_PADDING_HELP
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.YES
|
|
||||||
0: PLUGIN_ADMIN.NO
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
body_classes:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.BODY_CLASSES
|
|
||||||
size: medium
|
|
||||||
help: PLUGIN_ADMIN.BODY_CLASSES_HELP
|
|
||||||
|
|
||||||
sidebar.activate:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.SIDEBAR_ACTIVATION
|
|
||||||
help: PLUGIN_ADMIN.SIDEBAR_ACTIVATION_HELP
|
|
||||||
size: small
|
|
||||||
default: tab
|
|
||||||
options:
|
|
||||||
tab: PLUGIN_ADMIN.SIDEBAR_ACTIVATION_TAB
|
|
||||||
hover: PLUGIN_ADMIN.SIDEBAR_ACTIVATION_HOVER
|
|
||||||
|
|
||||||
sidebar.hover_delay:
|
|
||||||
type: text
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.SIDEBAR_HOVER_DELAY_APPEND
|
|
||||||
label: PLUGIN_ADMIN.SIDEBAR_HOVER_DELAY
|
|
||||||
default: 500
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
min: 1
|
|
||||||
|
|
||||||
|
|
||||||
sidebar.size:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.SIDEBAR_SIZE
|
|
||||||
help: PLUGIN_ADMIN.SIDEBAR_SIZE_HELP
|
|
||||||
size: medium
|
|
||||||
default: auto
|
|
||||||
options:
|
|
||||||
auto: PLUGIN_ADMIN.SIDEBAR_SIZE_AUTO
|
|
||||||
small: PLUGIN_ADMIN.SIDEBAR_SIZE_SMALL
|
|
||||||
|
|
||||||
theme:
|
|
||||||
type: hidden
|
|
||||||
label: PLUGIN_ADMIN.THEME
|
|
||||||
default: grav
|
|
||||||
|
|
||||||
edit_mode:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.EDIT_MODE
|
|
||||||
size: small
|
|
||||||
default: normal
|
|
||||||
options:
|
|
||||||
normal: PLUGIN_ADMIN.NORMAL
|
|
||||||
expert: PLUGIN_ADMIN.EXPERT
|
|
||||||
help: PLUGIN_ADMIN.EDIT_MODE_HELP
|
|
||||||
|
|
||||||
frontend_preview_target:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.FRONTEND_PREVIEW_TARGET
|
|
||||||
size: medium
|
|
||||||
default: inline
|
|
||||||
options:
|
|
||||||
inline: PLUGIN_ADMIN.FRONTEND_PREVIEW_TARGET_INLINE
|
|
||||||
_blank: PLUGIN_ADMIN.FRONTEND_PREVIEW_TARGET_NEW
|
|
||||||
_self: PLUGIN_ADMIN.FRONTEND_PREVIEW_TARGET_CURRENT
|
|
||||||
|
|
||||||
pages.show_parents:
|
|
||||||
type: select
|
|
||||||
size: medium
|
|
||||||
label: PLUGIN_ADMIN.PARENT_DROPDOWN
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
both: PLUGIN_ADMIN.PARENT_DROPDOWN_BOTH
|
|
||||||
folder: PLUGIN_ADMIN.PARENT_DROPDOWN_FOLDER
|
|
||||||
fullpath: PLUGIN_ADMIN.PARENT_DROPDOWN_FULLPATH
|
|
||||||
|
|
||||||
pages.parents_levels:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.PARENTS_LEVELS
|
|
||||||
size: small
|
|
||||||
help: PLUGIN_ADMIN.PARENTS_LEVELS_HELP
|
|
||||||
|
|
||||||
pages.show_modular:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.MODULAR_PARENTS
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.MODULAR_PARENTS_HELP
|
|
||||||
|
|
||||||
show_beta_msg:
|
|
||||||
type: hidden
|
|
||||||
|
|
||||||
show_github_msg:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.SHOW_GITHUB_LINK
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.SHOW_GITHUB_LINK_HELP
|
|
||||||
|
|
||||||
enable_auto_updates_check:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.AUTO_UPDATES
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.AUTO_UPDATES_HELP
|
|
||||||
|
|
||||||
session.timeout:
|
|
||||||
type: text
|
|
||||||
size: small
|
|
||||||
label: PLUGIN_ADMIN.TIMEOUT
|
|
||||||
append: GRAV.NICETIME.SECOND_PLURAL
|
|
||||||
help: PLUGIN_ADMIN.TIMEOUT_HELP
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
min: 1
|
|
||||||
|
|
||||||
session.keep_alive:
|
|
||||||
type: toggle
|
|
||||||
label: Keep Alive Ping
|
|
||||||
help: "Periodically pings to keep your admin session alive. Turn OFF to allow the session to expire while idle (useful for testing timeouts)."
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
hide_page_types:
|
|
||||||
type: select
|
|
||||||
size: large
|
|
||||||
label: PLUGIN_ADMIN.HIDE_PAGE_TYPES
|
|
||||||
classes: fancy
|
|
||||||
multiple: true
|
|
||||||
array: true
|
|
||||||
selectize:
|
|
||||||
create: true
|
|
||||||
data-options@: ['\Grav\Plugin\AdminPlugin::pagesTypes', true]
|
|
||||||
|
|
||||||
hide_modular_page_types:
|
|
||||||
type: select
|
|
||||||
size: large
|
|
||||||
label: PLUGIN_ADMIN.HIDE_MODULAR_PAGE_TYPES
|
|
||||||
classes: fancy
|
|
||||||
multiple: true
|
|
||||||
array: true
|
|
||||||
selectize:
|
|
||||||
create: true
|
|
||||||
data-options@: ['\Grav\Plugin\AdminPlugin::pagesModularTypes', true]
|
|
||||||
|
|
||||||
Dashboard:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.DASHBOARD
|
|
||||||
underline: true
|
|
||||||
|
|
||||||
widgets_display:
|
|
||||||
type: widgets
|
|
||||||
label: PLUGIN_ADMIN.WIDGETS_DISPLAY
|
|
||||||
validate:
|
|
||||||
type: array
|
|
||||||
|
|
||||||
Notifications:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.NOTIFICATIONS
|
|
||||||
underline: true
|
|
||||||
|
|
||||||
notifications.feed:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.FEED_NOTIFICATIONS
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.FEED_NOTIFICATIONS_HELP
|
|
||||||
|
|
||||||
notifications.dashboard:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.DASHBOARD_NOTIFICATIONS
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.DASHBOARD_NOTIFICATIONS_HELP
|
|
||||||
|
|
||||||
notifications.plugins:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.PLUGINS_NOTIFICATIONS
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.PLUGINS_NOTIFICATIONS_HELP
|
|
||||||
|
|
||||||
notifications.themes:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.THEMES_NOTIFICATIONS
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.THEMES_NOTIFICATIONS_HELP
|
|
||||||
|
|
||||||
customization_tab:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.CUSTOMIZATION
|
|
||||||
|
|
||||||
fields:
|
|
||||||
whitelabel.logos:
|
|
||||||
type: section
|
|
||||||
underline: true
|
|
||||||
title: PLUGIN_ADMIN.LOGOS
|
|
||||||
|
|
||||||
whitelabel.logo_login:
|
|
||||||
type: file
|
|
||||||
label: PLUGIN_ADMIN.LOGIN_SCREEN_CUSTOM_LOGO_LABEL
|
|
||||||
destination: 'user://assets'
|
|
||||||
accept:
|
|
||||||
- image/*
|
|
||||||
|
|
||||||
whitelabel.logo_custom:
|
|
||||||
type: file
|
|
||||||
label: PLUGIN_ADMIN.TOP_LEFT_CUSTOM_LOGO_LABEL
|
|
||||||
destination: 'user://assets'
|
|
||||||
accept:
|
|
||||||
- image/*
|
|
||||||
|
|
||||||
codemirror_section:
|
|
||||||
type: section
|
|
||||||
underline: true
|
|
||||||
title: PLUGIN_ADMIN.CODEMIRROR
|
|
||||||
|
|
||||||
whitelabel.codemirror_theme:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.CODEMIRROR_THEME
|
|
||||||
default: paper
|
|
||||||
markdown: true
|
|
||||||
data-options@: '\Grav\Plugin\AdminPlugin::themeOptions'
|
|
||||||
description: PLUGIN_ADMIN.CODEMIRROR_THEME_DESC
|
|
||||||
|
|
||||||
whitelabel.codemirror_fontsize:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.CODEMIRROR_FONTSIZE
|
|
||||||
default: md
|
|
||||||
options:
|
|
||||||
sm: PLUGIN_ADMIN.CODEMIRROR_FONTSIZE_SM
|
|
||||||
md: PLUGIN_ADMIN.CODEMIRROR_FONTSIZE_MD
|
|
||||||
lg: PLUGIN_ADMIN.CODEMIRROR_FONTSIZE_LG
|
|
||||||
|
|
||||||
whitelabel.codemirror_md_font:
|
|
||||||
type: select
|
|
||||||
label: PLUGIN_ADMIN.CODEMIRROR_MD_FONT
|
|
||||||
default: sans
|
|
||||||
options:
|
|
||||||
sans: PLUGIN_ADMIN.CODEMIRROR_MD_FONT_SANS
|
|
||||||
mono: PLUGIN_ADMIN.CODEMIRROR_MD_FONT_MONO
|
|
||||||
|
|
||||||
customization_section:
|
|
||||||
type: section
|
|
||||||
underline: true
|
|
||||||
title: PLUGIN_ADMIN.CUSTOMIZATION
|
|
||||||
|
|
||||||
whitelabel.quicktray_recompile:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.QUICKTRAY_RECOMPILE
|
|
||||||
help: PLUGIN_ADMIN.QUICKTRAY_RECOMPILE_HELP
|
|
||||||
highlight: 0
|
|
||||||
default: 0
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
whitelabel.color_scheme.name:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.COLOR_SCHEME_NAME
|
|
||||||
help: PLUGIN_ADMIN.COLOR_SCHEME_NAME_HELP
|
|
||||||
placeholder: PLUGIN_ADMIN.COLOR_SCHEME_NAME_PLACEHOLDER
|
|
||||||
|
|
||||||
themes-preview:
|
|
||||||
type: themepreview
|
|
||||||
ignore: true;
|
|
||||||
label: PLUGIN_ADMIN.PRESETS
|
|
||||||
style: vertical
|
|
||||||
|
|
||||||
colorschemes:
|
|
||||||
type: colorscheme
|
|
||||||
label: PLUGIN_ADMIN.COLOR_SCHEME_LABEL
|
|
||||||
style: vertical
|
|
||||||
help: PLUGIN_ADMIN.COLOR_SCHEME_HELP
|
|
||||||
|
|
||||||
fields:
|
|
||||||
whitelabel.color_scheme.colors.logo-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#1e333e'
|
|
||||||
help: PLUGIN_ADMIN.LOGO_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.logo-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.LOGO_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#253a47'
|
|
||||||
help: PLUGIN_ADMIN.NAV_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#afc7d5'
|
|
||||||
help: PLUGIN_ADMIN.NAV_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#d1dee7'
|
|
||||||
help: PLUGIN_ADMIN.NAV_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-selected-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#2d4d5b'
|
|
||||||
help: PLUGIN_ADMIN.NAV_SELECTED_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-selected-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.NAV_SELECTED_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-hover-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#1e333e'
|
|
||||||
help: PLUGIN_ADMIN.NAV_HOVER_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.nav-hover-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.NAV_HOVER_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.toolbar-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#349886'
|
|
||||||
help: PLUGIN_ADMIN.TOOLBAR_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.toolbar-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.TOOLBAR_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.page-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#314d5b'
|
|
||||||
help: PLUGIN_ADMIN.PAGE_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.page-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#81a5b5'
|
|
||||||
help: PLUGIN_ADMIN.PAGE_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.page-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#aad9ed'
|
|
||||||
help: PLUGIN_ADMIN.PAGE_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#eeeeee'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#737c81'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-link:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#0082ba'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_LINK_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-link2:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#da4b46'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_LINK2_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-header:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#314d5b'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_HEADER_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-tabs-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#223a47'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_TABS_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-tabs-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#d1dee7'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_TABS_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.content-highlight:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffd7'
|
|
||||||
help: PLUGIN_ADMIN.CONTENT_HIGHLIGHT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.button-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#41bea8'
|
|
||||||
help: PLUGIN_ADMIN.BUTTON_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.button-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.BUTTON_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.notice-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#00a6cf'
|
|
||||||
help: PLUGIN_ADMIN.NOTICE_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.notice-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.NOTICE_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.update-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#8f5aad'
|
|
||||||
help: PLUGIN_ADMIN.UPDATES_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.update-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.UPDATES_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.critical-bg:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#da4b46'
|
|
||||||
help: PLUGIN_ADMIN.CRITICAL_BG_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.colors.critical-text:
|
|
||||||
type: colorscheme.color
|
|
||||||
default: '#ffffff'
|
|
||||||
help: PLUGIN_ADMIN.CRITICAL_TEXT_HELP
|
|
||||||
|
|
||||||
whitelabel.color_scheme.accents.primary-accent:
|
|
||||||
type: select
|
|
||||||
size: medium
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.PRIMARY_ACCENT_LABEL
|
|
||||||
help: PLUGIN_ADMIN.PRIMARY_ACCENT_HELP
|
|
||||||
options:
|
|
||||||
button: PLUGIN_ADMIN.BUTTON_COLORS
|
|
||||||
content: PLUGIN_ADMIN.CONTENT_COLORS
|
|
||||||
tabs: PLUGIN_ADMIN.TABS_COLORS
|
|
||||||
critical: PLUGIN_ADMIN.CRITICAL_COLORS
|
|
||||||
logo: PLUGIN_ADMIN.LOGO_COLORS
|
|
||||||
nav: PLUGIN_ADMIN.NAV_COLORS
|
|
||||||
notice: PLUGIN_ADMIN.NOTICE_COLORS
|
|
||||||
page: PLUGIN_ADMIN.PAGE_COLORS
|
|
||||||
toolbar: PLUGIN_ADMIN.TOOLBAR_COLORS
|
|
||||||
update: PLUGIN_ADMIN.UPDATE_COLORS
|
|
||||||
|
|
||||||
whitelabel.color_scheme.accents.secondary-accent:
|
|
||||||
type: select
|
|
||||||
size: medium
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.SECONDARY_ACCENT_LABEL
|
|
||||||
help: PLUGIN_ADMIN.SECONDARY_ACCENT_HELP
|
|
||||||
options:
|
|
||||||
button: PLUGIN_ADMIN.BUTTON_COLORS
|
|
||||||
content: PLUGIN_ADMIN.CONTENT_COLORS
|
|
||||||
tabs: PLUGIN_ADMIN.TABS_COLORS
|
|
||||||
critical: PLUGIN_ADMIN.CRITICAL_COLORS
|
|
||||||
logo: PLUGIN_ADMIN.LOGO_COLORS
|
|
||||||
nav: PLUGIN_ADMIN.NAV_COLORS
|
|
||||||
notice: PLUGIN_ADMIN.NOTICE_COLORS
|
|
||||||
page: PLUGIN_ADMIN.PAGE_COLORS
|
|
||||||
toolbar: PLUGIN_ADMIN.TOOLBAR_COLORS
|
|
||||||
update: PLUGIN_ADMIN.UPDATE_COLORS
|
|
||||||
|
|
||||||
whitelabel.color_scheme.accents.tertiary-accent:
|
|
||||||
type: select
|
|
||||||
size: medium
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.TERTIARY_ACCENT_LABEL
|
|
||||||
help: PLUGIN_ADMIN.TERTIARY_ACCENT_HELP
|
|
||||||
options:
|
|
||||||
button: PLUGIN_ADMIN.BUTTON_COLORS
|
|
||||||
content: PLUGIN_ADMIN.CONTENT_COLORS
|
|
||||||
tabs: PLUGIN_ADMIN.TABS_COLORS
|
|
||||||
critical: PLUGIN_ADMIN.CRITICAL_COLORS
|
|
||||||
logo: PLUGIN_ADMIN.LOGO_COLORS
|
|
||||||
nav: PLUGIN_ADMIN.NAV_COLORS
|
|
||||||
notice: PLUGIN_ADMIN.NOTICE_COLORS
|
|
||||||
page: PLUGIN_ADMIN.PAGE_COLORS
|
|
||||||
toolbar: PLUGIN_ADMIN.TOOLBAR_COLORS
|
|
||||||
update: PLUGIN_ADMIN.UPDATE_COLORS
|
|
||||||
|
|
||||||
whitelabel.custom_footer:
|
|
||||||
type: textarea
|
|
||||||
rows: 2
|
|
||||||
label: PLUGIN_ADMIN.CUSTOM_FOOTER
|
|
||||||
help: PLUGIN_ADMIN.CUSTOM_FOOTER_HELP
|
|
||||||
placeholder: PLUGIN_ADMIN.CUSTOM_FOOTER_PLACEHOLDER
|
|
||||||
|
|
||||||
|
|
||||||
whitelabel.custom_css:
|
|
||||||
label: PLUGIN_ADMIN.CUSTOM_CSS_LABEL
|
|
||||||
placeholder: PLUGIN_ADMIN.CUSTOM_CSS_PLACEHOLDER
|
|
||||||
help: PLUGIN_ADMIN.CUSTOM_CSS_HELP
|
|
||||||
type: editor
|
|
||||||
codemirror:
|
|
||||||
mode: 'css'
|
|
||||||
indentUnit: 2
|
|
||||||
indentWithTabs: true
|
|
||||||
lineNumbers: true
|
|
||||||
styleActiveLine: true
|
|
||||||
|
|
||||||
whitelabel.custom_presets:
|
|
||||||
label: PLUGIN_ADMIN.CUSTOM_PRESETS
|
|
||||||
help: PLUGIN_ADMIN.CUSTOM_PRESETS_HELP
|
|
||||||
placeholder: PLUGIN_ADMIN.CUSTOM_PRESETS_PLACEHOLDER
|
|
||||||
type: editor
|
|
||||||
codemirror:
|
|
||||||
mode: 'yaml'
|
|
||||||
indentUnit: 2
|
|
||||||
indentWithTabs: false
|
|
||||||
lineNumbers: true
|
|
||||||
styleActiveLine: true
|
|
||||||
gutters: ['CodeMirror-lint-markers']
|
|
||||||
lint: true
|
|
||||||
|
|
||||||
extras_tab:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.EXTRAS
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
Popularity:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.POPULARITY
|
|
||||||
underline: true
|
|
||||||
|
|
||||||
popularity.enabled:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.VISITOR_TRACKING
|
|
||||||
highlight: 1
|
|
||||||
default: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
help: PLUGIN_ADMIN.VISITOR_TRACKING_HELP
|
|
||||||
|
|
||||||
dashboard.days_of_stats:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.DAYS_OF_STATS
|
|
||||||
append: days
|
|
||||||
size: x-small
|
|
||||||
default: 7
|
|
||||||
help: PLUGIN_ADMIN.DAYS_OF_STATS_HELP
|
|
||||||
validate:
|
|
||||||
type: int
|
|
||||||
|
|
||||||
popularity.ignore:
|
|
||||||
type: array
|
|
||||||
label: PLUGIN_ADMIN.IGNORE_URLS
|
|
||||||
size: large
|
|
||||||
help: PLUGIN_ADMIN.IGNORE_URLS_HELP
|
|
||||||
default: ['/test*','/modular']
|
|
||||||
value_only: true
|
|
||||||
placeholder_value: /ignore-this-route
|
|
||||||
|
|
||||||
popularity.history.daily:
|
|
||||||
type: hidden
|
|
||||||
label: PLUGIN_ADMIN.DAILY_HISTORY
|
|
||||||
default: 30
|
|
||||||
|
|
||||||
popularity.history.monthly:
|
|
||||||
type: hidden
|
|
||||||
label: PLUGIN_ADMIN.MONTHLY_HISTORY
|
|
||||||
default: 12
|
|
||||||
|
|
||||||
popularity.history.visitors:
|
|
||||||
type: hidden
|
|
||||||
label: PLUGIN_ADMIN.VISITORS_HISTORY
|
|
||||||
default: 20
|
|
||||||
|
|
||||||
MediaResize:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.MEDIA_RESIZE
|
|
||||||
underline: true
|
|
||||||
|
|
||||||
MediaResizeNote:
|
|
||||||
type: spacer
|
|
||||||
text: PLUGIN_ADMIN.PAGEMEDIA_RESIZER
|
|
||||||
markdown: true
|
|
||||||
|
|
||||||
pagemedia.resize_width:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RESIZE_WIDTH
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RESIZE_WIDTH_HELP
|
|
||||||
|
|
||||||
pagemedia.resize_height:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RESIZE_HEIGHT
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RESIZE_HEIGHT_HELP
|
|
||||||
|
|
||||||
pagemedia.res_min_width:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RES_MIN_WIDTH
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RES_MIN_WIDTH_HELP
|
|
||||||
|
|
||||||
pagemedia.res_min_height:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RES_MIN_HEIGHT
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RES_MIN_HEIGHT_HELP
|
|
||||||
|
|
||||||
pagemedia.res_max_width:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RES_MAX_WIDTH
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RES_MAX_WIDTH_HELP
|
|
||||||
|
|
||||||
pagemedia.res_max_height:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: PLUGIN_ADMIN.PIXELS
|
|
||||||
label: PLUGIN_ADMIN.RES_MAX_HEIGHT
|
|
||||||
default: 0
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
help: PLUGIN_ADMIN.RES_MAX_HEIGHT_HELP
|
|
||||||
|
|
||||||
pagemedia.resize_quality:
|
|
||||||
type: number
|
|
||||||
size: x-small
|
|
||||||
append: 0...1
|
|
||||||
label: PLUGIN_ADMIN.RESIZE_QUALITY
|
|
||||||
default: 0.8
|
|
||||||
validate:
|
|
||||||
type: number
|
|
||||||
step: 0.01
|
|
||||||
help: PLUGIN_ADMIN.RESIZE_QUALITY_HELP
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
section:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.COPY_PAGE
|
|
||||||
|
|
||||||
title:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
|
||||||
help: PLUGIN_ADMIN.PAGE_TITLE_HELP
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
header.published:
|
|
||||||
id: move-header-published
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.PUBLISHED
|
|
||||||
help: PLUGIN_ADMIN.PUBLISHED_HELP
|
|
||||||
highlight: ''
|
|
||||||
default: ''
|
|
||||||
size: medium
|
|
||||||
options:
|
|
||||||
'': PLUGIN_ADMIN.AUTO
|
|
||||||
1: PLUGIN_ADMIN.YES
|
|
||||||
0: PLUGIN_ADMIN.NO
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
section:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.ADD_MODULE_CONTENT
|
|
||||||
|
|
||||||
title:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: parents
|
|
||||||
label: PLUGIN_ADMIN.PAGE
|
|
||||||
classes: fancy
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
name:
|
|
||||||
type: select
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.MODULE_TEMPLATE
|
|
||||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
|
||||||
default: default
|
|
||||||
data-options@: '\Grav\Plugin\AdminPlugin::pagesModularTypes'
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
modular:
|
|
||||||
type: hidden
|
|
||||||
default: 1
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
blueprint:
|
|
||||||
type: blueprint
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
tabs:
|
|
||||||
type: tabs
|
|
||||||
active: 1
|
|
||||||
|
|
||||||
fields:
|
|
||||||
content:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.CONTENT
|
|
||||||
|
|
||||||
fields:
|
|
||||||
xss_check:
|
|
||||||
type: xss
|
|
||||||
|
|
||||||
frontmatter:
|
|
||||||
classes: frontmatter
|
|
||||||
type: editor
|
|
||||||
label: PLUGIN_ADMIN.FRONTMATTER
|
|
||||||
autofocus: true
|
|
||||||
codemirror:
|
|
||||||
mode: 'yaml'
|
|
||||||
indentUnit: 4
|
|
||||||
autofocus: true
|
|
||||||
indentWithTabs: false
|
|
||||||
lineNumbers: true
|
|
||||||
styleActiveLine: true
|
|
||||||
gutters: ['CodeMirror-lint-markers']
|
|
||||||
lint: true
|
|
||||||
|
|
||||||
content:
|
|
||||||
type: markdown
|
|
||||||
|
|
||||||
header.media_order:
|
|
||||||
type: pagemedia
|
|
||||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
|
||||||
|
|
||||||
options:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.OPTIONS
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
columns:
|
|
||||||
type: columns
|
|
||||||
|
|
||||||
fields:
|
|
||||||
column1:
|
|
||||||
type: column
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
ordering:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FILENAME
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: parents
|
|
||||||
label: PLUGIN_ADMIN.PARENT
|
|
||||||
classes: fancy
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
name:
|
|
||||||
type: select
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.MODULE_TEMPLATE
|
|
||||||
default: default
|
|
||||||
data-options@: '\Grav\Plugin\AdminPlugin::pagesModularTypes'
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
column2:
|
|
||||||
type: column
|
|
||||||
|
|
||||||
fields:
|
|
||||||
order:
|
|
||||||
type: order
|
|
||||||
label: PLUGIN_ADMIN.ORDERING
|
|
||||||
|
|
||||||
blueprint:
|
|
||||||
type: blueprint
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
route:
|
|
||||||
type: hidden
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
section:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.ADD_PAGE
|
|
||||||
|
|
||||||
title:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
|
||||||
help: PLUGIN_ADMIN.PAGE_TITLE_HELP
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: parents
|
|
||||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
|
||||||
classes: fancy
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
name:
|
|
||||||
type: select
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.PAGE_FILE
|
|
||||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
|
||||||
data-options@: '\Grav\Plugin\AdminPlugin::pagesTypes'
|
|
||||||
data-default@: '\Grav\Plugin\Admin\Admin::getLastPageName'
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
visible:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.VISIBLE
|
|
||||||
help: PLUGIN_ADMIN.VISIBLE_HELP
|
|
||||||
highlight: ''
|
|
||||||
default: ''
|
|
||||||
options:
|
|
||||||
'': PLUGIN_ADMIN.AUTO
|
|
||||||
1: PLUGIN_ADMIN.YES
|
|
||||||
0: PLUGIN_ADMIN.NO
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
required: true
|
|
||||||
|
|
||||||
blueprint:
|
|
||||||
type: blueprint
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
section:
|
|
||||||
type: section
|
|
||||||
title: PLUGIN_ADMIN.ADD_FOLDER
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: parents
|
|
||||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
|
||||||
classes: fancy
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
blueprint:
|
|
||||||
type: blueprint
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
tabs:
|
|
||||||
type: tabs
|
|
||||||
active: 1
|
|
||||||
|
|
||||||
fields:
|
|
||||||
content:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.CONTENT
|
|
||||||
|
|
||||||
fields:
|
|
||||||
xss_check:
|
|
||||||
type: xss
|
|
||||||
|
|
||||||
frontmatter:
|
|
||||||
classes: frontmatter
|
|
||||||
type: editor
|
|
||||||
label: PLUGIN_ADMIN.FRONTMATTER
|
|
||||||
autofocus: true
|
|
||||||
codemirror:
|
|
||||||
mode: 'yaml'
|
|
||||||
indentUnit: 4
|
|
||||||
autofocus: true
|
|
||||||
indentWithTabs: false
|
|
||||||
lineNumbers: true
|
|
||||||
styleActiveLine: true
|
|
||||||
gutters: ['CodeMirror-lint-markers']
|
|
||||||
lint: true
|
|
||||||
|
|
||||||
content:
|
|
||||||
type: codemirror
|
|
||||||
|
|
||||||
header.media_order:
|
|
||||||
type: pagemedia
|
|
||||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
|
||||||
|
|
||||||
options:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.OPTIONS
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
columns:
|
|
||||||
type: columns
|
|
||||||
|
|
||||||
fields:
|
|
||||||
column1:
|
|
||||||
type: column
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
ordering:
|
|
||||||
type: toggle
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
|
||||||
highlight: 1
|
|
||||||
options:
|
|
||||||
1: PLUGIN_ADMIN.ENABLED
|
|
||||||
0: PLUGIN_ADMIN.DISABLED
|
|
||||||
validate:
|
|
||||||
type: bool
|
|
||||||
|
|
||||||
folder:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
|
||||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
|
||||||
validate:
|
|
||||||
rule: slug
|
|
||||||
required: true
|
|
||||||
|
|
||||||
route:
|
|
||||||
type: parents
|
|
||||||
label: PLUGIN_ADMIN.PARENT
|
|
||||||
classes: fancy
|
|
||||||
|
|
||||||
name:
|
|
||||||
type: select
|
|
||||||
classes: fancy
|
|
||||||
label: PLUGIN_ADMIN.DISPLAY_TEMPLATE
|
|
||||||
help: PLUGIN_ADMIN.DISPLAY_TEMPLATE_HELP
|
|
||||||
default: default
|
|
||||||
data-options@: '\Grav\Plugin\AdminPlugin::pagesTypes'
|
|
||||||
validate:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
column2:
|
|
||||||
type: column
|
|
||||||
|
|
||||||
fields:
|
|
||||||
order:
|
|
||||||
type: order
|
|
||||||
label: PLUGIN_ADMIN.ORDERING
|
|
||||||
|
|
||||||
blueprint:
|
|
||||||
type: blueprint
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
rules:
|
|
||||||
slug:
|
|
||||||
pattern: '[a-zA-Zа-яA-Я0-9_\-]+'
|
|
||||||
min: 1
|
|
||||||
max: 200
|
|
||||||
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
|
|
||||||
tabs:
|
|
||||||
type: tabs
|
|
||||||
active: 1
|
|
||||||
|
|
||||||
fields:
|
|
||||||
content:
|
|
||||||
type: tab
|
|
||||||
title: PLUGIN_ADMIN.CONTENT
|
|
||||||
|
|
||||||
fields:
|
|
||||||
frontmatter:
|
|
||||||
classes: frontmatter
|
|
||||||
type: editor
|
|
||||||
label: PLUGIN_ADMIN.FRONTMATTER
|
|
||||||
autofocus: true
|
|
||||||
codemirror:
|
|
||||||
mode: 'yaml'
|
|
||||||
indentUnit: 4
|
|
||||||
autofocus: true
|
|
||||||
indentWithTabs: false
|
|
||||||
lineNumbers: true
|
|
||||||
styleActiveLine: true
|
|
||||||
gutters: ['CodeMirror-lint-markers']
|
|
||||||
lint: true
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
title: PLUGIN_ADMIN.MEDIA
|
|
||||||
form:
|
|
||||||
validation: loose
|
|
||||||
fields:
|
|
||||||
'types':
|
|
||||||
name: medias
|
|
||||||
type: list
|
|
||||||
label: PLUGIN_ADMIN.MEDIA_TYPES
|
|
||||||
style: vertical
|
|
||||||
key: extension
|
|
||||||
controls: both
|
|
||||||
collapsed: true
|
|
||||||
|
|
||||||
fields:
|
|
||||||
.extension:
|
|
||||||
type: key
|
|
||||||
label: PLUGIN_ADMIN.FILE_EXTENSION
|
|
||||||
.type:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.TYPE
|
|
||||||
.thumb:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.THUMB
|
|
||||||
.mime:
|
|
||||||
type: text
|
|
||||||
label: PLUGIN_ADMIN.MIME_TYPE
|
|
||||||
validate:
|
|
||||||
type: lower
|
|
||||||
.image:
|
|
||||||
type: textarea
|
|
||||||
yaml: true
|
|
||||||
label: PLUGIN_ADMIN.IMAGE_OPTIONS
|
|
||||||
validate:
|
|
||||||
type: yaml
|
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,182 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use ArrayAccess;
|
|
||||||
use Exception;
|
|
||||||
use Grav\Common\Data\Blueprint;
|
|
||||||
use Grav\Common\Data\Data;
|
|
||||||
use Grav\Framework\Form\Interfaces\FormFlashInterface;
|
|
||||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
|
||||||
use Grav\Framework\Form\Traits\FormTrait;
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use JsonSerializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class AdminForm
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*/
|
|
||||||
class AdminForm implements FormInterface, JsonSerializable
|
|
||||||
{
|
|
||||||
use FormTrait;
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_name;
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_action;
|
|
||||||
/** @var callable */
|
|
||||||
protected $submitMethod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AdminForm constructor.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param array $options
|
|
||||||
*/
|
|
||||||
public function __construct(string $name, array $options)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->nonce_name = $options['nonce_name'] ?? 'admin-nonce';
|
|
||||||
$this->nonce_action = $options['nonce_action'] ?? 'admin-form';
|
|
||||||
|
|
||||||
$this->setId($options['id'] ?? $this->getName());
|
|
||||||
$this->setUniqueId($options['unique_id'] ?? $this->getName());
|
|
||||||
$this->setBlueprint($options['blueprint']);
|
|
||||||
$this->setSubmitMethod($options['submit_method'] ?? null);
|
|
||||||
$this->setFlashLookupFolder('tmp://admin/forms/[SESSIONID]');
|
|
||||||
|
|
||||||
if (!empty($options['reset'])) {
|
|
||||||
$this->getFlash()->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function initialize(): AdminForm
|
|
||||||
{
|
|
||||||
$this->messages = [];
|
|
||||||
$this->submitted = false;
|
|
||||||
$this->unsetFlash();
|
|
||||||
|
|
||||||
/** @var FormFlashInterface $flash */
|
|
||||||
$flash = $this->getFlash();
|
|
||||||
if ($flash->exists()) {
|
|
||||||
$data = $flash->getData();
|
|
||||||
if (null !== $data) {
|
|
||||||
$data = new Data($data, $this->getBlueprint());
|
|
||||||
$data->setKeepEmptyValues(true);
|
|
||||||
$data->setMissingValuesAsNull(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->data = $data;
|
|
||||||
$this->files = $flash->getFilesByFields(false);
|
|
||||||
} else {
|
|
||||||
$this->data = new Data([], $this->getBlueprint());
|
|
||||||
$this->files = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getNonceName(): string
|
|
||||||
{
|
|
||||||
return $this->nonce_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getNonceAction(): string
|
|
||||||
{
|
|
||||||
return $this->nonce_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getScope(): string
|
|
||||||
{
|
|
||||||
return 'data.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Blueprint $blueprint
|
|
||||||
*/
|
|
||||||
public function setBlueprint(Blueprint $blueprint): void
|
|
||||||
{
|
|
||||||
if (null === $blueprint) {
|
|
||||||
throw new InvalidArgumentException('Blueprint is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->blueprint = $blueprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $field
|
|
||||||
* @param mixed $value
|
|
||||||
*/
|
|
||||||
public function setData(string $field, $value): void
|
|
||||||
{
|
|
||||||
$this->getData()->set($field, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Blueprint
|
|
||||||
*/
|
|
||||||
public function getBlueprint(): Blueprint
|
|
||||||
{
|
|
||||||
return $this->blueprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param callable|null $submitMethod
|
|
||||||
*/
|
|
||||||
public function setSubmitMethod(?callable $submitMethod): void
|
|
||||||
{
|
|
||||||
if (null === $submitMethod) {
|
|
||||||
throw new InvalidArgumentException('Submit method is required');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->submitMethod = $submitMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $data
|
|
||||||
* @param array $files
|
|
||||||
* @return void
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
protected function doSubmit(array $data, array $files): void
|
|
||||||
{
|
|
||||||
$method = $this->submitMethod;
|
|
||||||
$method($data, $files);
|
|
||||||
|
|
||||||
$this->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter validated data.
|
|
||||||
*
|
|
||||||
* @param ArrayAccess|Data|null $data
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function filterData($data = null): void
|
|
||||||
{
|
|
||||||
if ($data instanceof Data) {
|
|
||||||
$data->filter(true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Page\Interfaces\PageInterface;
|
|
||||||
use Grav\Common\Page\Page;
|
|
||||||
use Grav\Framework\Form\Interfaces\FormFactoryInterface;
|
|
||||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class FlexFormFactory
|
|
||||||
* @package Grav\Plugin\FlexObjects
|
|
||||||
*/
|
|
||||||
class AdminFormFactory implements FormFactoryInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param Page $page
|
|
||||||
* @param string $name
|
|
||||||
* @param array $form
|
|
||||||
* @return FormInterface|null
|
|
||||||
*/
|
|
||||||
public function createPageForm(Page $page, string $name, array $form): ?FormInterface
|
|
||||||
{
|
|
||||||
return $this->createFormForPage($page, $name, $form);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param PageInterface $page
|
|
||||||
* @param string $name
|
|
||||||
* @param array $form
|
|
||||||
* @return FormInterface|null
|
|
||||||
*/
|
|
||||||
public function createFormForPage(PageInterface $page, string $name, array $form): ?FormInterface
|
|
||||||
{
|
|
||||||
/** @var Admin|null $admin */
|
|
||||||
$admin = Grav::instance()['admin'] ?? null;
|
|
||||||
$object = $admin->form ?? null;
|
|
||||||
|
|
||||||
return $object && $object->getName() === $name ? $object : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin\Controllers;
|
|
||||||
|
|
||||||
use Grav\Common\Debugger;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Inflector;
|
|
||||||
use Grav\Common\Language\Language;
|
|
||||||
use Grav\Common\Utils;
|
|
||||||
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
|
|
||||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
|
||||||
use Grav\Framework\Psr7\Response;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\NotFoundException;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\PageExpiredException;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\RequestException;
|
|
||||||
use Grav\Framework\Route\Route;
|
|
||||||
use Grav\Framework\Session\SessionInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
|
||||||
use RocketTheme\Toolbox\Event\Event;
|
|
||||||
use RocketTheme\Toolbox\Session\Message;
|
|
||||||
|
|
||||||
abstract class AbstractController implements RequestHandlerInterface
|
|
||||||
{
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_action = 'admin-form';
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_name = 'admin-nonce';
|
|
||||||
|
|
||||||
/** @var ServerRequestInterface */
|
|
||||||
protected $request;
|
|
||||||
|
|
||||||
/** @var Grav */
|
|
||||||
protected $grav;
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
protected $type;
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
protected $key;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle request.
|
|
||||||
*
|
|
||||||
* Fires event: admin.[directory].[task|action].[command]
|
|
||||||
*
|
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
|
||||||
{
|
|
||||||
$attributes = $request->getAttributes();
|
|
||||||
$this->request = $request;
|
|
||||||
$this->grav = $attributes['grav'] ?? Grav::instance();
|
|
||||||
$this->type = $attributes['type'] ?? null;
|
|
||||||
$this->key = $attributes['key'] ?? null;
|
|
||||||
|
|
||||||
/** @var Route $route */
|
|
||||||
$route = $attributes['route'];
|
|
||||||
$post = $this->getPost();
|
|
||||||
|
|
||||||
if ($this->isFormSubmit()) {
|
|
||||||
$form = $this->getForm();
|
|
||||||
$this->nonce_name = $attributes['nonce_name'] ?? $form->getNonceName();
|
|
||||||
$this->nonce_action = $attributes['nonce_action'] ?? $form->getNonceAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$task = $request->getAttribute('task') ?? $post['task'] ?? $route->getParam('task');
|
|
||||||
if ($task) {
|
|
||||||
if (empty($attributes['forwarded'])) {
|
|
||||||
$this->checkNonce($task);
|
|
||||||
}
|
|
||||||
$type = 'task';
|
|
||||||
$command = $task;
|
|
||||||
} else {
|
|
||||||
$type = 'action';
|
|
||||||
$command = $request->getAttribute('action') ?? $post['action'] ?? $route->getParam('action') ?? 'display';
|
|
||||||
}
|
|
||||||
$command = strtolower($command);
|
|
||||||
|
|
||||||
$event = new Event(
|
|
||||||
[
|
|
||||||
'controller' => $this,
|
|
||||||
'response' => null
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->grav->fireEvent("admin.{$this->type}.{$type}.{$command}", $event);
|
|
||||||
|
|
||||||
$response = $event['response'];
|
|
||||||
if (!$response) {
|
|
||||||
/** @var Inflector $inflector */
|
|
||||||
$inflector = $this->grav['inflector'];
|
|
||||||
$method = $type . $inflector::camelize($command);
|
|
||||||
if ($method && method_exists($this, $method)) {
|
|
||||||
$response = $this->{$method}($request);
|
|
||||||
} else {
|
|
||||||
throw new NotFoundException($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
/** @var Debugger $debugger */
|
|
||||||
$debugger = $this->grav['debugger'];
|
|
||||||
$debugger->addException($e);
|
|
||||||
|
|
||||||
$response = $this->createErrorResponse($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($response instanceof Response) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createJsonResponse($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get request.
|
|
||||||
*
|
|
||||||
* @return ServerRequestInterface
|
|
||||||
*/
|
|
||||||
public function getRequest(): ServerRequestInterface
|
|
||||||
{
|
|
||||||
return $this->request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $name
|
|
||||||
* @param mixed $default
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getPost(?string $name = null, $default = null)
|
|
||||||
{
|
|
||||||
$body = $this->request->getParsedBody();
|
|
||||||
|
|
||||||
if ($name) {
|
|
||||||
return $body[$name] ?? $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a form has been submitted.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isFormSubmit(): bool
|
|
||||||
{
|
|
||||||
return (bool)$this->getPost('__form-name__');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get form.
|
|
||||||
*
|
|
||||||
* @param string|null $type
|
|
||||||
* @return FormInterface
|
|
||||||
*/
|
|
||||||
public function getForm(?string $type = null): FormInterface
|
|
||||||
{
|
|
||||||
$object = $this->getObject();
|
|
||||||
if (!$object) {
|
|
||||||
throw new \RuntimeException('Not Found', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$formName = $this->getPost('__form-name__');
|
|
||||||
$uniqueId = $this->getPost('__unique_form_id__') ?: $formName;
|
|
||||||
|
|
||||||
$form = $object->getForm($type ?? 'edit');
|
|
||||||
if ($uniqueId) {
|
|
||||||
$form->setUniqueId($uniqueId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return FlexObjectInterface
|
|
||||||
*/
|
|
||||||
abstract public function getObject();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Grav instance.
|
|
||||||
*
|
|
||||||
* @return Grav
|
|
||||||
*/
|
|
||||||
public function getGrav(): Grav
|
|
||||||
{
|
|
||||||
return $this->grav;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get session.
|
|
||||||
*
|
|
||||||
* @return SessionInterface
|
|
||||||
*/
|
|
||||||
public function getSession(): SessionInterface
|
|
||||||
{
|
|
||||||
return $this->getGrav()['session'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the current admin page.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function createDisplayResponse(): ResponseInterface
|
|
||||||
{
|
|
||||||
return new Response(418);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create custom HTML response.
|
|
||||||
*
|
|
||||||
* @param string $content
|
|
||||||
* @param int $code
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function createHtmlResponse(string $content, ?int $code = null): ResponseInterface
|
|
||||||
{
|
|
||||||
return new Response($code ?: 200, [], $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create JSON response.
|
|
||||||
*
|
|
||||||
* @param array $content
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function createJsonResponse(array $content): ResponseInterface
|
|
||||||
{
|
|
||||||
$code = $content['code'] ?? 200;
|
|
||||||
if ($code >= 301 && $code <= 307) {
|
|
||||||
$code = 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response($code, ['Content-Type' => 'application/json'], json_encode($content));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create redirect response.
|
|
||||||
*
|
|
||||||
* @param string $url
|
|
||||||
* @param int $code
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function createRedirectResponse(string $url, ?int $code = null): ResponseInterface
|
|
||||||
{
|
|
||||||
if (null === $code || $code < 301 || $code > 307) {
|
|
||||||
$code = $this->grav['config']->get('system.pages.redirect_default_code', 302);
|
|
||||||
}
|
|
||||||
|
|
||||||
$accept = $this->getAccept(['application/json', 'text/html']);
|
|
||||||
|
|
||||||
if ($accept === 'application/json') {
|
|
||||||
return $this->createJsonResponse(['code' => $code, 'status' => 'redirect', 'redirect' => $url]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response($code, ['Location' => $url]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create error response.
|
|
||||||
*
|
|
||||||
* @param \Exception $exception
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function createErrorResponse(\Exception $exception): ResponseInterface
|
|
||||||
{
|
|
||||||
$validCodes = [
|
|
||||||
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418,
|
|
||||||
422, 423, 424, 425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 511
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($exception instanceof RequestException) {
|
|
||||||
$code = $exception->getHttpCode();
|
|
||||||
$reason = $exception->getHttpReason();
|
|
||||||
} else {
|
|
||||||
$code = $exception->getCode();
|
|
||||||
$reason = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($code, $validCodes, true)) {
|
|
||||||
$code = 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = $exception->getMessage();
|
|
||||||
$response = [
|
|
||||||
'code' => $code,
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => htmlspecialchars($message, ENT_QUOTES | ENT_HTML5, 'UTF-8')
|
|
||||||
];
|
|
||||||
|
|
||||||
$accept = $this->getAccept(['application/json', 'text/html']);
|
|
||||||
|
|
||||||
if ($accept === 'text/html') {
|
|
||||||
$method = $this->getRequest()->getMethod();
|
|
||||||
|
|
||||||
// On POST etc, redirect back to the previous page.
|
|
||||||
if ($method !== 'GET' && $method !== 'HEAD') {
|
|
||||||
$this->setMessage($message, 'error');
|
|
||||||
$referer = $this->request->getHeaderLine('Referer');
|
|
||||||
return $this->createRedirectResponse($referer, 303);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: improve error page
|
|
||||||
return $this->createHtmlResponse($response['message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response($code, ['Content-Type' => 'application/json'], json_encode($response), '1.1', $reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a string.
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function translate(string $string): string
|
|
||||||
{
|
|
||||||
/** @var Language $language */
|
|
||||||
$language = $this->grav['language'];
|
|
||||||
|
|
||||||
return $language->translate($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set message to be shown in the admin.
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
* @param string $type
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setMessage($message, $type = 'info')
|
|
||||||
{
|
|
||||||
/** @var Message $messages */
|
|
||||||
$messages = $this->grav['messages'];
|
|
||||||
$messages->add($message, $type);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if request nonce is valid.
|
|
||||||
*
|
|
||||||
* @param string $task
|
|
||||||
* @throws PageExpiredException If nonce is not valid.
|
|
||||||
*/
|
|
||||||
protected function checkNonce(string $task): void
|
|
||||||
{
|
|
||||||
$nonce = null;
|
|
||||||
|
|
||||||
if (\in_array(strtoupper($this->request->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
|
||||||
$nonce = $this->getPost($this->nonce_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$nonce) {
|
|
||||||
$nonce = $this->grav['uri']->param($this->nonce_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$nonce) {
|
|
||||||
$nonce = $this->grav['uri']->query($this->nonce_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$nonce || !Utils::verifyNonce($nonce, $this->nonce_action)) {
|
|
||||||
throw new PageExpiredException($this->request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the best matching mime type for the request.
|
|
||||||
*
|
|
||||||
* @param string[] $compare
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
protected function getAccept(array $compare): ?string
|
|
||||||
{
|
|
||||||
$accepted = [];
|
|
||||||
foreach ($this->request->getHeader('Accept') as $accept) {
|
|
||||||
foreach (explode(',', $accept) as $item) {
|
|
||||||
if (!$item) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$split = explode(';q=', $item);
|
|
||||||
$mime = array_shift($split);
|
|
||||||
$priority = array_shift($split) ?? 1.0;
|
|
||||||
|
|
||||||
$accepted[$mime] = $priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arsort($accepted);
|
|
||||||
|
|
||||||
// TODO: add support for image/* etc
|
|
||||||
$list = array_intersect($compare, array_keys($accepted));
|
|
||||||
if (!$list && (isset($accepted['*/*']) || isset($accepted['*']))) {
|
|
||||||
return reset($compare) ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reset($list) ?: null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin\Controllers;
|
|
||||||
|
|
||||||
use Grav\Common\Config\Config;
|
|
||||||
use Grav\Common\Data\Blueprint;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Language\Language;
|
|
||||||
use Grav\Common\Page\Interfaces\PageInterface;
|
|
||||||
use Grav\Common\Page\Page;
|
|
||||||
use Grav\Common\Page\Pages;
|
|
||||||
use Grav\Common\Uri;
|
|
||||||
use Grav\Common\User\Interfaces\UserInterface;
|
|
||||||
use Grav\Common\Utils;
|
|
||||||
use Grav\Framework\Controller\Traits\ControllerResponseTrait;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\PageExpiredException;
|
|
||||||
use Grav\Framework\Session\SessionInterface;
|
|
||||||
use Grav\Plugin\Admin\Admin;
|
|
||||||
use Grav\Plugin\Admin\AdminForm;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
use RocketTheme\Toolbox\Session\Message;
|
|
||||||
|
|
||||||
abstract class AdminController
|
|
||||||
{
|
|
||||||
use ControllerResponseTrait {
|
|
||||||
createRedirectResponse as traitCreateRedirectResponse;
|
|
||||||
getErrorJson as traitGetErrorJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_action = 'admin-form';
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_name = 'admin-nonce';
|
|
||||||
/** @var Grav */
|
|
||||||
protected $grav;
|
|
||||||
/** @var PageInterface */
|
|
||||||
protected $page;
|
|
||||||
/** @var AdminForm|null */
|
|
||||||
protected $form;
|
|
||||||
|
|
||||||
public function __construct(Grav $grav)
|
|
||||||
{
|
|
||||||
$this->grav = $grav;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return PageInterface|null
|
|
||||||
*/
|
|
||||||
public function getPage(): ?PageInterface
|
|
||||||
{
|
|
||||||
return $this->page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get currently active form.
|
|
||||||
*
|
|
||||||
* @return AdminForm|null
|
|
||||||
*/
|
|
||||||
public function getActiveForm(): ?AdminForm
|
|
||||||
{
|
|
||||||
if (null === $this->form) {
|
|
||||||
$post = $this->getPost();
|
|
||||||
|
|
||||||
$active = $post['__form-name__'] ?? null;
|
|
||||||
|
|
||||||
$this->form = $active ? $this->getForm($active) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a form.
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param array $options
|
|
||||||
* @return AdminForm|null
|
|
||||||
*/
|
|
||||||
public function getForm(string $name, array $options = []): ?AdminForm
|
|
||||||
{
|
|
||||||
$post = $this->getPost();
|
|
||||||
$page = $this->getPage();
|
|
||||||
$forms = $page ? $page->forms() : [];
|
|
||||||
$blueprint = $forms[$name] ?? null;
|
|
||||||
if (null === $blueprint) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$active = $post['__form-name__'] ?? null;
|
|
||||||
$unique_id = $active && $active === $name ? ($post['__unique_form_id__'] ?? null) : null;
|
|
||||||
|
|
||||||
$options += [
|
|
||||||
'unique_id' => $unique_id,
|
|
||||||
'blueprint' => new Blueprint(null, ['form' => $blueprint]),
|
|
||||||
'submit_method' => $this->getFormSubmitMethod($name),
|
|
||||||
'nonce_name' => $this->nonce_name,
|
|
||||||
'nonce_action' => $this->nonce_action,
|
|
||||||
];
|
|
||||||
|
|
||||||
return new AdminForm($name, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected function getFormSubmitMethod(string $name): callable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $route
|
|
||||||
* @param string|null $lang
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getAdminUrl(string $route, ?string $lang = null): string
|
|
||||||
{
|
|
||||||
/** @var Pages $pages */
|
|
||||||
$pages = $this->grav['pages'];
|
|
||||||
$admin = $this->getAdmin();
|
|
||||||
|
|
||||||
return $pages->baseUrl($lang) . $admin->base . $route;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $route
|
|
||||||
* @param string|null $lang
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getAbsoluteAdminUrl(string $route, ?string $lang = null): string
|
|
||||||
{
|
|
||||||
/** @var Pages $pages */
|
|
||||||
$pages = $this->grav['pages'];
|
|
||||||
$admin = $this->getAdmin();
|
|
||||||
|
|
||||||
return $pages->baseUrl($lang, true) . $admin->base . $route;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get session.
|
|
||||||
*
|
|
||||||
* @return SessionInterface
|
|
||||||
*/
|
|
||||||
public function getSession(): SessionInterface
|
|
||||||
{
|
|
||||||
return $this->grav['session'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Admin
|
|
||||||
*/
|
|
||||||
protected function getAdmin(): Admin
|
|
||||||
{
|
|
||||||
return $this->grav['admin'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return UserInterface
|
|
||||||
*/
|
|
||||||
protected function getUser(): UserInterface
|
|
||||||
{
|
|
||||||
return $this->getAdmin()->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ServerRequestInterface
|
|
||||||
*/
|
|
||||||
public function getRequest(): ServerRequestInterface
|
|
||||||
{
|
|
||||||
return $this->getAdmin()->request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getPost(): array
|
|
||||||
{
|
|
||||||
return (array)($this->getRequest()->getParsedBody() ?? []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a string.
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param mixed ...$args
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function translate(string $string, ...$args): string
|
|
||||||
{
|
|
||||||
/** @var Language $language */
|
|
||||||
$language = $this->grav['language'];
|
|
||||||
|
|
||||||
array_unshift($args, $string);
|
|
||||||
|
|
||||||
return $language->translate($args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set message to be shown in the admin.
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
* @param string $type
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setMessage(string $message, string $type = 'info'): AdminController
|
|
||||||
{
|
|
||||||
/** @var Message $messages */
|
|
||||||
$messages = $this->grav['messages'];
|
|
||||||
$messages->add($message, $type);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Config
|
|
||||||
*/
|
|
||||||
protected function getConfig(): Config
|
|
||||||
{
|
|
||||||
return $this->grav['config'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if request nonce is valid.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @throws PageExpiredException If nonce is not valid.
|
|
||||||
*/
|
|
||||||
protected function checkNonce(): void
|
|
||||||
{
|
|
||||||
$nonce = null;
|
|
||||||
|
|
||||||
$nonce_name = $this->form ? $this->form->getNonceName() : $this->nonce_name;
|
|
||||||
$nonce_action = $this->form ? $this->form->getNonceAction() : $this->nonce_action;
|
|
||||||
|
|
||||||
if (\in_array(strtoupper($this->getRequest()->getMethod()), ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
|
||||||
$post = $this->getPost();
|
|
||||||
$nonce = $post[$nonce_name] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var Uri $uri */
|
|
||||||
$uri = $this->grav['uri'];
|
|
||||||
if (!$nonce) {
|
|
||||||
$nonce = $uri->param($nonce_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$nonce) {
|
|
||||||
$nonce = $uri->query($nonce_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$nonce || !Utils::verifyNonce($nonce, $nonce_action)) {
|
|
||||||
throw new PageExpiredException($this->getRequest());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the best matching mime type for the request.
|
|
||||||
*
|
|
||||||
* @param string[] $compare
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
protected function getAccept(array $compare): ?string
|
|
||||||
{
|
|
||||||
$accepted = [];
|
|
||||||
foreach ($this->getRequest()->getHeader('Accept') as $accept) {
|
|
||||||
foreach (explode(',', $accept) as $item) {
|
|
||||||
if (!$item) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$split = explode(';q=', $item);
|
|
||||||
$mime = array_shift($split);
|
|
||||||
$priority = array_shift($split) ?? 1.0;
|
|
||||||
|
|
||||||
$accepted[$mime] = $priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arsort($accepted);
|
|
||||||
|
|
||||||
// TODO: add support for image/* etc
|
|
||||||
$list = array_intersect($compare, array_keys($accepted));
|
|
||||||
if (!$list && (isset($accepted['*/*']) || isset($accepted['*']))) {
|
|
||||||
return reset($compare) ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reset($list) ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $template
|
|
||||||
* @return PageInterface
|
|
||||||
*/
|
|
||||||
protected function createPage(string $template): PageInterface
|
|
||||||
{
|
|
||||||
$page = new Page();
|
|
||||||
|
|
||||||
// Plugins may not have the correct Cache-Control header set, force no-store for the proxies.
|
|
||||||
$page->expires(0);
|
|
||||||
|
|
||||||
$filename = "plugin://admin/pages/admin/{$template}.md";
|
|
||||||
if (!file_exists($filename)) {
|
|
||||||
throw new \RuntimeException(sprintf('Creating admin page %s failed: not found', $template));
|
|
||||||
}
|
|
||||||
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage("Admin page: {$template}");
|
|
||||||
|
|
||||||
$page->init(new \SplFileInfo($filename));
|
|
||||||
$page->slug($template);
|
|
||||||
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|null $url
|
|
||||||
* @param int|null $code
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
protected function createRedirectResponse(?string $url = null, ?int $code = null): ResponseInterface
|
|
||||||
{
|
|
||||||
$request = $this->getRequest();
|
|
||||||
|
|
||||||
if (null === $url || '' === $url) {
|
|
||||||
$url = (string)$request->getUri();
|
|
||||||
} elseif (mb_strpos($url, '/') === 0) {
|
|
||||||
$url = $this->getAbsoluteAdminUrl($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $code) {
|
|
||||||
if (in_array($request->getMethod(), ['GET', 'HEAD'])) {
|
|
||||||
$code = 302;
|
|
||||||
} else {
|
|
||||||
$code = 303;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->traitCreateRedirectResponse($url, $code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \Throwable $e
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getErrorJson(\Throwable $e): array
|
|
||||||
{
|
|
||||||
$json = $this->traitGetErrorJson($e);
|
|
||||||
$code = $e->getCode();
|
|
||||||
if ($code === 401) {
|
|
||||||
$json['redirect'] = $this->getAbsoluteAdminUrl('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $json;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,673 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin\Controllers\Login;
|
|
||||||
|
|
||||||
use Grav\Common\Debugger;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Page\Pages;
|
|
||||||
use Grav\Common\Uri;
|
|
||||||
use Grav\Common\User\Interfaces\UserCollectionInterface;
|
|
||||||
use Grav\Common\User\Interfaces\UserInterface;
|
|
||||||
use Grav\Common\Utils;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\PageExpiredException;
|
|
||||||
use Grav\Framework\RequestHandler\Exception\RequestException;
|
|
||||||
use Grav\Plugin\Admin\Admin;
|
|
||||||
use Grav\Plugin\Admin\Controllers\AdminController;
|
|
||||||
use Grav\Plugin\Email\Email;
|
|
||||||
use Grav\Plugin\Login\Login;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use RobThree\Auth\TwoFactorAuthException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class LoginController
|
|
||||||
* @package Grav\Plugin\Admin\Controllers\Login
|
|
||||||
*/
|
|
||||||
class LoginController extends AdminController
|
|
||||||
{
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_action = 'admin-login';
|
|
||||||
/** @var string */
|
|
||||||
protected $nonce_name = 'login-nonce';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function displayLogin(): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('login');
|
|
||||||
|
|
||||||
$user = $this->getUser();
|
|
||||||
if ($this->is2FA($user)) {
|
|
||||||
$this->form = $this->getForm('login-twofa', ['reset' => true]);
|
|
||||||
} else {
|
|
||||||
$this->form = $this->getForm('login', ['reset' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function displayForgot(): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('forgot');
|
|
||||||
$this->form = $this->getForm('admin-login-forgot', ['reset' => true]);
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the reset password action.
|
|
||||||
*
|
|
||||||
* @param string|null $username
|
|
||||||
* @param string|null $token
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function displayReset(?string $username = null, ?string $token = null): ResponseInterface
|
|
||||||
{
|
|
||||||
if ('' === (string)$username || '' === (string)$token) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.RESET_INVALID_LINK'), 'error');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/forgot');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->page = $this->createPage('reset');
|
|
||||||
$this->form = $this->getForm('admin-login-reset', ['reset' => true]);
|
|
||||||
$this->form->setData('username', $username);
|
|
||||||
$this->form->setData('token', $token);
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.RESET_NEW_PASSWORD'));
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function displayRegister(): ResponseInterface
|
|
||||||
{
|
|
||||||
$route = $this->getRequest()->getAttribute('admin')['route'] ?? '';
|
|
||||||
if ('' !== $route) {
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->page = $this->createPage('register');
|
|
||||||
$this->form = $this->getForm('admin-login-register');
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function displayUnauthorized(): ResponseInterface
|
|
||||||
{
|
|
||||||
$uri = (string)$this->getRequest()->getUri();
|
|
||||||
|
|
||||||
$ext = Utils::pathinfo($uri, PATHINFO_EXTENSION);
|
|
||||||
$accept = $this->getAccept(['application/json', 'text/html']);
|
|
||||||
if ($ext === 'json' || $accept === 'application/json') {
|
|
||||||
return $this->createErrorResponse(new RequestException($this->getRequest(), $this->translate('PLUGIN_ADMIN.LOGGED_OUT'), 401));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.LOGGED_OUT'), 'warning');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle login.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskLogin(): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('login');
|
|
||||||
$this->form = $this->getActiveForm() ?? $this->getForm('login');
|
|
||||||
try {
|
|
||||||
$this->checkNonce();
|
|
||||||
} catch (PageExpiredException $e) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
$post = $this->getPost();
|
|
||||||
$credentials = (array)($post['data'] ?? []);
|
|
||||||
$login = $this->getLogin();
|
|
||||||
$config = $this->getConfig();
|
|
||||||
|
|
||||||
$userKey = (string)($credentials['username'] ?? '');
|
|
||||||
// Pseudonymization of the IP.
|
|
||||||
$ipKey = sha1(Uri::ip() . $config->get('security.salt'));
|
|
||||||
|
|
||||||
$rateLimiter = $login->getRateLimiter('login_attempts');
|
|
||||||
|
|
||||||
// Check if the current IP has been used in failed login attempts.
|
|
||||||
$attempts = count($rateLimiter->getAttempts($ipKey, 'ip'));
|
|
||||||
|
|
||||||
$rateLimiter->registerRateLimitedAction($ipKey, 'ip')->registerRateLimitedAction($userKey);
|
|
||||||
|
|
||||||
// Check rate limit for both IP and user, but allow each IP a single try even if user is already rate limited.
|
|
||||||
if ($rateLimiter->isRateLimited($ipKey, 'ip') || ($attempts && $rateLimiter->isRateLimited($userKey))) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login: rate limit, redirecting', $credentials);
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_LOGIN.TOO_MANY_LOGIN_ATTEMPTS', $rateLimiter->getInterval()), 'error');
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
/** @var Pages $pages */
|
|
||||||
$pages = $this->grav['pages'];
|
|
||||||
|
|
||||||
// Redirect to the home page of the site.
|
|
||||||
return $this->createRedirectResponse($pages->homeUrl(null, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login', $credentials);
|
|
||||||
|
|
||||||
// Fire Login process.
|
|
||||||
$event = $login->login(
|
|
||||||
$credentials,
|
|
||||||
['admin' => true, 'twofa' => $config->get('plugins.admin.twofa_enabled', false)],
|
|
||||||
['authorize' => 'admin.login', 'return_event' => true]
|
|
||||||
);
|
|
||||||
$user = $event->getUser();
|
|
||||||
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login: user', $user);
|
|
||||||
|
|
||||||
$redirect = (string)$this->getRequest()->getUri();
|
|
||||||
|
|
||||||
if ($user->authenticated) {
|
|
||||||
$rateLimiter->resetRateLimit($ipKey, 'ip')->resetRateLimit($userKey);
|
|
||||||
if ($user->authorized) {
|
|
||||||
$event->defMessage('PLUGIN_ADMIN.LOGIN_LOGGED_IN', 'info');
|
|
||||||
}
|
|
||||||
|
|
||||||
$event->defRedirect($redirect);
|
|
||||||
} elseif ($user->authorized) {
|
|
||||||
$event->defMessage('PLUGIN_LOGIN.ACCESS_DENIED', 'error');
|
|
||||||
} else {
|
|
||||||
$event->defMessage('PLUGIN_LOGIN.LOGIN_FAILED', 'error');
|
|
||||||
}
|
|
||||||
|
|
||||||
$event->defRedirect($redirect);
|
|
||||||
|
|
||||||
$message = $event->getMessage();
|
|
||||||
if ($message) {
|
|
||||||
$this->setMessage($this->translate($message), $event->getMessageType());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($event->getRedirect());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle logout when user isn't fully logged in or clicks logout after the session has been expired.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskLogout(): ResponseInterface
|
|
||||||
{
|
|
||||||
// We do not need to check the nonce here as user session has been expired or user hasn't fully logged in (2FA).
|
|
||||||
// Just be sure we terminate the current session.
|
|
||||||
$login = $this->getLogin();
|
|
||||||
$event = $login->logout(['admin' => true], ['return_event' => true]);
|
|
||||||
|
|
||||||
$event->defMessage('PLUGIN_ADMIN.LOGGED_OUT', 'info');
|
|
||||||
$message = $event->getMessage();
|
|
||||||
if ($message) {
|
|
||||||
$this->getSession()->setFlashCookieObject(Admin::TMP_COOKIE_NAME, ['message' => $this->translate($message), 'status' => $event->getMessageType()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a fresh login nonce and keep anonymous session alive while on the login screen.
|
|
||||||
*
|
|
||||||
* Route: GET /login.json/task:nonce
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskNonce(): ResponseInterface
|
|
||||||
{
|
|
||||||
// Touch the anonymous session to prevent immediate expiry on the login page.
|
|
||||||
$session = $this->getSession();
|
|
||||||
if (!$session->isStarted()) {
|
|
||||||
$session->start();
|
|
||||||
}
|
|
||||||
$session->__set('admin_login_keepalive', time());
|
|
||||||
|
|
||||||
// Generate a fresh nonce for the login form.
|
|
||||||
$nonce = Admin::getNonce($this->nonce_action);
|
|
||||||
|
|
||||||
return $this->createJsonResponse([
|
|
||||||
'status' => 'success',
|
|
||||||
'message' => null,
|
|
||||||
'nonce_name' => $this->nonce_name,
|
|
||||||
'nonce_action' => $this->nonce_action,
|
|
||||||
'nonce' => $nonce
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle 2FA verification.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskTwofa(): ResponseInterface
|
|
||||||
{
|
|
||||||
$user = $this->getUser();
|
|
||||||
if (!$this->is2FA($user)) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login: user is not logged in or does not have 2FA enabled', $user);
|
|
||||||
|
|
||||||
// Task is visible only for users who have enabled 2FA.
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
$login = $this->getLogin();
|
|
||||||
|
|
||||||
$this->page = $this->createPage('login');
|
|
||||||
$this->form = $this->getForm('login-twofa');
|
|
||||||
try {
|
|
||||||
$this->checkNonce();
|
|
||||||
} catch (PageExpiredException $e) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
|
||||||
|
|
||||||
// Failed 2FA nonce check, logout and redirect.
|
|
||||||
$login->logout(['admin' => true]);
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$post = $this->getPost();
|
|
||||||
$data = $post['data'] ?? [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
$twoFa = $login->twoFactorAuth();
|
|
||||||
} catch (TwoFactorAuthException $e) {
|
|
||||||
/** @var Debugger $debugger */
|
|
||||||
$debugger = $this->grav['debugger'];
|
|
||||||
$debugger->addException($e);
|
|
||||||
|
|
||||||
$twoFa = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = $data['2fa_code'] ?? '';
|
|
||||||
$secret = $user->twofa_secret ?? '';
|
|
||||||
// Strip any whitespace from secret (fixes corrupted secrets)
|
|
||||||
$secret = preg_replace('/\s+/', '', $secret);
|
|
||||||
$twofa_valid = $twoFa->verifyCode($secret, $code);
|
|
||||||
|
|
||||||
$yubikey_otp = $data['yubikey_otp'] ?? '';
|
|
||||||
$yubikey_id = $user->yubikey_id ?? '';
|
|
||||||
$yubikey_valid = $twoFa->verifyYubikeyOTP($yubikey_id, $yubikey_otp);
|
|
||||||
|
|
||||||
$redirect = (string)$this->getRequest()->getUri();
|
|
||||||
|
|
||||||
if (null === $twoFa || !$user->authenticated || (!$twofa_valid && !$yubikey_valid) ) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login: 2FA check failed, log out!');
|
|
||||||
|
|
||||||
// Failed 2FA auth, logout and redirect to the current page.
|
|
||||||
$login->logout(['admin' => true]);
|
|
||||||
|
|
||||||
$this->grav['session']->setFlashCookieObject(Admin::TMP_COOKIE_NAME, ['message' => $this->translate('PLUGIN_ADMIN.2FA_FAILED'), 'status' => 'error']);
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($redirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Successful 2FA, authorize user and redirect.
|
|
||||||
Grav::instance()['user']->authorized = true;
|
|
||||||
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Admin login: 2FA check succeeded, authorize user and redirect');
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.LOGIN_LOGGED_IN'));
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($redirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the reset password action.
|
|
||||||
*
|
|
||||||
* @param string|null $username
|
|
||||||
* @param string|null $token
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskReset(?string $username = null, ?string $token = null): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('reset');
|
|
||||||
$this->form = $this->getForm('admin-login-reset');
|
|
||||||
try {
|
|
||||||
$this->checkNonce();
|
|
||||||
} catch (PageExpiredException $e) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$post = $this->getPost();
|
|
||||||
$data = $post['data'] ?? [];
|
|
||||||
$users = $this->getAccounts();
|
|
||||||
|
|
||||||
$username = $username ?? $data['username'] ?? null;
|
|
||||||
$token = $token ?? $data['token'] ?? null;
|
|
||||||
|
|
||||||
$user = $username ? $users->load($username) : null;
|
|
||||||
$password = $data['password'];
|
|
||||||
|
|
||||||
if ($user && $user->exists() && !empty($user->get('reset'))) {
|
|
||||||
[$good_token, $expire] = explode('::', $user->get('reset'));
|
|
||||||
|
|
||||||
if ($good_token === $token) {
|
|
||||||
if (time() > $expire) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.RESET_LINK_EXPIRED'), 'error');
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/forgot');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set new password.
|
|
||||||
$login = $this->getLogin();
|
|
||||||
try {
|
|
||||||
$login->validateField('password1', $password);
|
|
||||||
} catch (\RuntimeException $e) {
|
|
||||||
$this->setMessage($this->translate($e->getMessage()), 'error');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse("/reset/u/{$username}/{$token}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->undef('hashed_password');
|
|
||||||
$user->undef('reset');
|
|
||||||
$user->update(['password' => $password]);
|
|
||||||
$user->save();
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.RESET_PASSWORD_RESET'));
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage(sprintf('Failed to reset password: Token %s is not good', $token));
|
|
||||||
} else {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage(sprintf('Failed to reset password: User %s does not exist or has not requested reset', $username));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.RESET_INVALID_LINK'), 'error');
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/forgot');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the email password recovery procedure.
|
|
||||||
*
|
|
||||||
* Sends email to the user.
|
|
||||||
*
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskForgot(): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('forgot');
|
|
||||||
$this->form = $this->getForm('admin-login-forgot');
|
|
||||||
try {
|
|
||||||
$this->checkNonce();
|
|
||||||
} catch (PageExpiredException $e) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$post = $this->getPost();
|
|
||||||
$data = $post['data'] ?? [];
|
|
||||||
$login = $this->getLogin();
|
|
||||||
$users = $this->getAccounts();
|
|
||||||
$email = $this->getEmail();
|
|
||||||
|
|
||||||
$current = (string)$this->getRequest()->getUri();
|
|
||||||
|
|
||||||
$search = isset($data['username']) ? strip_tags($data['username']) : '';
|
|
||||||
$user = !empty($search) ? $users->load($search) : null;
|
|
||||||
$username = $user->username ?? null;
|
|
||||||
$to = $user->email ?? null;
|
|
||||||
|
|
||||||
// Only send email to users which are enabled and have an email address.
|
|
||||||
if (null === $user || $user->state !== 'enabled' || !$to) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage(sprintf('Failed sending email: %s <%s> was not found or is blocked', $search, $to ?? 'N/A'));
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'));
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($current);
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = $this->getConfig();
|
|
||||||
|
|
||||||
// Check rate limit for the user.
|
|
||||||
$rateLimiter = $login->getRateLimiter('pw_resets');
|
|
||||||
$rateLimiter->registerRateLimitedAction($username);
|
|
||||||
if ($rateLimiter->isRateLimited($username)) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage(sprintf('Failed sending email: user %s <%s> is rate limited', $search, $to));
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
$interval = $config->get('plugins.login.max_pw_resets_interval', 2);
|
|
||||||
|
|
||||||
// Security: Use generic message to prevent email enumeration (GHSA-q3qx-cp62-f6m7)
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.FORGOT_CANNOT_RESET_RATE_LIMITED', $interval), 'error');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($current);
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = md5(uniqid(mt_rand(), true));
|
|
||||||
$expire = time() + 3600; // 1 hour
|
|
||||||
|
|
||||||
$user->set('reset', $token . '::' . $expire);
|
|
||||||
$user->save();
|
|
||||||
|
|
||||||
$from = $config->get('plugins.email.from');
|
|
||||||
if (empty($from)) {
|
|
||||||
Admin::DEBUG && Admin::addDebugMessage('Failed sending email: from address is not configured in email plugin');
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.FORGOT_EMAIL_NOT_CONFIGURED'), 'error');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse($current);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not trust username from the request.
|
|
||||||
$fullname = $user->fullname ?: $username;
|
|
||||||
$author = $config->get('site.author.name', '');
|
|
||||||
$sitename = $config->get('site.title', 'Website');
|
|
||||||
$reset_route = "/reset/u/{$username}/{$token}";
|
|
||||||
|
|
||||||
$site_host = $config->get('plugins.login.site_host');
|
|
||||||
if (!empty($site_host)) {
|
|
||||||
$admin = $this->getAdmin();
|
|
||||||
$reset_link = rtrim($site_host, '/') . '/' . trim($admin->base, '/') . '/' . ltrim($reset_route, '/');
|
|
||||||
} else {
|
|
||||||
$reset_link = $this->getAbsoluteAdminUrl($reset_route);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For testing only!
|
|
||||||
//Admin::DEBUG && Admin::addDebugMessage(sprintf('Reset link: %s', $reset_link));
|
|
||||||
|
|
||||||
$subject = $this->translate('PLUGIN_ADMIN.FORGOT_EMAIL_SUBJECT', $sitename);
|
|
||||||
$content = $this->translate('PLUGIN_ADMIN.FORGOT_EMAIL_BODY', $fullname, $reset_link, $author, $sitename);
|
|
||||||
|
|
||||||
$this->grav['twig']->init();
|
|
||||||
$body = $this->grav['twig']->processTemplate('email/base.html.twig', ['content' => $content]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$message = $email->message($subject, $body, 'text/html')->setFrom($from)->setTo($to);
|
|
||||||
$sent = $email->send($message);
|
|
||||||
if ($sent < 1) {
|
|
||||||
throw new \RuntimeException('Sending email failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL'));
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$rateLimiter->resetRateLimit($username);
|
|
||||||
|
|
||||||
/** @var Debugger $debugger */
|
|
||||||
$debugger = $this->grav['debugger'];
|
|
||||||
$debugger->addException($e);
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.FORGOT_FAILED_TO_EMAIL'), 'error');
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/forgot');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->form->reset();
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function taskRegister(): ResponseInterface
|
|
||||||
{
|
|
||||||
$this->page = $this->createPage('register');
|
|
||||||
$this->form = $form = $this->getForm('admin-login-register');
|
|
||||||
try {
|
|
||||||
$this->checkNonce();
|
|
||||||
} catch (PageExpiredException $e) {
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.INVALID_SECURITY_TOKEN'), 'error');
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: Calls $this->doRegistration() to perform the user registration.
|
|
||||||
$form->handleRequest($this->getRequest());
|
|
||||||
$error = $form->getError();
|
|
||||||
$errors = $form->getErrors();
|
|
||||||
if ($error || $errors) {
|
|
||||||
foreach ($errors as $field => $list) {
|
|
||||||
foreach ((array)$list as $message) {
|
|
||||||
if ($message !== $error) {
|
|
||||||
$this->setMessage($message, 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createDisplayResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setMessage($this->translate('PLUGIN_ADMIN.LOGIN_LOGGED_IN'));
|
|
||||||
|
|
||||||
return $this->createRedirectResponse('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param UserInterface $user
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function is2FA(UserInterface $user): bool
|
|
||||||
{
|
|
||||||
return $user && $user->authenticated && !$user->authorized && $user->get('twofa_enabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $name
|
|
||||||
* @return callable
|
|
||||||
*/
|
|
||||||
protected function getFormSubmitMethod(string $name): callable
|
|
||||||
{
|
|
||||||
switch ($name) {
|
|
||||||
case 'login':
|
|
||||||
case 'login-twofa':
|
|
||||||
case 'admin-login-forgot':
|
|
||||||
case 'admin-login-reset':
|
|
||||||
return static function(array $data, array $files) {};
|
|
||||||
case 'admin-login-register':
|
|
||||||
return function(array $data, array $files) {
|
|
||||||
$this->doRegistration($data, $files);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \RuntimeException('Unknown form');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by registration form when calling handleRequest().
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @param array $files
|
|
||||||
*/
|
|
||||||
private function doRegistration(array $data, array $files): void
|
|
||||||
{
|
|
||||||
if (Admin::doAnyUsersExist()) {
|
|
||||||
throw new \RuntimeException('A user account already exists, please create an admin account manually.', 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$login = $this->getLogin();
|
|
||||||
if (!$login) {
|
|
||||||
throw new \RuntimeException($this->grav['language']->translate('PLUGIN_LOGIN.PLUGIN_LOGIN_DISABLED', 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['title'] = $data['title'] ?? 'Administrator';
|
|
||||||
|
|
||||||
// Do not allow form to set the following fields (make super user):
|
|
||||||
$data['state'] = 'enabled';
|
|
||||||
$data['access'] = ['admin' => ['login' => true, 'super' => true], 'site' => ['login' => true]];
|
|
||||||
unset($data['groups']);
|
|
||||||
|
|
||||||
// Create user.
|
|
||||||
$user = $login->register($data, $files);
|
|
||||||
|
|
||||||
// Log in the new super admin user.
|
|
||||||
unset($this->grav['user']);
|
|
||||||
$this->grav['user'] = $user;
|
|
||||||
$this->grav['session']->user = $user;
|
|
||||||
$user->authenticated = true;
|
|
||||||
$user->authorized = $user->authorize('admin.login') ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Login
|
|
||||||
*/
|
|
||||||
private function getLogin(): Login
|
|
||||||
{
|
|
||||||
return $this->grav['login'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Email
|
|
||||||
*/
|
|
||||||
private function getEmail(): Email
|
|
||||||
{
|
|
||||||
return $this->grav['Email'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return UserCollectionInterface
|
|
||||||
*/
|
|
||||||
private function getAccounts(): UserCollectionInterface
|
|
||||||
{
|
|
||||||
return $this->grav['accounts'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,442 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use Grav\Common\Cache;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\GPM\GPM as GravGPM;
|
|
||||||
use Grav\Common\GPM\Licenses;
|
|
||||||
use Grav\Common\GPM\Installer;
|
|
||||||
use Grav\Common\GPM\Upgrader;
|
|
||||||
use Grav\Common\HTTP\Response;
|
|
||||||
use Grav\Common\Filesystem\Folder;
|
|
||||||
use Grav\Common\GPM\Common\Package;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Gpm
|
|
||||||
*
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*/
|
|
||||||
class Gpm
|
|
||||||
{
|
|
||||||
// Probably should move this to Grav DI container?
|
|
||||||
/** @var GravGPM */
|
|
||||||
protected static $GPM;
|
|
||||||
|
|
||||||
public static function GPM()
|
|
||||||
{
|
|
||||||
if (!static::$GPM) {
|
|
||||||
static::$GPM = new GravGPM();
|
|
||||||
}
|
|
||||||
|
|
||||||
return static::$GPM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default options for the install
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $options = [
|
|
||||||
'destination' => GRAV_ROOT,
|
|
||||||
'overwrite' => true,
|
|
||||||
'ignore_symlinks' => true,
|
|
||||||
'skip_invalid' => true,
|
|
||||||
'install_deps' => true,
|
|
||||||
'theme' => false
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Package[]|string[]|string $packages
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* @return string|bool
|
|
||||||
*/
|
|
||||||
public static function install($packages, array $options)
|
|
||||||
{
|
|
||||||
$options = array_merge(self::$options, $options);
|
|
||||||
|
|
||||||
if (!Installer::isGravInstance($options['destination']) || !Installer::isValidDestination($options['destination'],
|
|
||||||
[Installer::EXISTS, Installer::IS_LINK])
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$packages = is_array($packages) ? $packages : [$packages];
|
|
||||||
$count = count($packages);
|
|
||||||
|
|
||||||
$packages = array_filter(array_map(function ($p) {
|
|
||||||
return !is_string($p) ? $p instanceof Package ? $p : false : self::GPM()->findPackage($p);
|
|
||||||
}, $packages));
|
|
||||||
|
|
||||||
if (!$options['skip_invalid'] && $count !== count($packages)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$messages = '';
|
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
|
||||||
if (isset($package->dependencies) && $options['install_deps']) {
|
|
||||||
$result = static::install($package->dependencies, $options);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check destination
|
|
||||||
Installer::isValidDestination($options['destination'] . DS . $package->install_path);
|
|
||||||
|
|
||||||
if (!$options['overwrite'] && Installer::lastErrorCode() === Installer::EXISTS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$license = Licenses::get($package->slug);
|
|
||||||
$local = static::download($package, $license);
|
|
||||||
|
|
||||||
Installer::install($local, $options['destination'],
|
|
||||||
['install_path' => $package->install_path, 'theme' => $options['theme']]);
|
|
||||||
Folder::delete(dirname($local));
|
|
||||||
|
|
||||||
$errorCode = Installer::lastErrorCode();
|
|
||||||
if ($errorCode) {
|
|
||||||
$msg = Installer::lastErrorMsg();
|
|
||||||
throw new \RuntimeException($msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($packages) === 1) {
|
|
||||||
$message = Installer::getMessage();
|
|
||||||
if ($message) {
|
|
||||||
return $message;
|
|
||||||
}
|
|
||||||
|
|
||||||
$messages .= $message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cache::clearCache();
|
|
||||||
|
|
||||||
return $messages ?: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Package[]|string[]|string $packages
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* @return string|bool
|
|
||||||
*/
|
|
||||||
public static function update($packages, array $options)
|
|
||||||
{
|
|
||||||
$options['overwrite'] = true;
|
|
||||||
|
|
||||||
return static::install($packages, $options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Package[]|string[]|string $packages
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* @return string|bool
|
|
||||||
*/
|
|
||||||
public static function uninstall($packages, array $options)
|
|
||||||
{
|
|
||||||
$options = array_merge(self::$options, $options);
|
|
||||||
|
|
||||||
$packages = (array)$packages;
|
|
||||||
$count = count($packages);
|
|
||||||
|
|
||||||
$packages = array_filter(array_map(function ($p) {
|
|
||||||
|
|
||||||
if (is_string($p)) {
|
|
||||||
$p = strtolower($p);
|
|
||||||
$plugin = static::GPM()->getInstalledPlugin($p);
|
|
||||||
$p = $plugin ?: static::GPM()->getInstalledTheme($p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $p instanceof Package ? $p : false;
|
|
||||||
|
|
||||||
}, $packages));
|
|
||||||
|
|
||||||
if (!$options['skip_invalid'] && $count !== count($packages)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
|
||||||
|
|
||||||
$location = Grav::instance()['locator']->findResource($package->package_type . '://' . $package->slug);
|
|
||||||
|
|
||||||
// Check destination
|
|
||||||
Installer::isValidDestination($location);
|
|
||||||
|
|
||||||
if (!$options['ignore_symlinks'] && Installer::lastErrorCode() === Installer::IS_LINK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Installer::uninstall($location);
|
|
||||||
|
|
||||||
$errorCode = Installer::lastErrorCode();
|
|
||||||
if ($errorCode && $errorCode !== Installer::IS_LINK && $errorCode !== Installer::EXISTS) {
|
|
||||||
$msg = Installer::lastErrorMsg();
|
|
||||||
throw new \RuntimeException($msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($packages) === 1) {
|
|
||||||
$message = Installer::getMessage();
|
|
||||||
if ($message) {
|
|
||||||
return $message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cache::clearCache();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct install a file
|
|
||||||
*
|
|
||||||
* @param string $package_file
|
|
||||||
*
|
|
||||||
* @return string|bool
|
|
||||||
*/
|
|
||||||
public static function directInstall($package_file)
|
|
||||||
{
|
|
||||||
if (!$package_file) {
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.NO_PACKAGE_NAME');
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
|
|
||||||
$tmp_zip = $tmp_dir . '/Grav-' . uniqid('', false);
|
|
||||||
|
|
||||||
if (Response::isRemote($package_file)) {
|
|
||||||
$zip = GravGPM::downloadPackage($package_file, $tmp_zip);
|
|
||||||
} else {
|
|
||||||
$zip = GravGPM::copyPackage($package_file, $tmp_zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_exists($zip)) {
|
|
||||||
$tmp_source = $tmp_dir . '/Grav-' . uniqid('', false);
|
|
||||||
$extracted = Installer::unZip($zip, $tmp_source);
|
|
||||||
|
|
||||||
if (!$extracted) {
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.PACKAGE_EXTRACTION_FAILED');
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = GravGPM::getPackageType($extracted);
|
|
||||||
|
|
||||||
if (!$type) {
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.NOT_VALID_GRAV_PACKAGE');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($type === 'grav') {
|
|
||||||
Installer::isValidDestination(GRAV_ROOT . '/system');
|
|
||||||
if (Installer::IS_LINK === Installer::lastErrorCode()) {
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS');
|
|
||||||
}
|
|
||||||
|
|
||||||
static::upgradeGrav($zip, $extracted);
|
|
||||||
} else {
|
|
||||||
$name = GravGPM::getPackageName($extracted);
|
|
||||||
|
|
||||||
if (!$name) {
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.NAME_COULD_NOT_BE_DETERMINED');
|
|
||||||
}
|
|
||||||
|
|
||||||
$install_path = GravGPM::getInstallPath($type, $name);
|
|
||||||
$is_update = file_exists($install_path);
|
|
||||||
|
|
||||||
Installer::isValidDestination(GRAV_ROOT . DS . $install_path);
|
|
||||||
if (Installer::lastErrorCode() === Installer::IS_LINK) {
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.CANNOT_OVERWRITE_SYMLINKS');
|
|
||||||
}
|
|
||||||
|
|
||||||
Installer::install($zip, GRAV_ROOT,
|
|
||||||
['install_path' => $install_path, 'theme' => $type === 'theme', 'is_update' => $is_update],
|
|
||||||
$extracted);
|
|
||||||
}
|
|
||||||
|
|
||||||
Folder::delete($tmp_source);
|
|
||||||
|
|
||||||
if (Installer::lastErrorCode()) {
|
|
||||||
return Installer::lastErrorMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return Admin::translate('PLUGIN_ADMIN.ZIP_PACKAGE_NOT_FOUND');
|
|
||||||
}
|
|
||||||
|
|
||||||
Folder::delete($tmp_zip);
|
|
||||||
Cache::clearCache();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Package $package
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function download(Package $package, $license = null)
|
|
||||||
{
|
|
||||||
$query = '';
|
|
||||||
|
|
||||||
if ($package->premium) {
|
|
||||||
$query = \json_encode(array_merge($package->premium, [
|
|
||||||
'slug' => $package->slug,
|
|
||||||
'license_key' => $license,
|
|
||||||
'sid' => md5(GRAV_ROOT)
|
|
||||||
]));
|
|
||||||
|
|
||||||
$query = '?d=' . base64_encode($query);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$contents = Response::get($package->zipball_url . $query, []);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
throw new \RuntimeException($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmp_dir = Admin::getTempDir() . '/Grav-' . uniqid('', false);
|
|
||||||
Folder::mkdir($tmp_dir);
|
|
||||||
|
|
||||||
$bad_chars = array_merge(array_map('chr', range(0, 31)), ['<', '>', ':', '"', '/', '\\', '|', '?', '*']);
|
|
||||||
|
|
||||||
$filename = $package->slug . str_replace($bad_chars, '', \Grav\Common\Utils::basename($package->zipball_url));
|
|
||||||
$filename = preg_replace('/[\\\\\/:"*?&<>|]+/m', '-', $filename);
|
|
||||||
|
|
||||||
file_put_contents($tmp_dir . DS . $filename . '.zip', $contents);
|
|
||||||
|
|
||||||
return $tmp_dir . DS . $filename . '.zip';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $package
|
|
||||||
* @param string $tmp
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function _downloadSelfupgrade(array $package, $tmp)
|
|
||||||
{
|
|
||||||
$output = Response::get($package['download'], []);
|
|
||||||
Folder::mkdir($tmp);
|
|
||||||
file_put_contents($tmp . DS . $package['name'], $output);
|
|
||||||
|
|
||||||
return $tmp . DS . $package['name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function selfupgrade()
|
|
||||||
{
|
|
||||||
$upgrader = new Upgrader();
|
|
||||||
|
|
||||||
if (!Installer::isGravInstance(GRAV_ROOT)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_link(GRAV_ROOT . DS . 'index.php')) {
|
|
||||||
Installer::setError(Installer::IS_LINK);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method_exists($upgrader, 'meetsRequirements') &&
|
|
||||||
method_exists($upgrader, 'minPHPVersion') &&
|
|
||||||
!$upgrader->meetsRequirements()) {
|
|
||||||
$error = [];
|
|
||||||
$error[] = '<p>Grav has increased the minimum PHP requirement.<br />';
|
|
||||||
$error[] = 'You are currently running PHP <strong>' . phpversion() . '</strong>';
|
|
||||||
$error[] = ', but PHP <strong>' . $upgrader->minPHPVersion() . '</strong> is required.</p>';
|
|
||||||
$error[] = '<p><a href="https://getgrav.org/blog/changing-php-requirements-to-5.5" class="button button-small secondary">Additional information</a></p>';
|
|
||||||
|
|
||||||
Installer::setError(implode("\n", $error));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$update = $upgrader->getAssets()['grav-update'];
|
|
||||||
$tmp = Admin::getTempDir() . '/Grav-' . uniqid('', false);
|
|
||||||
if ($tmp) {
|
|
||||||
$file = self::_downloadSelfupgrade($update, $tmp);
|
|
||||||
$folder = Installer::unZip($file, $tmp . '/zip');
|
|
||||||
$keepFolder = false;
|
|
||||||
} else {
|
|
||||||
// If you make $tmp empty, you can install your local copy of Grav (for testing purposes only).
|
|
||||||
$file = 'grav.zip';
|
|
||||||
$folder = '~/phpstorm/grav-clones/grav';
|
|
||||||
//$folder = '/home/matias/phpstorm/rockettheme/grav-devtools/grav-clones/grav';
|
|
||||||
$keepFolder = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static::upgradeGrav($file, $folder, $keepFolder);
|
|
||||||
|
|
||||||
$errorCode = Installer::lastErrorCode();
|
|
||||||
|
|
||||||
if ($tmp) {
|
|
||||||
Folder::delete($tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !(is_string($errorCode) || ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function upgradeGrav($zip, $folder, $keepFolder = false)
|
|
||||||
{
|
|
||||||
static $ignores = [
|
|
||||||
'backup',
|
|
||||||
'cache',
|
|
||||||
'images',
|
|
||||||
'logs',
|
|
||||||
'tmp',
|
|
||||||
'user',
|
|
||||||
'.htaccess',
|
|
||||||
'robots.txt'
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!is_dir($folder)) {
|
|
||||||
Installer::setError('Invalid source folder');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$script = $folder . '/system/install.php';
|
|
||||||
/** Install $installer */
|
|
||||||
if ((file_exists($script) && $install = include $script) && is_callable($install)) {
|
|
||||||
$install($zip);
|
|
||||||
} else {
|
|
||||||
Installer::install(
|
|
||||||
$zip,
|
|
||||||
GRAV_ROOT,
|
|
||||||
['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true, 'ignores' => $ignores],
|
|
||||||
$folder,
|
|
||||||
$keepFolder
|
|
||||||
);
|
|
||||||
|
|
||||||
Cache::clearCache();
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Installer::setError($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use Grav\Common\Config\Config;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Page\Interfaces\PageInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Popularity
|
|
||||||
* @package Grav\Plugin
|
|
||||||
*/
|
|
||||||
class Popularity
|
|
||||||
{
|
|
||||||
/** @var Config */
|
|
||||||
protected $config;
|
|
||||||
protected $data_path;
|
|
||||||
|
|
||||||
protected $daily_file;
|
|
||||||
protected $monthly_file;
|
|
||||||
protected $totals_file;
|
|
||||||
protected $visitors_file;
|
|
||||||
|
|
||||||
protected $daily_data;
|
|
||||||
protected $monthly_data;
|
|
||||||
protected $totals_data;
|
|
||||||
protected $visitors_data;
|
|
||||||
|
|
||||||
const DAILY_FORMAT = 'd-m-Y';
|
|
||||||
const MONTHLY_FORMAT = 'm-Y';
|
|
||||||
const DAILY_FILE = 'daily.json';
|
|
||||||
const MONTHLY_FILE = 'monthly.json';
|
|
||||||
const TOTALS_FILE = 'totals.json';
|
|
||||||
const VISITORS_FILE = 'visitors.json';
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->config = Grav::instance()['config'];
|
|
||||||
|
|
||||||
$this->data_path = Grav::instance()['locator']->findResource('log://popularity', true, true);
|
|
||||||
$this->daily_file = $this->data_path . '/' . self::DAILY_FILE;
|
|
||||||
$this->monthly_file = $this->data_path . '/' . self::MONTHLY_FILE;
|
|
||||||
$this->totals_file = $this->data_path . '/' . self::TOTALS_FILE;
|
|
||||||
$this->visitors_file = $this->data_path . '/' . self::VISITORS_FILE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function trackHit()
|
|
||||||
{
|
|
||||||
// Don't track bot or crawler requests
|
|
||||||
if (!Grav::instance()['browser']->isHuman()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respect visitors "do not track" setting
|
|
||||||
if (!Grav::instance()['browser']->isTrackable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var PageInterface $page */
|
|
||||||
$page = Grav::instance()['page'];
|
|
||||||
$relative_url = str_replace(Grav::instance()['base_url_relative'], '', $page->url());
|
|
||||||
|
|
||||||
// Don't track error pages or pages that have no route
|
|
||||||
if ($page->template() === 'error' || !$page->route()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure no 'widcard-style' ignore matches this url
|
|
||||||
foreach ((array)$this->config->get('plugins.admin.popularity.ignore') as $ignore) {
|
|
||||||
if (fnmatch($ignore, $relative_url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initial creation if it doesn't exist
|
|
||||||
if (!file_exists($this->data_path)) {
|
|
||||||
mkdir($this->data_path);
|
|
||||||
$this->flushPopularity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the data we want to track
|
|
||||||
$this->updateDaily();
|
|
||||||
$this->updateMonthly();
|
|
||||||
$this->updateTotals($page->route());
|
|
||||||
$this->updateVisitors(Grav::instance()['uri']->ip());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function updateDaily()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!$this->daily_data) {
|
|
||||||
$this->daily_data = $this->getData($this->daily_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
$day_month_year = date(self::DAILY_FORMAT);
|
|
||||||
|
|
||||||
// get the daily access count
|
|
||||||
if (array_key_exists($day_month_year, $this->daily_data)) {
|
|
||||||
$this->daily_data[$day_month_year] = (int)$this->daily_data[$day_month_year] + 1;
|
|
||||||
} else {
|
|
||||||
$this->daily_data[$day_month_year] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep correct number as set by history
|
|
||||||
$count = (int)$this->config->get('plugins.admin.popularity.history.daily', 30);
|
|
||||||
$total = count($this->daily_data);
|
|
||||||
|
|
||||||
if ($total > $count) {
|
|
||||||
$this->daily_data = array_slice($this->daily_data, -$count, $count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
file_put_contents($this->daily_file, json_encode($this->daily_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getDailyChartData()
|
|
||||||
{
|
|
||||||
if (!$this->daily_data) {
|
|
||||||
$this->daily_data = $this->getData($this->daily_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
$limit = (int)$this->config->get('plugins.admin.popularity.dashboard.days_of_stats', 7);
|
|
||||||
$chart_data = array_slice($this->daily_data, -$limit, $limit);
|
|
||||||
|
|
||||||
$labels = [];
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
/** @var Admin $admin */
|
|
||||||
$admin = Grav::instance()['admin'];
|
|
||||||
foreach ($chart_data as $date => $count) {
|
|
||||||
$labels[] = $admin::translate([
|
|
||||||
'PLUGIN_ADMIN.' . strtoupper(date('D', strtotime($date)))]) .
|
|
||||||
'<br>' . date('M d', strtotime($date));
|
|
||||||
$data[] = $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['labels' => $labels, 'data' => $data];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getDailyTotal()
|
|
||||||
{
|
|
||||||
if (!$this->daily_data) {
|
|
||||||
$this->daily_data = $this->getData($this->daily_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($this->daily_data[date(self::DAILY_FORMAT)])) {
|
|
||||||
return $this->daily_data[date(self::DAILY_FORMAT)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getWeeklyTotal()
|
|
||||||
{
|
|
||||||
if (!$this->daily_data) {
|
|
||||||
$this->daily_data = $this->getData($this->daily_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
$day = 0;
|
|
||||||
$total = 0;
|
|
||||||
foreach (array_reverse($this->daily_data) as $daily) {
|
|
||||||
$total += $daily;
|
|
||||||
$day++;
|
|
||||||
if ($day === 7) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getMonthlyTotal()
|
|
||||||
{
|
|
||||||
if (!$this->monthly_data) {
|
|
||||||
$this->monthly_data = $this->getData($this->monthly_file);
|
|
||||||
}
|
|
||||||
if (isset($this->monthly_data[date(self::MONTHLY_FORMAT)])) {
|
|
||||||
return $this->monthly_data[date(self::MONTHLY_FORMAT)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function updateMonthly()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!$this->monthly_data) {
|
|
||||||
$this->monthly_data = $this->getData($this->monthly_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
$month_year = date(self::MONTHLY_FORMAT);
|
|
||||||
|
|
||||||
// get the monthly access count
|
|
||||||
if (array_key_exists($month_year, $this->monthly_data)) {
|
|
||||||
$this->monthly_data[$month_year] = (int)$this->monthly_data[$month_year] + 1;
|
|
||||||
} else {
|
|
||||||
$this->monthly_data[$month_year] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep correct number as set by history
|
|
||||||
$count = (int)$this->config->get('plugins.admin.popularity.history.monthly', 12);
|
|
||||||
$total = count($this->monthly_data);
|
|
||||||
$this->monthly_data = array_slice($this->monthly_data, $total - $count, $count);
|
|
||||||
|
|
||||||
|
|
||||||
file_put_contents($this->monthly_file, json_encode($this->monthly_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getMonthyChartData()
|
|
||||||
{
|
|
||||||
if (!$this->monthly_data) {
|
|
||||||
$this->monthly_data = $this->getData($this->monthly_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
$labels = [];
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
foreach ($this->monthly_data as $date => $count) {
|
|
||||||
$labels[] = date('M', strtotime($date));
|
|
||||||
$data[] = $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['labels' => $labels, 'data' => $data];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $url
|
|
||||||
*/
|
|
||||||
protected function updateTotals($url)
|
|
||||||
{
|
|
||||||
if (!$this->totals_data) {
|
|
||||||
$this->totals_data = $this->getData($this->totals_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the totals for this url
|
|
||||||
if (array_key_exists($url, $this->totals_data)) {
|
|
||||||
$this->totals_data[$url] = (int)$this->totals_data[$url] + 1;
|
|
||||||
} else {
|
|
||||||
$this->totals_data[$url] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_put_contents($this->totals_file, json_encode($this->totals_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $ip
|
|
||||||
*/
|
|
||||||
protected function updateVisitors($ip)
|
|
||||||
{
|
|
||||||
if (!$this->visitors_data) {
|
|
||||||
$this->visitors_data = $this->getData($this->visitors_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update with current timestamp
|
|
||||||
$this->visitors_data[hash('sha1', $ip)] = time();
|
|
||||||
$visitors = $this->visitors_data;
|
|
||||||
arsort($visitors);
|
|
||||||
|
|
||||||
$count = (int)$this->config->get('plugins.admin.popularity.history.visitors', 20);
|
|
||||||
$this->visitors_data = array_slice($visitors, 0, $count, true);
|
|
||||||
|
|
||||||
file_put_contents($this->visitors_file, json_encode($this->visitors_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getData($path)
|
|
||||||
{
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return (array)json_decode(file_get_contents($path), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function flushPopularity()
|
|
||||||
{
|
|
||||||
file_put_contents($this->daily_file, []);
|
|
||||||
file_put_contents($this->monthly_file, []);
|
|
||||||
file_put_contents($this->totals_file, []);
|
|
||||||
file_put_contents($this->visitors_file, []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Processors\ProcessorBase;
|
|
||||||
use Grav\Framework\Route\Route;
|
|
||||||
use Grav\Plugin\Admin\Routers\LoginRouter;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
|
||||||
|
|
||||||
class Router extends ProcessorBase
|
|
||||||
{
|
|
||||||
public $id = 'admin_router';
|
|
||||||
public $title = 'Admin Panel';
|
|
||||||
|
|
||||||
/** @var Admin */
|
|
||||||
protected $admin;
|
|
||||||
|
|
||||||
public function __construct(Grav $container, Admin $admin)
|
|
||||||
{
|
|
||||||
parent::__construct($container);
|
|
||||||
|
|
||||||
$this->admin = $admin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle routing to the dashboard, group and build objects.
|
|
||||||
*
|
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @param RequestHandlerInterface $handler
|
|
||||||
* @return ResponseInterface
|
|
||||||
*/
|
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
|
||||||
{
|
|
||||||
$this->startTimer();
|
|
||||||
|
|
||||||
$context = $request->getAttributes();
|
|
||||||
$query = $request->getQueryParams();
|
|
||||||
|
|
||||||
/** @var Route $route */
|
|
||||||
$route = $context['route'];
|
|
||||||
$normalized = mb_strtolower(trim($route->getRoute(), '/'));
|
|
||||||
$parts = explode('/', $normalized);
|
|
||||||
array_shift($parts); // Admin path
|
|
||||||
$routeStr = implode('/', $parts);
|
|
||||||
$view = array_shift($parts);
|
|
||||||
$path = implode('/', $parts);
|
|
||||||
$task = $this->container['task'] ?? $query['task'] ?? null;
|
|
||||||
$action = $this->container['action'] ?? $query['action'] ?? null;
|
|
||||||
|
|
||||||
$params = ['view' => $view, 'route' => $routeStr, 'path' => $path, 'parts' => $parts, 'task' => $task, 'action' => $action];
|
|
||||||
$request = $request->withAttribute('admin', $params);
|
|
||||||
|
|
||||||
// Run login controller if user isn't fully logged in or asks to logout.
|
|
||||||
$user = $this->admin->user;
|
|
||||||
if (!$user->authorized || !$user->authorize('admin.login')) {
|
|
||||||
$params = (new LoginRouter())->matchServerRequest($request);
|
|
||||||
$request = $request->withAttribute('admin', $params + $request->getAttribute('admin'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->admin->request = $request;
|
|
||||||
|
|
||||||
$response = $handler->handle($request);
|
|
||||||
|
|
||||||
$this->stopTimer();
|
|
||||||
|
|
||||||
// Never allow admin pages to be rendered in <frame>, <iframe>, <embed> or <object> for improved security.
|
|
||||||
return $response->withHeader('X-Frame-Options', 'DENY');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin\Routers;
|
|
||||||
|
|
||||||
use Grav\Plugin\Admin\Admin;
|
|
||||||
use Grav\Plugin\Admin\Controllers\Login\LoginController;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
|
|
||||||
class LoginRouter
|
|
||||||
{
|
|
||||||
/** @var string[] */
|
|
||||||
private $taskTemplates = [
|
|
||||||
'logout' => 'login',
|
|
||||||
'twofa' => 'login',
|
|
||||||
'forgot' => 'forgot',
|
|
||||||
'reset' => 'reset'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ServerRequestInterface $request
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function matchServerRequest(ServerRequestInterface $request): array
|
|
||||||
{
|
|
||||||
$adminInfo = $request->getAttribute('admin');
|
|
||||||
$task = $adminInfo['task'];
|
|
||||||
$class = LoginController::class;
|
|
||||||
|
|
||||||
// Special controller for the new sites.
|
|
||||||
if (!Admin::doAnyUsersExist()) {
|
|
||||||
$method = $task === 'register' ? 'taskRegister' : 'displayRegister';
|
|
||||||
|
|
||||||
return [
|
|
||||||
'controller' => [
|
|
||||||
'class' => $class,
|
|
||||||
'method' => $method,
|
|
||||||
'params' => []
|
|
||||||
],
|
|
||||||
'template' => 'register',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$httpMethod = $request->getMethod() ?? '';
|
|
||||||
$template = $this->taskTemplates[$task ?? ''] ?? $adminInfo['view'];
|
|
||||||
|
|
||||||
$params = [];
|
|
||||||
|
|
||||||
switch ($template) {
|
|
||||||
case 'forgot':
|
|
||||||
break;
|
|
||||||
case 'reset':
|
|
||||||
$path = $adminInfo['path'];
|
|
||||||
if (str_starts_with($path, 'u/')) {
|
|
||||||
// Path is 'u/username/token'
|
|
||||||
$parts = explode('/', $path, 4);
|
|
||||||
$user = $parts[1] ?? null;
|
|
||||||
$token = $parts[2] ?? null;
|
|
||||||
} else {
|
|
||||||
// Old path used to be 'task:reset/user:username/token:token'
|
|
||||||
if ($httpMethod === 'GET' || $httpMethod === 'HEAD') {
|
|
||||||
$task = null;
|
|
||||||
}
|
|
||||||
$route = $request->getAttribute('route');
|
|
||||||
$user = $route->getGravParam('user');
|
|
||||||
$token = $route->getGravParam('token');
|
|
||||||
}
|
|
||||||
$params = [$user, $token];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$template = 'login';
|
|
||||||
}
|
|
||||||
|
|
||||||
$method = ($task ? 'task' : 'display') . ucfirst($task ?? $template);
|
|
||||||
if (!method_exists($class, $method)) {
|
|
||||||
$method = 'displayUnauthorized';
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'controller' => [
|
|
||||||
'class' => $class,
|
|
||||||
'method' => $method,
|
|
||||||
'params' => $params
|
|
||||||
],
|
|
||||||
'template' => $template,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use ScssPhp\ScssPhp\Compiler;
|
|
||||||
use ScssPhp\ScssPhp\ValueConverter;
|
|
||||||
|
|
||||||
class ScssCompiler
|
|
||||||
{
|
|
||||||
protected $compiler;
|
|
||||||
|
|
||||||
public function compiler()
|
|
||||||
{
|
|
||||||
if ($this->compiler === null) {
|
|
||||||
$this->reset();
|
|
||||||
}
|
|
||||||
return $this->compiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function reset()
|
|
||||||
{
|
|
||||||
$this->compiler = new Compiler();
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setVariables(array $variables)
|
|
||||||
{
|
|
||||||
// $parsed = ValueConverter::fromPhp($variables);
|
|
||||||
$parsed = [];
|
|
||||||
foreach ($variables as $key => $value) {
|
|
||||||
$parsed[$key] = ValueConverter::parseValue($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->compiler()->addVariables($parsed);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setImportPaths(array $paths)
|
|
||||||
{
|
|
||||||
$this->compiler()->setImportPaths($paths);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function compile(string $input_file, string $output_file)
|
|
||||||
{
|
|
||||||
$input = file_get_contents($input_file);
|
|
||||||
$output = $this->compiler()->compileString($input)->getCss();
|
|
||||||
file_put_contents($output_file, $output);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function compileAll(array $input_paths, string $output_file)
|
|
||||||
{
|
|
||||||
$input = '';
|
|
||||||
foreach ($input_paths as $input_file) {
|
|
||||||
$input .= trim(file_get_contents($input_file)) . "\n\n";
|
|
||||||
}
|
|
||||||
$output = $this->compiler()->compileString($input)->getCss();
|
|
||||||
file_put_contents($output_file, $output);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
class ScssList
|
|
||||||
{
|
|
||||||
/** @var string[] */
|
|
||||||
protected $list = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ScssList constructor.
|
|
||||||
* @param string|null $item
|
|
||||||
*/
|
|
||||||
public function __construct($item = null)
|
|
||||||
{
|
|
||||||
if ($item) {
|
|
||||||
$this->add($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function all(): array
|
|
||||||
{
|
|
||||||
return $this->list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $item
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function add($item): void
|
|
||||||
{
|
|
||||||
if ($item) {
|
|
||||||
$this->list[] = $item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $item
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function remove($item): void
|
|
||||||
{
|
|
||||||
$pos = array_search($item, $this->list, true);
|
|
||||||
if ($pos) {
|
|
||||||
unset($this->list[$pos]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Admin theme object
|
|
||||||
*
|
|
||||||
* @author RocketTheme
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
class Themes extends \Grav\Common\Themes
|
|
||||||
{
|
|
||||||
public function init()
|
|
||||||
{
|
|
||||||
/** @var Themes $themes */
|
|
||||||
$themes = $this->grav['themes'];
|
|
||||||
$themes->configure();
|
|
||||||
$themes->initTheme();
|
|
||||||
|
|
||||||
$this->grav->fireEvent('onAdminThemeInitialized');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin\Twig;
|
|
||||||
|
|
||||||
use Grav\Common\Data\Data;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\Page\Interfaces\PageInterface;
|
|
||||||
use Grav\Common\Utils;
|
|
||||||
use Grav\Common\Yaml;
|
|
||||||
use Grav\Common\Language\Language;
|
|
||||||
use Twig\Extension\AbstractExtension;
|
|
||||||
use Twig\TwigFilter;
|
|
||||||
use Twig\TwigFunction;
|
|
||||||
use Grav\Plugin\Admin\Admin;
|
|
||||||
|
|
||||||
class AdminTwigExtension extends AbstractExtension
|
|
||||||
{
|
|
||||||
/** @var Grav */
|
|
||||||
protected $grav;
|
|
||||||
|
|
||||||
/** @var Language $lang */
|
|
||||||
protected $lang;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->grav = Grav::instance();
|
|
||||||
$this->lang = $this->grav['user']->language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFilters(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
new TwigFilter('tu', [$this, 'tuFilter']),
|
|
||||||
new TwigFilter('toYaml', [$this, 'toYamlFilter']),
|
|
||||||
new TwigFilter('fromYaml', [$this, 'fromYamlFilter']),
|
|
||||||
new TwigFilter('adminNicetime', [$this, 'adminNicetimeFilter']),
|
|
||||||
new TwigFilter('nested', [$this, 'nestedFilter']),
|
|
||||||
new TwigFilter('flatten', [$this, 'flattenFilter']),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFunctions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
new TwigFunction('admin_route', [$this, 'adminRouteFunc']),
|
|
||||||
new TwigFunction('getPageUrl', [$this, 'getPageUrl']),
|
|
||||||
new TwigFunction('clone', [$this, 'cloneFunc']),
|
|
||||||
new TwigFunction('data', [$this, 'dataFunc']),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function nestedFilter($current, $name)
|
|
||||||
{
|
|
||||||
$path = explode('.', trim($name, '.'));
|
|
||||||
|
|
||||||
foreach ($path as $field) {
|
|
||||||
if (is_object($current) && isset($current->{$field})) {
|
|
||||||
$current = $current->{$field};
|
|
||||||
} elseif (is_array($current) && isset($current[$field])) {
|
|
||||||
$current = $current[$field];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $current;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function flattenFilter($array)
|
|
||||||
{
|
|
||||||
return Utils::arrayFlattenDotNotation($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cloneFunc($obj)
|
|
||||||
{
|
|
||||||
return clone $obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function adminRouteFunc(string $route = '', ?string $languageCode = null)
|
|
||||||
{
|
|
||||||
/** @var Admin $admin */
|
|
||||||
$admin = Grav::instance()['admin'];
|
|
||||||
|
|
||||||
return $admin->getAdminRoute($route, $languageCode)->toString(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPageUrl(PageInterface $page)
|
|
||||||
{
|
|
||||||
/** @var Admin $admin */
|
|
||||||
$admin = Grav::instance()['admin'];
|
|
||||||
|
|
||||||
return $admin->getAdminRoute('/pages' . $page->rawRoute(), $page->language())->toString(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tuFilter()
|
|
||||||
{
|
|
||||||
$args = func_get_args();
|
|
||||||
$numargs = count($args);
|
|
||||||
$lang = null;
|
|
||||||
|
|
||||||
if (($numargs === 3 && is_array($args[1])) || ($numargs === 2 && !is_array($args[1]))) {
|
|
||||||
$lang = array_pop($args);
|
|
||||||
} elseif ($numargs === 2 && is_array($args[1])) {
|
|
||||||
$subs = array_pop($args);
|
|
||||||
$args = array_merge($args, $subs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Grav::instance()['admin']->translate($args, $lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toYamlFilter($value, $inline = null)
|
|
||||||
{
|
|
||||||
return Yaml::dump($value, $inline);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fromYamlFilter($value)
|
|
||||||
{
|
|
||||||
return Yaml::parse($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function adminNicetimeFilter($date, $long_strings = true)
|
|
||||||
{
|
|
||||||
return Grav::instance()['admin']->adminNiceTime($date, $long_strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dataFunc(array $data, $blueprints = null)
|
|
||||||
{
|
|
||||||
return new Data($data, $blueprints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Common\User\Interfaces\UserCollectionInterface;
|
|
||||||
use Grav\Common\User\Interfaces\UserInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Admin utils class
|
|
||||||
*
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
class Utils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Matches an email to a user
|
|
||||||
*
|
|
||||||
* @param string $email
|
|
||||||
*
|
|
||||||
* @return UserInterface
|
|
||||||
*/
|
|
||||||
public static function findUserByEmail(string $email)
|
|
||||||
{
|
|
||||||
$grav = Grav::instance();
|
|
||||||
|
|
||||||
/** @var UserCollectionInterface $users */
|
|
||||||
$users = $grav['accounts'];
|
|
||||||
|
|
||||||
return $users->find($email, ['email']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a slug of the given string
|
|
||||||
*
|
|
||||||
* @param string $str
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function slug(string $str)
|
|
||||||
{
|
|
||||||
if (function_exists('transliterator_transliterate')) {
|
|
||||||
$str = transliterator_transliterate('Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC; [:Punctuation:] Remove;', $str);
|
|
||||||
} else {
|
|
||||||
$str = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
$str = strtolower($str);
|
|
||||||
$str = preg_replace('/[-\s]+/', '-', $str);
|
|
||||||
$str = preg_replace('/[^a-z0-9-]/i', '', $str);
|
|
||||||
$str = trim($str, '-');
|
|
||||||
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Grav\Plugin\Admin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Grav\Plugin\Admin
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
|
|
||||||
* @license MIT License; see LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use Grav\Common\Filesystem\Folder;
|
|
||||||
use Grav\Common\Grav;
|
|
||||||
use Grav\Framework\File\File;
|
|
||||||
use RocketTheme\Toolbox\Event\Event;
|
|
||||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class WhiteLabel
|
|
||||||
{
|
|
||||||
protected $grav;
|
|
||||||
protected $scss;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->grav = Grav::instance();
|
|
||||||
// ScssCompiler is now lazy-loaded to avoid loading scssphp classes until actually needed
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the ScssCompiler instance (lazy-loaded)
|
|
||||||
*
|
|
||||||
* @return ScssCompiler
|
|
||||||
*/
|
|
||||||
protected function getScss(): ScssCompiler
|
|
||||||
{
|
|
||||||
if ($this->scss === null) {
|
|
||||||
$this->scss = new ScssCompiler();
|
|
||||||
}
|
|
||||||
return $this->scss;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function compilePresetScss($config, $options = [
|
|
||||||
'input' => 'plugin://admin/themes/grav/scss/preset.scss',
|
|
||||||
'output' => 'asset://admin-preset.css'
|
|
||||||
])
|
|
||||||
{
|
|
||||||
if (is_array($config)) {
|
|
||||||
$color_scheme = $config['color_scheme'];
|
|
||||||
} else {
|
|
||||||
$color_scheme = $config->get('whitelabel.color_scheme');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($color_scheme) {
|
|
||||||
/** @var UniformResourceLocator $locator */
|
|
||||||
$locator = $this->grav['locator'];
|
|
||||||
|
|
||||||
// Use ScssList object to make it easier ot handle in event
|
|
||||||
$scss_list = new ScssList($locator->findResource($options['input']));
|
|
||||||
$output_css = $locator->findResource(($options['output']), true, true);
|
|
||||||
|
|
||||||
Folder::create(dirname($output_css));
|
|
||||||
|
|
||||||
Grav::instance()->fireEvent('onAdminCompilePresetSCSS', new Event(['scss' => $scss_list]));
|
|
||||||
|
|
||||||
// Convert bak to regular array now we have run the event
|
|
||||||
$input_scss = $scss_list->all();
|
|
||||||
|
|
||||||
$imports = [$locator->findResource('plugin://admin/themes/grav/scss')];
|
|
||||||
foreach ($input_scss as $scss) {
|
|
||||||
$input_path = dirname($scss);
|
|
||||||
if (!in_array($input_path, $imports)) {
|
|
||||||
$imports[] = $input_path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$compiler = $this->getScss()->reset();
|
|
||||||
|
|
||||||
$compiler->setVariables($color_scheme['colors'] + $color_scheme['accents']);
|
|
||||||
$compiler->setImportPaths($imports);
|
|
||||||
$compiler->compileAll($input_scss, $output_css);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return [false, $e->getMessage()];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return [true, 'Recompiled successfully'];
|
|
||||||
|
|
||||||
}
|
|
||||||
return [false, ' Could not be recompiled, missing color scheme...'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function exportPresetScsss($config, $location = 'asset://admin-theme-export.yaml')
|
|
||||||
{
|
|
||||||
|
|
||||||
if (isset($config['color_scheme'])) {
|
|
||||||
|
|
||||||
$color_scheme = $config['color_scheme'];
|
|
||||||
|
|
||||||
$body = Yaml::dump($color_scheme);
|
|
||||||
|
|
||||||
$file = new File($location);
|
|
||||||
$file->save($body);
|
|
||||||
// todo: handle errors/exceptions?
|
|
||||||
|
|
||||||
return [true, 'File created successfully'];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return [false, ' Could not export, missing color scheme...'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
actor: Tester
|
|
||||||
paths:
|
|
||||||
tests: tests
|
|
||||||
log: tests/_output
|
|
||||||
data: tests/_data
|
|
||||||
support: tests/_support
|
|
||||||
envs: tests/_envs
|
|
||||||
settings:
|
|
||||||
bootstrap: _bootstrap.php
|
|
||||||
colors: true
|
|
||||||
memory_limit: 1024M
|
|
||||||
extensions:
|
|
||||||
enabled:
|
|
||||||
- Codeception\Extension\RunFailed
|
|
||||||
# - Codeception\Extension\Recorder
|
|
||||||
|
|
||||||
modules:
|
|
||||||
config:
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "getgrav/grav-plugin-admin",
|
|
||||||
"type": "grav-plugin",
|
|
||||||
"description": "Admin plugin for Grav CMS",
|
|
||||||
"keywords": ["admin", "plugin", "manager", "panel"],
|
|
||||||
"homepage": "https://github.com/getgrav/grav-plugin-admin",
|
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Team Grav",
|
|
||||||
"email": "devs@getgrav.org",
|
|
||||||
"homepage": "https://getgrav.org",
|
|
||||||
"role": "Developer"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/getgrav/grav-plugin-admin/issues",
|
|
||||||
"irc": "https://chat.getgrav.org",
|
|
||||||
"forum": "https://discourse.getgrav.org",
|
|
||||||
"docs": "https://github.com/getgrav/grav-plugin-admin/blob/master/README.md"
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^8.3",
|
|
||||||
"ext-json": "*",
|
|
||||||
"scssphp/scssphp": "^2.0",
|
|
||||||
"p3k/picofeed": "^1.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"codeception/codeception": "^5.0",
|
|
||||||
"fakerphp/faker": "^1.23",
|
|
||||||
"symfony/yaml": "^6.4 || ^7.0",
|
|
||||||
"symfony/console": "^6.4 || ^7.0",
|
|
||||||
"symfony/finder": "^6.4 || ^7.0",
|
|
||||||
"symfony/event-dispatcher": "^6.4 || ^7.0"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Grav\\Plugin\\Admin\\": "classes/plugin"
|
|
||||||
},
|
|
||||||
"classmap": [
|
|
||||||
"admin.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"platform": {
|
|
||||||
"php": "8.3.0"
|
|
||||||
},
|
|
||||||
"allow-plugins": {
|
|
||||||
"phpstan/extension-installer": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "vendor/bin/codecept run unit",
|
|
||||||
"test-windows": "vendor\\bin\\codecept run unit"
|
|
||||||
},
|
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "vcs",
|
|
||||||
"url": "https://github.com/rhukster/picoFeed"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Generated
-4004
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"project":"grav-plugin-admin",
|
|
||||||
"platforms":{
|
|
||||||
"grav":{
|
|
||||||
"nodes":{
|
|
||||||
"plugin":[
|
|
||||||
{
|
|
||||||
"source":"/",
|
|
||||||
"destination":"/user/plugins/admin"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
ADMIN_NOSCRIPT_MSG: "يرجى تفعيل جافا سكريبت في المتصفح الخاص بك."
|
|
||||||
ADMIN_BETA_MSG: "هذا إصدار بيتا! استخدم هذا في الإنتاج على مسؤوليتك الخاصة..."
|
|
||||||
ADMIN_REPORT_ISSUE: "وجدت مشكلة؟ الرجاء الإبلاغ عن GitHub."
|
|
||||||
EMAIL_FOOTER: "<a href=\"https://getgrav.org\">الموقع مدعوم من Grav</a> - نظام إدارة الملفات الحديثة"
|
|
||||||
LOGIN_BTN: "تسجل الدخول"
|
|
||||||
LOGIN_BTN_FORGOT: "نسيت"
|
|
||||||
LOGIN_BTN_RESET: "إعادة تعيين كلمة المرور"
|
|
||||||
LOGIN_BTN_SEND_INSTRUCTIONS: "إرسال إرشادات إعادة تعيين"
|
|
||||||
LOGIN_BTN_CLEAR: "مسح النموذج"
|
|
||||||
LOGIN_BTN_CREATE_USER: "أنشاء مستخدم جديد"
|
|
||||||
LOGIN_LOGGED_IN: "لقد تم تسجيل بنجاح"
|
|
||||||
LOGIN_FAILED: "فشل تسجيل الخول"
|
|
||||||
LOGGED_OUT: "لقد قمت بتسجيل الخروج"
|
|
||||||
RESET_NEW_PASSWORD: "إدخال كلمة سر جديدة رجاءً …"
|
|
||||||
RESET_LINK_EXPIRED: "انتهت مدة صلاحية إعادة الارتباط، الرجاء المحاولة مرة أخرى"
|
|
||||||
RESET_PASSWORD_RESET: "لقد تم إعادة تعيين كلمة المرور"
|
|
||||||
RESET_INVALID_LINK: "اللينك خاطئ ، الرجاء المحاولة مرة أخرى"
|
|
||||||
FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "تم إرسال إرشادات إعادة تعيين كلمة المرور الخاصة بك عبر البريد الإلكتروني إلى %s"
|
|
||||||
FORGOT_FAILED_TO_EMAIL: "فشل في تعليمات البريد الإلكتروني، الرجاء المحاولة مرة أخرى لاحقاً"
|
|
||||||
FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "لا يمكن إعادة تعيين كلمة المرور ل %s، لم يتم تعيين عنوان البريد الإلكتروني"
|
|
||||||
FORGOT_USERNAME_DOES_NOT_EXIST: "لا يوجد المستخدم مع اسم المستخدم <b>%s</b>"
|
|
||||||
FORGOT_EMAIL_NOT_CONFIGURED: "لا يمكن إعادة تعيين كلمة المرور. لم يتم تكوين هذا الموقع لإرسال رسائل البريد الإلكتروني"
|
|
||||||
FORGOT_EMAIL_SUBJECT: "طلب إعادة تعيين كلمة المرور %s"
|
|
||||||
FORGOT_EMAIL_BODY: "<h1>\"إعادة تعيين كلمة المرور\"</h1><p>عزيزي %1$s،</p><p>طلبا قدم في <b>%4$s</b> لإعادة تعيين كلمة المرور الخاصة بك.</p><p><br /><a href=\"%2$s\" class=\"btn-primary\">انقر فوق هذا الخيار لإعادة تعيين الخاص بك كلمة مرور</a><br /><br /></p><p>بدلاً من ذلك، نسخ عنوان URL التالي في شريط العناوين في المستعرض الخاص بك:</p> <p>%2$s</p><p><br />أطيب التحيات،<br /><br />%3$s</p>"
|
|
||||||
MANAGE_PAGES: "إدارة الصفحات"
|
|
||||||
PAGES: "الصفحات"
|
|
||||||
PLUGINS: "الملحقات"
|
|
||||||
PLUGIN: "البرنامج الإضافي"
|
|
||||||
THEMES: "المواضيع"
|
|
||||||
LOGOUT: "تسجيل الخروج"
|
|
||||||
BACK: "الرجوع"
|
|
||||||
NEXT: "التالي"
|
|
||||||
PREVIOUS: "السابق"
|
|
||||||
ADD_PAGE: "إضافة صفحة"
|
|
||||||
MOVE: "انقل"
|
|
||||||
DELETE: "حذف"
|
|
||||||
UNSET: "تراجع عن التعيين"
|
|
||||||
VIEW: "عرض"
|
|
||||||
SAVE: "حفظ"
|
|
||||||
NORMAL: "عادي"
|
|
||||||
EXPERT: "خبير"
|
|
||||||
EXPAND_ALL: "عرض الكل"
|
|
||||||
COLLAPSE_ALL: "طي الكل"
|
|
||||||
ERROR: "خطأ"
|
|
||||||
CLOSE: "أغلق"
|
|
||||||
CANCEL: "إلغاء"
|
|
||||||
CONTINUE: "المتابعة"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "التأكيد مطلوب"
|
|
||||||
MODAL_CHANGED_DETECTED_TITLE: "تم الكشف عن التغييرات"
|
|
||||||
MODAL_CHANGED_DETECTED_DESC: "وقد تغييرات غير محفوظة. هل أنت متأكد من أنك تريد ترك دون الحفظ؟"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE: "التأكيد مطلوب"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC: "هل أنت متأكد من حذف هذا الملف؟ لا يمكن التراجع عن هذا الإجراء."
|
|
||||||
ADD_FILTERS: "إضافة عامل تصفية"
|
|
||||||
SEARCH_PAGES: "صفحات البحث"
|
|
||||||
VERSION: "النسخة"
|
|
||||||
WAS_MADE_WITH: "تم عمله مع"
|
|
||||||
BY: "بواسطة"
|
|
||||||
UPDATE_THEME: "تحديث الموضوع"
|
|
||||||
UPDATE_PLUGIN: "تحديث البرنامج الإضافي"
|
|
||||||
OF_THIS_THEME_IS_NOW_AVAILABLE: "من هذه السمة الآن متوفرة"
|
|
||||||
OF_THIS_PLUGIN_IS_NOW_AVAILABLE: "من هذه الإضافة متوفرة الآن"
|
|
||||||
AUTHOR: "المؤلّف"
|
|
||||||
HOMEPAGE: "الصفحة الرئيسية"
|
|
||||||
DEMO: "عرض تجريبي"
|
|
||||||
BUG_TRACKER: "متتبع الأخطاء"
|
|
||||||
KEYWORDS: "الكلمات الرئيسية"
|
|
||||||
LICENSE: "الرخصة"
|
|
||||||
DESCRIPTION: "الوصف"
|
|
||||||
README: "الملف التمهيدي"
|
|
||||||
REMOVE_THEME: "إزالة الموضوع"
|
|
||||||
INSTALL_THEME: "تثبيت الموضوع"
|
|
||||||
THEME: "الموضوع"
|
|
||||||
BACK_TO_THEMES: "العودة إلى المواضيع"
|
|
||||||
BACK_TO_PLUGINS: "العودة إلى البرامج الإضافية"
|
|
||||||
CHECK_FOR_UPDATES: "التحقق من وجود تحديثات"
|
|
||||||
ADD: "أَضِف"
|
|
||||||
CLEAR_CACHE: "مسح ذاكرة التخزين المؤقتة"
|
|
||||||
CLEAR_CACHE_ALL_CACHE: "كافة المحفوظات"
|
|
||||||
CLEAR_CACHE_ASSETS_ONLY: "الاصول فقط"
|
|
||||||
CLEAR_CACHE_IMAGES_ONLY: "الصور فقط"
|
|
||||||
CLEAR_CACHE_CACHE_ONLY: "المحفوظات فقط"
|
|
||||||
CLEAR_CACHE_TMP_ONLY: "المؤقتة فقط"
|
|
||||||
UPDATES_AVAILABLE: "تحديثات متوفّرة"
|
|
||||||
DAYS: "أيام"
|
|
||||||
UPDATE: "تحديث"
|
|
||||||
BACKUP: "نسخة احتياطية"
|
|
||||||
BACKUPS: "النسخ الاحتياطية"
|
|
||||||
BACKUP_NOW: "قم بحفض نسخة احتياطية"
|
|
||||||
BACKUPS_STATS: "قم بحفض نسخة احتياطية لاحصائيات"
|
|
||||||
BACKUPS_HISTORY: "قم بحفض نسخة احتياطية للسجل"
|
|
||||||
BACKUPS_PROFILES: "قم بحفض نسخة احتياطي للحسابات"
|
|
||||||
BACKUPS_COUNT: "عدد النسخ الاحتياطية"
|
|
||||||
BACKUPS_PROFILES_COUNT: "عدد الحسابات"
|
|
||||||
BACKUPS_TOTAL_SIZE: "المساحة المستعملة"
|
|
||||||
BACKUPS_NEWEST: "النسخ الاحتياطية الحديثة"
|
|
||||||
BACKUPS_OLDEST: "النسخ الاحتياطية القديمة"
|
|
||||||
BACKUPS_PURGE: "تطهير"
|
|
||||||
BACKUPS_NOT_GENERATED: "لم يتم إنشاء نسخ احتياطية بعد..."
|
|
||||||
BACKUPS_PURGE_NUMBER: "استخدام %s من %s من فتحات النسخ الاحتياطي"
|
|
||||||
BACKUPS_PURGE_TIME: "%s ايام من النسخ الاحتياطية بقية"
|
|
||||||
BACKUPS_PURGE_SPACE: "استعمال %s من %s"
|
|
||||||
BACKUP_DELETED: "تم حذف النسخة الاحتياطية بنجاح"
|
|
||||||
BACKUP_NOT_FOUND: "لم يتم العثور على نسخة احتياطية"
|
|
||||||
BACKUP_DATE: "تاريخ النسخ الاحتياطي"
|
|
||||||
STATISTICS: "إحصائيات"
|
|
||||||
TODAY: "اليوم"
|
|
||||||
WEEK: "اسبوع"
|
|
||||||
MONTH: "شهر"
|
|
||||||
LATEST_PAGE_UPDATES: "آخر التحديثات"
|
|
||||||
MAINTENANCE: "الصيانه"
|
|
||||||
UPDATED: "تم تحديثه"
|
|
||||||
MON: "الإثنين"
|
|
||||||
TUE: "الثلاثاء"
|
|
||||||
WED: "الإربعاء"
|
|
||||||
THU: "الخميس"
|
|
||||||
FRI: "الجمعة"
|
|
||||||
SAT: "السبت"
|
|
||||||
SUN: "الأحد"
|
|
||||||
COPY: "نسخ"
|
|
||||||
EDIT: "تحرير"
|
|
||||||
CREATE: "انشاء"
|
|
||||||
GRAV_ADMIN: "مدير جريف"
|
|
||||||
GRAV_OFFICIAL_PLUGIN: "اضاف رسمية ل جريف"
|
|
||||||
GRAV_OFFICIAL_THEME: "سمة جريف رسمية"
|
|
||||||
PLUGIN_SYMBOLICALLY_LINKED: "هذه الاضافه مرتبطة بمرجع. لن يام اكتشاف التحديثات."
|
|
||||||
THEME_SYMBOLICALLY_LINKED: "هذه السمة مرتبطة بمرجع. لم يتم اكتشاف التحديثات"
|
|
||||||
REMOVE_PLUGIN: "حذف الإضافة"
|
|
||||||
INSTALL_PLUGIN: "تثبيت الإضافة"
|
|
||||||
AVAILABLE: "متوفر"
|
|
||||||
INSTALLED: "مثبت"
|
|
||||||
INSTALL: "تثبيت"
|
|
||||||
ACTIVE_THEME: "سمة نشطة"
|
|
||||||
SWITCHING_TO: "التبديل إلى"
|
|
||||||
SWITCHING_TO_DESCRIPTION: "بالتبديل إلى سمة مختلفة, لايوجد أي ضمانات بأن صفحات الواجهة مدعومة, من المحتمل أن تحدث أخطاء عند محاولة تحميل الصفحات المذكورة."
|
|
||||||
SWITCHING_TO_CONFIRMATION: "هل تريد التبديل الى السمة والمتابعة"
|
|
||||||
CREATE_NEW_USER: "إنشاء مستخدم جديد"
|
|
||||||
REMOVE_USER: "حذف المستخدم"
|
|
||||||
ACCESS_DENIED: "الدخول ممنوع"
|
|
||||||
ACCOUNT_NOT_ADMIN: "لا يملك حسابك أي صلاحيات للإدارة"
|
|
||||||
PHP_INFO: "معلومات بي إش بي"
|
|
||||||
INSTALLER: "المثبت"
|
|
||||||
AVAILABLE_THEMES: "سمات متوفرة"
|
|
||||||
AVAILABLE_PLUGINS: "إضافات متوفرة"
|
|
||||||
INSTALLED_THEMES: "السمات المثبتة"
|
|
||||||
INSTALLED_PLUGINS: "الإضافات المثبتة"
|
|
||||||
BROWSE_ERROR_LOGS: "سجل أخطاء التصفح"
|
|
||||||
SITE: "موقع"
|
|
||||||
INFO: "معلومات"
|
|
||||||
SYSTEM: "النظام"
|
|
||||||
USER: "المستخدم"
|
|
||||||
ADD_ACCOUNT: "إضافة حساب"
|
|
||||||
SWITCH_LANGUAGE: "تبديل اللغة"
|
|
||||||
SUCCESSFULLY_ENABLED_PLUGIN: "تم تفعيل الإضافة بنجاح"
|
|
||||||
SUCCESSFULLY_DISABLED_PLUGIN: "تم إيقاف الإضافة بنجاح"
|
|
||||||
SUCCESSFULLY_CHANGED_THEME: "تم تبديل السمة الإفتراضية بنجاح"
|
|
||||||
INSTALLATION_FAILED: "فشل التثبيت"
|
|
||||||
INSTALLATION_SUCCESSFUL: "تم التثبيت بنجاح"
|
|
||||||
UNINSTALL_FAILED: "فشل الغاء التثبيت"
|
|
||||||
UNINSTALL_SUCCESSFUL: "تم إلغاء التثبيت بنجاح"
|
|
||||||
SUCCESSFULLY_SAVED: "حفظ بنجاح"
|
|
||||||
SUCCESSFULLY_COPIED: "نسخ بنجاح"
|
|
||||||
REORDERING_WAS_SUCCESSFUL: "إعادة ترتيب تم بنجاح"
|
|
||||||
SUCCESSFULLY_DELETED: "تم الحذف بنجاح"
|
|
||||||
SUCCESSFULLY_SWITCHED_LANGUAGE: "تم تغيير اللغة بنجاح"
|
|
||||||
INSUFFICIENT_PERMISSIONS_FOR_TASK: "لديك أذونات غير كافية للقيام بالمهمة"
|
|
||||||
CACHE_CLEARED: "تم مسح الذاكرة المؤقتة"
|
|
||||||
METHOD: "الأسلوب"
|
|
||||||
ERROR_CLEARING_CACHE: "خطأ مسح ذاكرة التخزين المؤقت"
|
|
||||||
AN_ERROR_OCCURRED: "حدث خطأ ما"
|
|
||||||
YOUR_BACKUP_IS_READY_FOR_DOWNLOAD: "النسخة الاحتياطية جاهزة للتحميل"
|
|
||||||
DOWNLOAD_BACKUP: "تنزيل النسخة الاحتياطية"
|
|
||||||
PAGES_FILTERED: "الصفحات التي تمت تصفيتها"
|
|
||||||
NO_PAGE_FOUND: "لم يتم العثور على أي صفحة"
|
|
||||||
INVALID_PARAMETERS: "متغيرات غير صالحة"
|
|
||||||
NO_FILES_SENT: "لا توجد ملفات أرسلت حتى الآن"
|
|
||||||
EXCEEDED_FILESIZE_LIMIT: "تجاوز الحد الأقصى لحجم ملف التكوين بي إتش بي"
|
|
||||||
UNKNOWN_ERRORS: "خطأ غير معروف"
|
|
||||||
EXCEEDED_GRAV_FILESIZE_LIMIT: "تجاوز الحد الأقصى لحجم ملف التكوين بي إتش بي"
|
|
||||||
UNSUPPORTED_FILE_TYPE: "نوع ملف غير معتمد"
|
|
||||||
FAILED_TO_MOVE_UPLOADED_FILE: "فشل في تحميل الملف"
|
|
||||||
FILE_UPLOADED_SUCCESSFULLY: "تم رفع الملف بنجاح"
|
|
||||||
FILE_DELETED: "تم حذف الملف"
|
|
||||||
FILE_COULD_NOT_BE_DELETED: "لا يمكن حذف الملف"
|
|
||||||
FILE_NOT_FOUND: "لم يتم العثور على الملف"
|
|
||||||
NO_FILE_FOUND: "لا يوجد ملف"
|
|
||||||
GRAV_WAS_SUCCESSFULLY_UPDATED_TO: "تم تحديث النظام بنجاح الى"
|
|
||||||
GRAV_UPDATE_FAILED: "فشل تحديث نظام جراف"
|
|
||||||
EVERYTHING_UPDATED: "تم تحديث كل شيء"
|
|
||||||
UPDATES_FAILED: "فشل التحديث"
|
|
||||||
AVATAR_BY: "الصورة الرمزية التي"
|
|
||||||
AVATAR_UPLOAD_OWN: "أو قم بتحميل الخاصة بك..."
|
|
||||||
LAST_BACKUP: "آخر نسخ احتياطي"
|
|
||||||
FULL_NAME: "الإسم الكامل"
|
|
||||||
USERNAME: "إسم المستخدم"
|
|
||||||
EMAIL: "البريد الإلكتروني"
|
|
||||||
USERNAME_EMAIL: "إسم المستخدم أو البريد الإلكتروني"
|
|
||||||
PASSWORD: "كلمة السر"
|
|
||||||
PASSWORD_CONFIRM: "تأكيد كلمة السر"
|
|
||||||
TITLE: "العنوان"
|
|
||||||
ACCOUNT: "الحساب"
|
|
||||||
EMAIL_VALIDATION_MESSAGE: "يجب أن يكون البريد الإلكتروني صحيحاً"
|
|
||||||
PASSWORD_VALIDATION_MESSAGE: "يجب أن تحتوي كلمة المرور على الأقل على رقم وعلى حرف كبير وعلى حرف صغير، و أن تكون مكونة على الأقل من 8 أحرف أو أكثر"
|
|
||||||
LANGUAGE: "اللّغة"
|
|
||||||
LANGUAGE_HELP: "تعيين اللغة المفضلة"
|
|
||||||
DEFAULTS: "الإعدادات الافتراضية"
|
|
||||||
SITE_TITLE: "عنوان الموقع"
|
|
||||||
SITE_TITLE_PLACEHOLDER: "عنوان الموقع العريض"
|
|
||||||
SITE_TITLE_HELP: "العنوان الإفتراضي لموقعك, غالبا يستخدم في السمات"
|
|
||||||
SITE_DEFAULT_LANG: "اللغة الإفتراضية"
|
|
||||||
SITE_DEFAULT_LANG_PLACEHOLDER: "اللغة الإفتراضية المستخدمة في السمات وسم <HTML>"
|
|
||||||
SITE_DEFAULT_LANG_HELP: "اللغة الإفتراضية المستخدمة في السمات وسم <HTML>"
|
|
||||||
DEFAULT_AUTHOR: "المؤلف الافتراضي"
|
|
||||||
DEFAULT_AUTHOR_HELP: "إسم المؤلف الإفتراضي, يستخدم عادة في السمات او محتوى الصفحة"
|
|
||||||
DEFAULT_EMAIL: "البريد الإلكتروني الإفتراضي"
|
|
||||||
DEFAULT_EMAIL_HELP: "البريد الإلكتروني للإشارة في المواضيع أو صفحات"
|
|
||||||
TAXONOMY_TYPES: "أنواع التصنيف"
|
|
||||||
TAXONOMY_TYPES_HELP: "يجب أن يتم تعريف أنواع التصنيف هنا إذا كنت ترغب في استخدامها في صفحات"
|
|
||||||
PAGE_SUMMARY: "ملخص الصفحة"
|
|
||||||
ENABLED: "فعال"
|
|
||||||
ENABLED_HELP: "تمكين صفحة الموجز (الملخص ترجع نفس محتوى الصفحة)"
|
|
||||||
'YES': "نعم"
|
|
||||||
'NO': "لا"
|
|
||||||
SUMMARY_SIZE: "حجم الملخص"
|
|
||||||
SUMMARY_SIZE_HELP: "مقدار أحرف صفحة لاستخدامها كمحتوى موجز"
|
|
||||||
FORMAT: "الشكل"
|
|
||||||
FORMAT_HELP: "اختصار = الاستخدام الأولى لوقوع محدد أو الحجم؛ = فترة طويلة سيتم تجاهل موجز محدد"
|
|
||||||
SHORT: "قصير"
|
|
||||||
LONG: "طويل"
|
|
||||||
DELIMITER: "الفاصل"
|
|
||||||
DELIMITER_HELP: "موجز محدد (الافتراضي '= = =')"
|
|
||||||
METADATA: "البيانات الوصفية"
|
|
||||||
METADATA_HELP: "قيم بيانات التعريف الافتراضية التي سيتم عرضها في كل صفحة ما لم يتم تجاوز الصفحة"
|
|
||||||
NAME: "الإسم"
|
|
||||||
CONTENT: "المحتوى"
|
|
||||||
SIZE: "حجم"
|
|
||||||
ACTION: "اجراء"
|
|
||||||
REDIRECTS_AND_ROUTES: "اعادة التوجيه و المسارات"
|
|
||||||
CUSTOM_REDIRECTS: "تخصيص اعادة التوجيه"
|
|
||||||
CUSTOM_REDIRECTS_HELP: "مسارات لإعادة التوجيه إلى صفحات أخرى. الاستبدال الاساسي ل Regex صحيح"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_KEY: "/ الخاص / الاسم المستعار"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_VALUE: "/ الخاص /إعادة التوجيه"
|
|
||||||
CUSTOM_ROUTES: "تخصيص المسارات"
|
|
||||||
CUSTOM_ROUTES_HELP: "مسارات لاسماء المستعارة إلى صفحات أخرى. الاستبدال الاساسي ل Regex صحيح"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_KEY: "/ الخاص / الاسم المستعار"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_VALUE: "/ الخاص / المسار"
|
|
||||||
FILE_STREAMS: "تيارات الملف"
|
|
||||||
DEFAULT: "الإعدادات العامة"
|
|
||||||
PAGE_MEDIA: "صور و فيديوهات الصفحة"
|
|
||||||
OPTIONS: "الخيارات"
|
|
||||||
PUBLISHED: "نُشِرَ"
|
|
||||||
PUBLISHED_HELP: "بشكل افتراضي، يتم نشر صفحة إلا إذا قمت بتعيين المنشور: false أو عن طريق publish_date يجري في المستقبل، أو unpublish_date في الماضي"
|
|
||||||
DATE: "التاريخ"
|
|
||||||
PUBLISHED_DATE: "تاريخ النشر"
|
|
||||||
ROBOTS: "الروبوتات"
|
|
||||||
ADVANCED: "خيارات متقدمة"
|
|
||||||
SETTINGS: "الإعدادات"
|
|
||||||
FOLDER_NAME: "إسم المجلد"
|
|
||||||
MENU: "القائمة"
|
|
||||||
USE_GLOBAL: "الاستخدام العام"
|
|
||||||
ROUTABLE: "قابل للتوجيه"
|
|
||||||
ROUTABLE_HELP: "إذا أمكن ولوج هذه الصفحة عبر عنوان URL"
|
|
||||||
VISIBLE: "مرئي"
|
|
||||||
ASCENDING: "تصاعدي"
|
|
||||||
DESCENDING: "تنازلي"
|
|
||||||
PAGE_TITLE: "موضوع عنوان الصفحة"
|
|
||||||
PAGE_TITLE_HELP: "عنوان الصفحة"
|
|
||||||
PAGE: "صفحة"
|
|
||||||
FILENAME: "اسم الملف"
|
|
||||||
PARENT_PAGE: "الصفحة الأصل"
|
|
||||||
HOME_PAGE: "الصفحة الرئيسية"
|
|
||||||
TIMEZONE: "المنطقة الزمنية"
|
|
||||||
LANGUAGES: "اللغات"
|
|
||||||
EXPIRES: "انتهاء الصلاحية"
|
|
||||||
LAST_MODIFIED: "آخر تعديل"
|
|
||||||
SESSION: "الجلسة"
|
|
||||||
CURRENT: "الحالي"
|
|
||||||
SAVE_AS: "حفظ كـ"
|
|
||||||
AND: "و"
|
|
||||||
FULLY_UPDATED: "تم تحديث النظام بالكامل"
|
|
||||||
IGNORE_FILES: "تجاهل الملفات"
|
|
||||||
IGNORE_FOLDERS: "تجاهل المجلدات"
|
|
||||||
GROUPS: "الفِرَق"
|
|
||||||
ADMIN_ACCESS: "النفاذ إلى الإدارة"
|
|
||||||
SITE_ACCESS: "الوصول إلى الموقع"
|
|
||||||
INVALID_SECURITY_TOKEN: "رمز الأمان غير صالح"
|
|
||||||
ACTIVATE: "تفعيل"
|
|
||||||
HIDE_HOME_IN_URLS: "إخفاء المسار الرئيسي في عناوين URL"
|
|
||||||
SESSION_SECURE: "آمن"
|
|
||||||
ADD_FOLDER: "إضافة مجلد"
|
|
||||||
ADD_ITEM: "إضافة عنصر"
|
|
||||||
LOADING: "جار التحميل …"
|
|
||||||
PACKAGES_SUCCESSFULLY_UPDATED: "تم تحديث حزمة أو حزمات بنجاح."
|
|
||||||
INSERT: "إدراج"
|
|
||||||
UNDO: "تراجع"
|
|
||||||
REDO: "إعادة"
|
|
||||||
HEADERS: "العناوين الرأسية"
|
|
||||||
ITALIC: "مائل"
|
|
||||||
LINK: "رابط"
|
|
||||||
IMAGE: "صورة"
|
|
||||||
EDITOR: "المحرر"
|
|
||||||
PREVIEW: "معاينة"
|
|
||||||
FULLSCREEN: "ملء الشاشة"
|
|
||||||
PUBLISHING: "النشر"
|
|
||||||
ALL: "الكل"
|
|
||||||
FROM: "من"
|
|
||||||
TO: "إلى"
|
|
||||||
RELEASE_DATE: "تاريخ الإصدار"
|
|
||||||
FORCE_SSL: "فرض SSL"
|
|
||||||
DROPZONE_REMOVE_FILE: "إزالة الملف"
|
|
||||||
TOOLS: "الأدوات"
|
|
||||||
2FA_CODE_INPUT: "000000"
|
|
||||||
2FA_REGENERATE: "إعادة التوليد"
|
|
||||||
VIEW_SITE_TIP: "رؤية الموقع"
|
|
||||||
TOOLS_DIRECT_INSTALL_UPLOAD_BUTTON: "تحميل وتثبيت"
|
|
||||||
SCHEDULER_INSTALL_INSTRUCTIONS: "إرشادات التثبيت"
|
|
||||||
SCHEDULER_INSTALLED_READY: "مثبت وجاهز"
|
|
||||||
EXPERIMENTAL: "تجريبي"
|
|
||||||
FILE: "ملف"
|
|
||||||
ACCOUNTS: "الحسابات"
|
|
||||||
USER_ACCOUNTS: "حسابات المستخدمين"
|
|
||||||
USER_GROUPS: "مجموعات المستخدمين"
|
|
||||||
GROUP_NAME: "اسم الفريق"
|
|
||||||
DISPLAY_NAME: "الاسم المعروض"
|
|
||||||
ICON: "أيقونة"
|
|
||||||
ACCESS: "الوصول"
|
|
||||||
NO_ACCESS: "لا يوجد وصول"
|
|
||||||
SUPER_USER: "مستخدم خارق"
|
|
||||||
ALLOWED: "مسموح"
|
|
||||||
DENIED: "مرفوض"
|
|
||||||
ACCESS_ADMIN_SETTINGS: "الإعدادات"
|
|
||||||
ACCESS_ADMIN_PAGES: "إدارة الصفحات"
|
|
||||||
ACCESS_ADMIN_MAINTENANCE: "صيانة الموقع"
|
|
||||||
ACCESS_ADMIN_STATISTICS: "إحصائيات الموقع"
|
|
||||||
ACCESS_ADMIN_PLUGINS: "إدارة الإضافات"
|
|
||||||
ACCESS_ADMIN_THEMES: "إدارة السمات"
|
|
||||||
ACCESS_ADMIN_TOOLS: "الوصول إلى الأدوات"
|
|
||||||
ACCESS_ADMIN_USERS: "إدارة المستخدمين"
|
|
||||||
USERS: "المستخدمون"
|
|
||||||
ACL: "إدارة صلاحيات الوصول"
|
|
||||||
LANGUAGE_TRANSLATIONS: "الترجمات"
|
|
||||||
LOGOS: "الشعارات"
|
|
||||||
PRESETS: "الإعدادات المسبقة"
|
|
||||||
COLOR_SCHEME_LABEL: "تشكيلات الألوان"
|
|
||||||
CONFIGURATION: "الإعدادات"
|
|
||||||
DASHBOARD: "لوحة المعلومات"
|
|
||||||
MONTHLY_HISTORY: "السجل الشهري"
|
|
||||||
ENABLE: تمكين
|
|
||||||
@@ -1,361 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
ADMIN_NOSCRIPT_MSG: "Моля активирайте JavaScript във вашия браузър."
|
|
||||||
ADMIN_BETA_MSG: "Това е Бета версия! Използвате на ваша отговорност..."
|
|
||||||
ADMIN_REPORT_ISSUE: "Открили сте проблем? Моля, съобщете за него в GitHub."
|
|
||||||
EMAIL_FOOTER: ""
|
|
||||||
LOGIN_BTN: "Вход"
|
|
||||||
LOGIN_BTN_FORGOT: "Забравена парола"
|
|
||||||
LOGIN_BTN_RESET: "Промяна на паролата"
|
|
||||||
LOGIN_BTN_SEND_INSTRUCTIONS: "Изпращане на инструкциите за възстановяването"
|
|
||||||
LOGIN_BTN_CLEAR: "Изтриване на формуляра"
|
|
||||||
LOGIN_BTN_CREATE_USER: "Създаване на потребител"
|
|
||||||
LOGIN_LOGGED_IN: "Влязохте успешно"
|
|
||||||
LOGIN_FAILED: "Влизането не е успешно"
|
|
||||||
LOGGED_OUT: "Излязохте от системата"
|
|
||||||
RESET_NEW_PASSWORD: "Въведете нова парола …"
|
|
||||||
RESET_LINK_EXPIRED: "Връзката за нулиране е изтекла, опитайте отново"
|
|
||||||
RESET_PASSWORD_RESET: "Паролата е променена"
|
|
||||||
RESET_INVALID_LINK: "Използвана невалидна връзка за нулиране, моля опитайте отново"
|
|
||||||
FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "На Вашия имейл, бяха изпратени инструкции за възстановяване на паролата"
|
|
||||||
FORGOT_FAILED_TO_EMAIL: "Неуспешно изпращане на имейл с инструкции, опитайте по-късно"
|
|
||||||
FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Паролата на %s не може да бъде обновена, няма въведен имейл адрес"
|
|
||||||
FORGOT_USERNAME_DOES_NOT_EXIST: "Потребител с име <b>%s</b> не съществува"
|
|
||||||
FORGOT_EMAIL_NOT_CONFIGURED: "Не може да обнови паролата. Този сайт не е конфигуриран да изпраща имейли"
|
|
||||||
FORGOT_EMAIL_SUBJECT: "%s - искане за смяна на парола"
|
|
||||||
FORGOT_EMAIL_BODY: "<h1>Смяна на парола</h1><p>Уважаеми %1$s</p><p>На <b>%4$s</b> бе направено искане за смяна на парола.</p><p><br /><a href=\"%2$s\" class=\"btn-primary\">Натиснете тук за да обновите паролата си</a><br /><br /></p><p>Като алтернатива, можете да копирате линка в адресната лента на браузъра си:</p><p>%2$s</p><p><br />С уважение,<br /><br />%3$s</p>"
|
|
||||||
MANAGE_PAGES: "Управление на страниците"
|
|
||||||
PAGES: "Страници"
|
|
||||||
PLUGINS: "Разширения"
|
|
||||||
PLUGIN: "Разширение"
|
|
||||||
THEMES: "Теми"
|
|
||||||
LOGOUT: "Изход"
|
|
||||||
BACK: "Назад"
|
|
||||||
NEXT: "Напред"
|
|
||||||
PREVIOUS: "Назад"
|
|
||||||
ADD_PAGE: "Добавяне на страница"
|
|
||||||
MOVE: "Преместване"
|
|
||||||
DELETE: "Изтриване"
|
|
||||||
UNSET: "Незададен"
|
|
||||||
VIEW: "Виж"
|
|
||||||
SAVE: "Запазване"
|
|
||||||
NORMAL: "Обикновен"
|
|
||||||
EXPERT: "Експертен"
|
|
||||||
EXPAND_ALL: "Разгъване на всички"
|
|
||||||
COLLAPSE_ALL: "Свиване на всички"
|
|
||||||
ERROR: "Грешка"
|
|
||||||
CLOSE: "Затваряне"
|
|
||||||
CANCEL: "Отказ"
|
|
||||||
CONTINUE: "Продължаване"
|
|
||||||
CONFIRM: "Потвърди"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Изисква се потвърждение"
|
|
||||||
MODAL_CHANGED_DETECTED_TITLE: "Засечени са промени"
|
|
||||||
MODAL_CHANGED_DETECTED_DESC: "Имате незапазени промени. Наистина ли искате да излезете без да сте ги запазили?"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE: "Изисква се потвърждение"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC: "Наистина ли искате да изтриете този файл? Това действие не може да бъде отменено."
|
|
||||||
MODAL_UPDATE_GRAV_CONFIRMATION_REQUIRED_DESC: "Предстои да обновите Grav до последна версия. Искате ли да продължите?"
|
|
||||||
ADD_FILTERS: "Добавяне на филтри"
|
|
||||||
SEARCH_PAGES: "Търсене"
|
|
||||||
VERSION: "Версия"
|
|
||||||
WAS_MADE_WITH: "е създаден с"
|
|
||||||
BY: "от"
|
|
||||||
UPDATE_THEME: "Актуализация на тема"
|
|
||||||
UPDATE_PLUGIN: "Актуализация на разширение"
|
|
||||||
OF_THIS_THEME_IS_NOW_AVAILABLE: "на тази тема е наличен"
|
|
||||||
OF_THIS_PLUGIN_IS_NOW_AVAILABLE: "на този плъгин е вече наличен"
|
|
||||||
AUTHOR: "Автор"
|
|
||||||
HOMEPAGE: "Страница"
|
|
||||||
DEMO: "Демо"
|
|
||||||
BUG_TRACKER: "Докладване за грешки"
|
|
||||||
KEYWORDS: "Ключови думи"
|
|
||||||
LICENSE: "Лиценз"
|
|
||||||
DESCRIPTION: "Описание"
|
|
||||||
README: "Документация"
|
|
||||||
DOCS: "Документи"
|
|
||||||
REMOVE_THEME: "Премахване на тема"
|
|
||||||
INSTALL_THEME: "Инсталиране на тема"
|
|
||||||
THEME: "Тема"
|
|
||||||
BACK_TO_THEMES: "Обратно към темите"
|
|
||||||
BACK_TO_PLUGINS: "Обратно към разширенията"
|
|
||||||
CHECK_FOR_UPDATES: "Проверка за актуализации"
|
|
||||||
ADD: "Добавяне"
|
|
||||||
CLEAR_CACHE: "Изтриване на временните файлове"
|
|
||||||
CLEAR_CACHE_ALL_CACHE: "Всички"
|
|
||||||
CLEAR_CACHE_ASSETS_ONLY: "Само Assets"
|
|
||||||
CLEAR_CACHE_IMAGES_ONLY: "Само изображенията"
|
|
||||||
CLEAR_CACHE_CACHE_ONLY: "Само временните файлове"
|
|
||||||
CLEAR_CACHE_TMP_ONLY: "само временен"
|
|
||||||
UPDATES_AVAILABLE: "Налични актуализации"
|
|
||||||
DAYS: "Дни"
|
|
||||||
UPDATE: "Актуализация"
|
|
||||||
BACKUP: "Резервно копие"
|
|
||||||
BACKUPS: "Резервно копие"
|
|
||||||
BACKUP_NOW: "Създай резервно копие"
|
|
||||||
BACKUPS_STATS: "Статистика резервни копия"
|
|
||||||
BACKUPS_HISTORY: "История резервни копия"
|
|
||||||
BACKUPS_PURGE_CONFIG: "Настройка изтриване на резервно копие"
|
|
||||||
BACKUPS_PROFILES: "Профили на резервни копия"
|
|
||||||
BACKUPS_COUNT: "Брой резервни копия"
|
|
||||||
BACKUPS_PROFILES_COUNT: "Брой профили"
|
|
||||||
BACKUPS_TOTAL_SIZE: "Използвано пространство"
|
|
||||||
BACKUPS_NEWEST: "Най-ново резервно копие"
|
|
||||||
BACKUPS_OLDEST: "Най-старо резервно копие"
|
|
||||||
BACKUPS_PURGE: "Изтриване"
|
|
||||||
BACKUPS_NOT_GENERATED: "Все още не са генериране резервни копия..."
|
|
||||||
BACKUPS_PURGE_NUMBER: "Използва %s от %s слота за резервни копия"
|
|
||||||
BACKUPS_PURGE_TIME: "Остават %s дни за резервно копие"
|
|
||||||
BACKUPS_PURGE_SPACE: "Използва %s от %s"
|
|
||||||
BACKUP_DELETED: "Успешно изтрито резервно копие"
|
|
||||||
BACKUP_NOT_FOUND: "Не е намерено резервно копие"
|
|
||||||
BACKUP_DATE: "Данни за резервно копие"
|
|
||||||
STATISTICS: "Статистика"
|
|
||||||
VIEWS_STATISTICS: "Статистика на страницата"
|
|
||||||
TODAY: "Днес"
|
|
||||||
WEEK: "Седмица"
|
|
||||||
MONTH: "Месец"
|
|
||||||
LATEST_PAGE_UPDATES: "Скоро актуализирани страници"
|
|
||||||
MAINTENANCE: "Техническа поддръжка"
|
|
||||||
UPDATED: "Актуализиран"
|
|
||||||
MON: "пон"
|
|
||||||
TUE: "вт"
|
|
||||||
WED: "ср"
|
|
||||||
THU: "чт"
|
|
||||||
FRI: "пт"
|
|
||||||
SAT: "сб"
|
|
||||||
SUN: "нд"
|
|
||||||
COPY: "Копиране"
|
|
||||||
EDIT: "Редактиране"
|
|
||||||
CREATE: "Създаване"
|
|
||||||
GRAV_ADMIN: "Grav Admin"
|
|
||||||
GRAV_OFFICIAL_PLUGIN: "Официално разширение на Grav"
|
|
||||||
GRAV_OFFICIAL_THEME: "Официална тема на Grav"
|
|
||||||
PLUGIN_SYMBOLICALLY_LINKED: "Този плъгин е символично свързан. Актуализации няма да бъдат отразени."
|
|
||||||
THEME_SYMBOLICALLY_LINKED: "Тази тема е символично свързана. Актуализации няма да бъдат отразени."
|
|
||||||
REMOVE_PLUGIN: "Премахване на разширение"
|
|
||||||
INSTALL_PLUGIN: "Инсталиране на разширение"
|
|
||||||
AVAILABLE: "Налични"
|
|
||||||
INSTALLED: "Инсталирани"
|
|
||||||
INSTALL: "Инсталиране"
|
|
||||||
ACTIVE_THEME: "Активна тема"
|
|
||||||
SWITCHING_TO: "Превключване към"
|
|
||||||
SWITCHING_TO_DESCRIPTION: "При превключването към различна тема няма гаранция, че всички страници са поддържани, което може да доведе до потенциални грешки при опит за зареждане на тези страници."
|
|
||||||
SWITCHING_TO_CONFIRMATION: "Искате ли да продължите и да превключите към темата"
|
|
||||||
CREATE_NEW_USER: "Създаване на нов потребител"
|
|
||||||
REMOVE_USER: "Премахване на потребител"
|
|
||||||
ACCESS_DENIED: "Нямате достъп"
|
|
||||||
ACCOUNT_NOT_ADMIN: "вашият профил няма администраторски права"
|
|
||||||
PHP_INFO: "Информация за PHP"
|
|
||||||
INSTALLER: "Инсталатор"
|
|
||||||
AVAILABLE_THEMES: "Налични теми"
|
|
||||||
AVAILABLE_PLUGINS: "Налични разширения"
|
|
||||||
INSTALLED_THEMES: "Инсталирани теми"
|
|
||||||
INSTALLED_PLUGINS: "Инсталирани разширения"
|
|
||||||
BROWSE_ERROR_LOGS: "Преглед на дневниците за грешки"
|
|
||||||
SITE: "Сайт"
|
|
||||||
INFO: "Информация"
|
|
||||||
SYSTEM: "Система"
|
|
||||||
USER: "Потребител"
|
|
||||||
ADD_ACCOUNT: "Добавяне на профил"
|
|
||||||
SWITCH_LANGUAGE: "Превключване на езика"
|
|
||||||
SUCCESSFULLY_ENABLED_PLUGIN: "Разширението е активирано успешно"
|
|
||||||
SUCCESSFULLY_DISABLED_PLUGIN: "Разширението е спряно"
|
|
||||||
SUCCESSFULLY_CHANGED_THEME: "Промяната на подразбиращата се тема е успешно"
|
|
||||||
INSTALLATION_FAILED: "Неуспешна инсталация"
|
|
||||||
INSTALLATION_SUCCESSFUL: "Инсталацията е успешна"
|
|
||||||
UNINSTALL_FAILED: "Неуспешно деинсталиране"
|
|
||||||
UNINSTALL_SUCCESSFUL: "Деинсталирането е успешно"
|
|
||||||
SUCCESSFULLY_SAVED: "Успешно запазено"
|
|
||||||
SUCCESSFULLY_COPIED: "Успешно копирано"
|
|
||||||
REORDERING_WAS_SUCCESSFUL: "Записът бе успешен"
|
|
||||||
SUCCESSFULLY_DELETED: "Успешно изтрити"
|
|
||||||
SUCCESSFULLY_SWITCHED_LANGUAGE: "Езикът е променен успешно"
|
|
||||||
INSUFFICIENT_PERMISSIONS_FOR_TASK: "Нямате достатъчно права за тази задача"
|
|
||||||
CACHE_CLEARED: "Временните файлове са изчистени"
|
|
||||||
METHOD: "Метод"
|
|
||||||
ERROR_CLEARING_CACHE: "Грешка при изтриването на временните файлове"
|
|
||||||
AN_ERROR_OCCURRED: "Възникна грешка"
|
|
||||||
YOUR_BACKUP_IS_READY_FOR_DOWNLOAD: "Резервното копие е готово за изтегляне"
|
|
||||||
DOWNLOAD_BACKUP: "Изтегляне на резервното копие"
|
|
||||||
PAGES_FILTERED: "Филтрирани страници"
|
|
||||||
NO_PAGE_FOUND: "Няма намерени страници"
|
|
||||||
INVALID_PARAMETERS: "Невалидни параметри"
|
|
||||||
NO_FILES_SENT: "Няма изпратени файлове"
|
|
||||||
EXCEEDED_FILESIZE_LIMIT: "Надхвърлен лимит за размер на PHP конфигурационен файл"
|
|
||||||
EXCEEDED_POSTMAX_LIMIT: "Превишена PHP конфигурация post_max_size"
|
|
||||||
UNKNOWN_ERRORS: "Неизвестни грешки"
|
|
||||||
EXCEEDED_GRAV_FILESIZE_LIMIT: "Превишен лимит за размера на конфигурационен GRAV файл"
|
|
||||||
UNSUPPORTED_FILE_TYPE: "Този файлов формат не се поддържа"
|
|
||||||
FAILED_TO_MOVE_UPLOADED_FILE: "Преместването на качения файл не е успешно."
|
|
||||||
FILE_UPLOADED_SUCCESSFULLY: "Файлът е качен успешно"
|
|
||||||
FILE_DELETED: "Файлът е изтрит"
|
|
||||||
FILE_COULD_NOT_BE_DELETED: "Файлът не може да бъде изтрит"
|
|
||||||
FILE_NOT_FOUND: "Файлът не е намерен"
|
|
||||||
NO_FILE_FOUND: "Няма намерени файлове"
|
|
||||||
GRAV_WAS_SUCCESSFULLY_UPDATED_TO: "Grav беше успешно актуализиран до"
|
|
||||||
GRAV_UPDATE_FAILED: "Актуализацията на Grav е неуспешна"
|
|
||||||
EVERYTHING_UPDATED: "Всичко е актуализирано"
|
|
||||||
UPDATES_FAILED: "Актуализациите не бяха успшено"
|
|
||||||
AVATAR_BY: "Аватар от"
|
|
||||||
AVATAR_UPLOAD_OWN: "Или качи собствени..."
|
|
||||||
LAST_BACKUP: "Последно резервно копие"
|
|
||||||
FULL_NAME: "Пълно име"
|
|
||||||
USERNAME: "Потребителско име"
|
|
||||||
EMAIL: "Ел. поща"
|
|
||||||
USERNAME_EMAIL: "Потребителско име или инейл"
|
|
||||||
PASSWORD: "Парола"
|
|
||||||
PASSWORD_CONFIRM: "Потвърждение на паролата"
|
|
||||||
TITLE: "Титла"
|
|
||||||
ACCOUNT: "Профил"
|
|
||||||
EMAIL_VALIDATION_MESSAGE: "Ел. поща трябва да бъде валидна"
|
|
||||||
PASSWORD_VALIDATION_MESSAGE: "Паролата трябва да съдържа поне един номер, една главна буква, една малка буква и да съдържа поне 8 или повече знака"
|
|
||||||
LANGUAGE: "Език"
|
|
||||||
LANGUAGE_HELP: "Задаване на любим език"
|
|
||||||
DEFAULTS: "По подразбиране"
|
|
||||||
SITE_TITLE: "Заглавие на сайта"
|
|
||||||
SITE_TITLE_PLACEHOLDER: "Заглавие за всички страници"
|
|
||||||
SITE_TITLE_HELP: "Подразбиращо се заглавие за вашият сайт, често се използва от темите"
|
|
||||||
SITE_DEFAULT_LANG: "Език по подразбиране"
|
|
||||||
SITE_DEFAULT_LANG_PLACEHOLDER: "Език по подразбиране, използван от <HTML> тага на темите"
|
|
||||||
SITE_DEFAULT_LANG_HELP: "Език по подразбиране, използван от <HTML> тага на темите"
|
|
||||||
DEFAULT_AUTHOR: "Подразбиращ се автор"
|
|
||||||
DEFAULT_AUTHOR_HELP: "Име на автор по подразбиране, често използвано в теми или страници"
|
|
||||||
DEFAULT_EMAIL: "Имейл по подразбиране"
|
|
||||||
DEFAULT_EMAIL_HELP: "Имейл по подразбиране, използван в теми или страници"
|
|
||||||
TAXONOMY_TYPES: "Видове таксономии"
|
|
||||||
TAXONOMY_TYPES_HELP: "Типовете таксономия трябва да бъдат дефинирани тук, ако искате да ги използвате в страници"
|
|
||||||
PAGE_SUMMARY: "Резюме на страницата"
|
|
||||||
ENABLED: "Включен"
|
|
||||||
ENABLED_HELP: "Разреши извлечение (извлечението връща същото съдържание, като в страницата)"
|
|
||||||
'YES': "Да"
|
|
||||||
'NO': "Не"
|
|
||||||
SUMMARY_SIZE: "Размер на резюмето"
|
|
||||||
SUMMARY_SIZE_HELP: "Брой знаци, които да бъдат използвани при създаването на резюме за страницата"
|
|
||||||
FORMAT: "Формат"
|
|
||||||
SHORT: "Къс"
|
|
||||||
LONG: "Дълъг"
|
|
||||||
DELIMITER: "Делител"
|
|
||||||
DELIMITER_HELP: "Разделител на извлечението (по подразбиране '===')"
|
|
||||||
METADATA: "Мета-данни"
|
|
||||||
METADATA_HELP: "Ще бъдат показани метадата стойностите по подразбиране на всяка страница, освен ако не са отхвърлени от страницата"
|
|
||||||
NAME: "Име"
|
|
||||||
CONTENT: "Съдържание"
|
|
||||||
SIZE: "Размер"
|
|
||||||
ACTION: "Действие"
|
|
||||||
REDIRECTS_AND_ROUTES: "Пренасочвания и пътища"
|
|
||||||
CUSTOM_REDIRECTS: "Потребителски пренасочвания"
|
|
||||||
CUSTOM_REDIRECTS_HELP: "маршрути за пренасочване към сдруга страница. Подмяна със стандартен Regex е валидна"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_KEY: "/your/alias"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_VALUE: "/your/redirect"
|
|
||||||
CUSTOM_ROUTES: "Потребителски пренасочвания"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_KEY: "/your/alias"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_VALUE: "/your/route"
|
|
||||||
FILE_STREAMS: "Потоци файлове"
|
|
||||||
DEFAULT: "По подразбиране"
|
|
||||||
PAGE_MEDIA: "Страница с медия"
|
|
||||||
OPTIONS: "Опции"
|
|
||||||
PUBLISHED: "Публикувано"
|
|
||||||
PUBLISHED_HELP: "По подразбиране страницата се публикува, освен ако не е зададео published: false или publish_date е в бъдеще или unpublish_date е в миналото"
|
|
||||||
DATE: "Дата"
|
|
||||||
DATE_HELP: "Променливата за дата позволява да се зададе дата асоциирана със страницата."
|
|
||||||
PUBLISHED_DATE: "Дата на публикуване"
|
|
||||||
PUBLISHED_DATE_HELP: "Дата, на която автоматично ще се публикува."
|
|
||||||
UNPUBLISHED_DATE: "Дата на непубликуване"
|
|
||||||
UNPUBLISHED_DATE_HELP: "Може да зададе дата за автоматично непубликуване."
|
|
||||||
ROBOTS: "Роботи"
|
|
||||||
TAXONOMIES: "Таксономии"
|
|
||||||
TAXONOMY: "Таксономия"
|
|
||||||
ADVANCED: "Разширено"
|
|
||||||
SETTINGS: "Настройки"
|
|
||||||
FOLDER_NUMERIC_PREFIX: "Цифров префикс на папка"
|
|
||||||
FOLDER_NUMERIC_PREFIX_HELP: "Цифров префикс осигуряващ ръчно подреждане и по-добра видимост"
|
|
||||||
FOLDER_NAME: "Име на папка"
|
|
||||||
FOLDER_NAME_HELP: "Името на папката, която ще се съхрани във файлова система за тази страница"
|
|
||||||
PARENT: "Родител"
|
|
||||||
DEFAULT_OPTION_ROOT: "- Коренова папка -"
|
|
||||||
DEFAULT_OPTION_SELECT: "- Избор -"
|
|
||||||
DISPLAY_TEMPLATE: "Показване на шаблон"
|
|
||||||
ORDERING: "Подреждане"
|
|
||||||
PAGE_ORDER: "Подредба на страниците"
|
|
||||||
OVERRIDES: "Замени"
|
|
||||||
MENU: "Меню"
|
|
||||||
MENU_HELP: "Стрингът, който ще се използва в меню. Ако не се зададе, ще се използва Title."
|
|
||||||
SLUG: "Слъг"
|
|
||||||
SLUG_HELP: "Слъг променливата Ви позволява да зададете конкретна порция от URL на страницата"
|
|
||||||
SLUG_VALIDATE_MESSAGE: "Слъговете могат да съдържат само малки букви, цифри и тирета"
|
|
||||||
PROCESS: "Обработване"
|
|
||||||
PROCESS_HELP: "Контролирайте обработката на страниците. Може да бъде за отделна страница или глобално"
|
|
||||||
DEFAULT_CHILD_TYPE: "Тип по подразбиране"
|
|
||||||
USE_GLOBAL: "Използвай глобални"
|
|
||||||
ROUTABLE: "Маршрутизируем"
|
|
||||||
ROUTABLE_HELP: "Ако страницата е достъпна през URL"
|
|
||||||
CACHING: "Създаване на временни файлове"
|
|
||||||
VISIBLE: "Видим"
|
|
||||||
VISIBLE_HELP: "Определя дали една страница е видима в навигацията."
|
|
||||||
DISABLED: "Изключено"
|
|
||||||
ITEMS: "Елементи"
|
|
||||||
ORDER_BY: "Подреждане по"
|
|
||||||
ORDER: "Подреждане"
|
|
||||||
FOLDER: "Папка"
|
|
||||||
ASCENDING: "Възходящо"
|
|
||||||
DESCENDING: "Низходящо"
|
|
||||||
PAGE_TITLE: "Заглавие на страницата"
|
|
||||||
PAGE_TITLE_HELP: "Заглавието на страницата"
|
|
||||||
PAGE: "Страница"
|
|
||||||
FRONTMATTER: "Встъпление"
|
|
||||||
FILENAME: "Име на файла"
|
|
||||||
PARENT_PAGE: "Родителска страница"
|
|
||||||
HOME_PAGE: "Начална страница"
|
|
||||||
HOME_PAGE_HELP: "Страницата, която Grav ще използва по подразбиране за начална страница"
|
|
||||||
DEFAULT_THEME: "Тема по подразбиране"
|
|
||||||
DEFAULT_THEME_HELP: "Задаване на темата по подразбиране, която Grav ще използва (по подразбиране това е Antimatter)"
|
|
||||||
TIMEZONE: "Часова зона"
|
|
||||||
TIMEZONE_HELP: "Презаписване на времевата зона на сървъра"
|
|
||||||
SHORT_DATE_FORMAT: "Кратък формат дата"
|
|
||||||
SHORT_DATE_FORMAT_HELP: "Задай кратък формат дата, който може да се използва от темите"
|
|
||||||
LONG_DATE_FORMAT: "Пълен формат дата"
|
|
||||||
LONG_DATE_FORMAT_HELP: "Задай пълен формат дата, който може да се използва от темите"
|
|
||||||
DEFAULT_ORDERING: "По подразбиране"
|
|
||||||
DEFAULT_ORDERING_DEFAULT: "По подразбиране - според име на папка"
|
|
||||||
DEFAULT_ORDERING_FOLDER: "Папка - според името на папката без префикс"
|
|
||||||
DEFAULT_ORDERING_TITLE: "Заглавие - според заглавно поле в главата"
|
|
||||||
DEFAULT_ORDERING_DATE: "Дата - според поле за дата в главата"
|
|
||||||
DEFAULT_ORDER_DIRECTION: "Подреждане по подразбиране"
|
|
||||||
DEFAULT_ORDER_DIRECTION_HELP: "Посоката на страниците в списък"
|
|
||||||
DEFAULT_PAGE_COUNT: "Брой страници по подразбиране"
|
|
||||||
DEFAULT_PAGE_COUNT_HELP: "Максимален брой страници в списък по подразбиране"
|
|
||||||
DATE_BASED_PUBLISHING: "Публикуване според датата"
|
|
||||||
DATE_BASED_PUBLISHING_HELP: "Автоматично (не)публикувай постове според датата"
|
|
||||||
EVENTS: "Събития"
|
|
||||||
EVENTS_HELP: "Пускане или спиране на специфични събития. Спирането на някои събития може да счупи определени приставки"
|
|
||||||
REDIRECT_DEFAULT_ROUTE: "Пренасочване на пътя по подразбиране"
|
|
||||||
REDIRECT_DEFAULT_ROUTE_HELP: "Автоматично пренасочване към пътя по подразбиране на страницата"
|
|
||||||
LANGUAGES: "Езици"
|
|
||||||
SUPPORTED: "Поддържани"
|
|
||||||
SUPPORTED_HELP: "Списък от двубуквени езикови кодове, отделени със запетая (пример 'bg,en,de')"
|
|
||||||
HTTP_HEADERS: "HTTP заглавки"
|
|
||||||
EXPIRES: "Изтича на"
|
|
||||||
CACHE_CONTROL: "HTTP кеш-контрол"
|
|
||||||
LAST_MODIFIED: "Последна промяна"
|
|
||||||
CACHE_CHECK_METHOD: "Мотод проверка на кеша"
|
|
||||||
CACHE_DRIVER: "Кеш драйвър"
|
|
||||||
CACHE_PREFIX: "Кеш представка"
|
|
||||||
CACHE_PURGE: "Изтриване на стр кеш"
|
|
||||||
LIFETIME: "Продължителност на живот"
|
|
||||||
GZIP_COMPRESSION: "Gzip компресия"
|
|
||||||
GZIP_COMPRESSION_HELP: "Разреши GZip компресия на Grav страницата, за оптимизация."
|
|
||||||
CSS_PIPELINE: "CSS pipeline"
|
|
||||||
JAVASCRIPT_PIPELINE: "JavaScript pipeline"
|
|
||||||
LOG_HANDLER: "Обработка на лога"
|
|
||||||
DEBUGGER: "Дибъгър"
|
|
||||||
SESSION: "Сесия"
|
|
||||||
CURRENT: "Текущ"
|
|
||||||
SAVE_AS: "Запази като"
|
|
||||||
AND: "и"
|
|
||||||
UPDATE_AVAILABLE: "Налична актуализация"
|
|
||||||
FULLY_UPDATED: "Напълно обновен"
|
|
||||||
SAVE_LOCATION: "Местоположение за запис"
|
|
||||||
IGNORE_HIDDEN_HELP: "Игнорирай всички файлове и папки, които започват с точка"
|
|
||||||
WRAPPED_SITE: "Опаковани сайт"
|
|
||||||
CONFIGURATION: "Настройки"
|
|
||||||
TIMEOUT: "Таймаут"
|
|
||||||
DASHBOARD: "Контролен панел"
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
LOGIN_BTN: "লগ ইন"
|
|
||||||
LOGIN_BTN_FORGOT: "ভুলে গেছি"
|
|
||||||
@@ -1,584 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
ADMIN_BETA_MSG: "Un ermaeziadenn beta an hini eo! Arverit en endro produadur gant evezh..."
|
|
||||||
ADMIN_REPORT_ISSUE: "Kavet hoc'h eus ur gudenn? Danevellit anezhi war Github."
|
|
||||||
LOGIN_BTN: "Anv arveriad"
|
|
||||||
LOGIN_BTN_FORGOT: "Ankouaet"
|
|
||||||
LOGIN_BTN_RESET: "Adderaouekaat ar ger-tremen"
|
|
||||||
LOGIN_BTN_SEND_INSTRUCTIONS: "Kas an ditouroù adderaouekaat"
|
|
||||||
LOGIN_BTN_CLEAR: "Skarzhañ ar furmskrid"
|
|
||||||
LOGIN_BTN_CREATE_USER: "Krouiñ an arveriad"
|
|
||||||
LOGIN_LOGGED_IN: "Kennasket oc'h gant berzh"
|
|
||||||
LOGIN_FAILED: "C'hwitadenn war ar c'hennask"
|
|
||||||
LOGGED_OUT: "Digennasket oc'h"
|
|
||||||
RESET_NEW_PASSWORD: "Enankit ur ger-tremen nevez …"
|
|
||||||
RESET_LINK_EXPIRED: "Diamzeret eo an ere adderaouekaat, klaskit en-dro"
|
|
||||||
RESET_PASSWORD_RESET: "Adderaouekaet eo bet ar ger-tremen"
|
|
||||||
RESET_INVALID_LINK: "Ere adderaouekaat didalvoudek, klaskit en-dro"
|
|
||||||
FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Kaset eo bet an ditouroù da adderaouekaat ho ker-tremen d'ho chmolec'h postel"
|
|
||||||
FORGOT_FAILED_TO_EMAIL: "C'hwitadenn en ur gas an ditouroù, klaskit en-dro diwezhatoc'h"
|
|
||||||
FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "N'haller ket adderaouekaat ar ger-tremen evit %s, chomlec'h postel ebet arventennet"
|
|
||||||
FORGOT_USERNAME_DOES_NOT_EXIST: "N'eus ket eus an arveriad gant an anv <b>%s</b>"
|
|
||||||
FORGOT_EMAIL_NOT_CONFIGURED: "N'haller ket adderaouekaat ar ger-tremen. N'eo ket kefluniet al lec'hienn evit kas posteloù"
|
|
||||||
FORGOT_EMAIL_SUBJECT: "%s Goulenn adderaouekaat ar ger-tremen"
|
|
||||||
FORGOT_EMAIL_BODY: "<h1>Adderaouekaat ar ger-tremen/h1><p>%1$s,</p><p>Graet eo bet un azgoulenn war <b>%4$s</b> evit adderaouekaat ho ker-tremen.</p><p><br /><a href=\"%2$s\" class=\"btn-primary\">Klikit amañ da adderaouekaat ho ker-tremen</a><br /><br /></p><p>Gallout a rit ivez eilañ an URL da heul er varrenn chomlec'h en ho merdeer:</p> <p>%2$s</p><p><br />A galon,<br /><br />%3$s</p>"
|
|
||||||
MANAGE_PAGES: "Ardeiñ ar pajennoù"
|
|
||||||
PAGES: "Pajennoù"
|
|
||||||
PLUGINS: "Enlugelladoù"
|
|
||||||
PLUGIN: "Enlugellad"
|
|
||||||
THEMES: "Neuzioù"
|
|
||||||
LOGOUT: "Digennaskañ"
|
|
||||||
BACK: "Distreiñ"
|
|
||||||
NEXT: "War-lerc'h"
|
|
||||||
PREVIOUS: "Diaraog"
|
|
||||||
ADD_PAGE: "Ouzhpennañ ur bajenn"
|
|
||||||
MOVE: "Dilec'hiañ"
|
|
||||||
DELETE: "Dilemel"
|
|
||||||
VIEW: "Gwel"
|
|
||||||
SAVE: "Enrollañ"
|
|
||||||
NORMAL: "Reoliek"
|
|
||||||
EXPERT: "Kemplezhoc'h"
|
|
||||||
EXPAND_ALL: "Astenn an holl"
|
|
||||||
COLLAPSE_ALL: "Bihanaat an holl"
|
|
||||||
ERROR: "Fazi"
|
|
||||||
CLOSE: "Serriñ"
|
|
||||||
CANCEL: "Nullañ"
|
|
||||||
CONTINUE: "Kenderc'hel"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Kadarnadur azgoulennet"
|
|
||||||
MODAL_CHANGED_DETECTED_TITLE: "Kemmoù dinoet"
|
|
||||||
MODAL_CHANGED_DETECTED_DESC: "Kemmoù dienrollet a zo. Sur oc'h e fell deoc'h kuitaat hep enrollañ?"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE: "Kadarnadur azgoulennet"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC: "Sur oc'h e fell deoc'h dilemel ar restr-mañ? N'haller ket dizober ar gwered-mañ."
|
|
||||||
ADD_FILTERS: "Ouzhpennañ siloù"
|
|
||||||
SEARCH_PAGES: "Klask pajennoù"
|
|
||||||
VERSION: "Handelv"
|
|
||||||
WAS_MADE_WITH: "Savet eo bet gant"
|
|
||||||
BY: "Gant"
|
|
||||||
UPDATE_THEME: "Hizivaat an neuz"
|
|
||||||
UPDATE_PLUGIN: "Hizivaat an enlugellad"
|
|
||||||
OF_THIS_THEME_IS_NOW_AVAILABLE: "an neuz-mañ a zo hegerz"
|
|
||||||
OF_THIS_PLUGIN_IS_NOW_AVAILABLE: "an enlugellad-mañ a zo hegerz"
|
|
||||||
AUTHOR: "Aozer"
|
|
||||||
HOMEPAGE: "Pennbajenn"
|
|
||||||
DEMO: "Tañva"
|
|
||||||
BUG_TRACKER: "Heulier beugoù"
|
|
||||||
KEYWORDS: "Gerioù-alc'hwez"
|
|
||||||
LICENSE: "Lañvaz"
|
|
||||||
DESCRIPTION: "Deskrivadur"
|
|
||||||
README: "Skoazell"
|
|
||||||
REMOVE_THEME: "Dilemel an neuz"
|
|
||||||
INSTALL_THEME: "Staliañ an neuz"
|
|
||||||
THEME: "Neuz"
|
|
||||||
BACK_TO_THEMES: "Distreiñ d'an neuzioù"
|
|
||||||
BACK_TO_PLUGINS: "Distreiñ d'an enlugelladoù"
|
|
||||||
CHECK_FOR_UPDATES: "Klask hizivadennoù"
|
|
||||||
ADD: "Ouzhpenañ"
|
|
||||||
CLEAR_CACHE: "Skarzhañ ar c'hrubuilh"
|
|
||||||
CLEAR_CACHE_ALL_CACHE: "Ar c'hrubuilh a-bezh"
|
|
||||||
CLEAR_CACHE_ASSETS_ONLY: "Loazioù nemetken"
|
|
||||||
CLEAR_CACHE_IMAGES_ONLY: "Skeudennoù nemetken"
|
|
||||||
CLEAR_CACHE_CACHE_ONLY: "Krubuilh nemetken"
|
|
||||||
CLEAR_CACHE_TMP_ONLY: "Padennek hepken"
|
|
||||||
UPDATES_AVAILABLE: "Hizivadennoù hegerz"
|
|
||||||
DAYS: "Devezhioù"
|
|
||||||
UPDATE: "Hizivadenn"
|
|
||||||
BACKUP: "Gwared"
|
|
||||||
STATISTICS: "Stadegoù"
|
|
||||||
TODAY: "Hiziv"
|
|
||||||
WEEK: "Sizhun"
|
|
||||||
MONTH: "Miz"
|
|
||||||
LATEST_PAGE_UPDATES: "Hizivadennoù diwezhañ ar bajenn"
|
|
||||||
MAINTENANCE: "Trezalc'h"
|
|
||||||
UPDATED: "Hizivaet"
|
|
||||||
MON: "Lun"
|
|
||||||
TUE: "Meu"
|
|
||||||
WED: "Mer"
|
|
||||||
THU: "Yao"
|
|
||||||
FRI: "Gwe"
|
|
||||||
SAT: "Sad"
|
|
||||||
SUN: "Sul"
|
|
||||||
COPY: "Eilañ"
|
|
||||||
EDIT: "Kemmañ"
|
|
||||||
CREATE: "Krouiñ"
|
|
||||||
GRAV_ADMIN: "Merour Grav"
|
|
||||||
GRAV_OFFICIAL_PLUGIN: "Enlugellad Kefridiel Grav"
|
|
||||||
GRAV_OFFICIAL_THEME: "Neuz Kefridiel Grav"
|
|
||||||
PLUGIN_SYMBOLICALLY_LINKED: "Gant un ere arouezus eo lakaet an enlugellad. Ne vo ket dinoet an hizivadennoù."
|
|
||||||
THEME_SYMBOLICALLY_LINKED: "Gant un ere arouezus eo lakaet an neuz. Ne vo ket dinoet an hizivadennoù"
|
|
||||||
REMOVE_PLUGIN: "Dilemel an enlugellad"
|
|
||||||
INSTALL_PLUGIN: "Staliañ an enlugellad"
|
|
||||||
AVAILABLE: "Hegerz"
|
|
||||||
INSTALLED: "Staliet"
|
|
||||||
INSTALL: "Staliañ"
|
|
||||||
ACTIVE_THEME: "Neuz oberiant"
|
|
||||||
SWITCHING_TO: "Kemmañ da"
|
|
||||||
SWITCHING_TO_DESCRIPTION: "En ur gemmañ d'un neuz disheñvel n'eus gwarant ebet e vo skoret an holl frammoù pajenn, ar pezh a zegasfe fazioù en ur gargañ ar pajennoù-mañ."
|
|
||||||
SWITCHING_TO_CONFIRMATION: "Fellout a ra deoc'h kenderc'hel ha kemmañ an neuz"
|
|
||||||
CREATE_NEW_USER: "Krouiñ un arveriad nevez"
|
|
||||||
REMOVE_USER: "Dilemel an arveriad"
|
|
||||||
ACCESS_DENIED: "Haeziñ nac'het"
|
|
||||||
ACCOUNT_NOT_ADMIN: "n'hoc'h eus ket an aotreoù a-zere"
|
|
||||||
PHP_INFO: "Titouroù PHP"
|
|
||||||
INSTALLER: "Stalier"
|
|
||||||
AVAILABLE_THEMES: "Neuzioù hegerz"
|
|
||||||
AVAILABLE_PLUGINS: "Enlugelladoù hegerz"
|
|
||||||
INSTALLED_THEMES: "Neuzioù staliet"
|
|
||||||
INSTALLED_PLUGINS: "Enlugelladoù staliet"
|
|
||||||
BROWSE_ERROR_LOGS: "Furchal er c'herzhlevr fazioù"
|
|
||||||
SITE: "Lec'hienn"
|
|
||||||
INFO: "Titouroù"
|
|
||||||
SYSTEM: "Reizhiad"
|
|
||||||
USER: "Arveriad"
|
|
||||||
ADD_ACCOUNT: "Ouzhpennañ ur gont"
|
|
||||||
SWITCH_LANGUAGE: "Kemmañ ar yezh"
|
|
||||||
SUCCESSFULLY_ENABLED_PLUGIN: "Gweredekaet an enlugellad gant berzh"
|
|
||||||
SUCCESSFULLY_DISABLED_PLUGIN: "Diweredekaet an enlugellad gant berzh"
|
|
||||||
SUCCESSFULLY_CHANGED_THEME: "Kemmet an neuz dre ziouer gant berzh"
|
|
||||||
INSTALLATION_FAILED: "C'hwitadenn war ar staliadur"
|
|
||||||
INSTALLATION_SUCCESSFUL: "Berzh war ar staliadur"
|
|
||||||
UNINSTALL_FAILED: "C'hwitadenn war an distaliadur"
|
|
||||||
UNINSTALL_SUCCESSFUL: "Berzh war an distaliadur"
|
|
||||||
SUCCESSFULLY_SAVED: "Enrollet gant berzh"
|
|
||||||
SUCCESSFULLY_COPIED: "Eilet gant berzh"
|
|
||||||
REORDERING_WAS_SUCCESSFUL: "Adurzhiet gant berzh"
|
|
||||||
SUCCESSFULLY_DELETED: "Dilamet gant berzh"
|
|
||||||
SUCCESSFULLY_SWITCHED_LANGUAGE: "Kemmet ar yezh gant berzh"
|
|
||||||
INSUFFICIENT_PERMISSIONS_FOR_TASK: "N'ho peus ket trawalc'h a aotreoù evit ar gwered"
|
|
||||||
CACHE_CLEARED: "Skarzhet ar c'hrubuilh"
|
|
||||||
METHOD: "Hentenn"
|
|
||||||
ERROR_CLEARING_CACHE: "Fazi en ur skarzhañ ar c'hrubuilh"
|
|
||||||
AN_ERROR_OCCURRED: "Degouezhet ez eus bet ur fazi"
|
|
||||||
YOUR_BACKUP_IS_READY_FOR_DOWNLOAD: "Prest eo ho kwared da vezañ pellgarget"
|
|
||||||
DOWNLOAD_BACKUP: "Pellgargañ ar gwared"
|
|
||||||
PAGES_FILTERED: "Pajennoù silet"
|
|
||||||
NO_PAGE_FOUND: "Pajenn ebet kavet"
|
|
||||||
INVALID_PARAMETERS: "Arventennoù didalvoudek"
|
|
||||||
NO_FILES_SENT: "Restr ebet kaset"
|
|
||||||
UNKNOWN_ERRORS: "Fazioù dianav"
|
|
||||||
UNSUPPORTED_FILE_TYPE: "Doare restr amskor"
|
|
||||||
FAILED_TO_MOVE_UPLOADED_FILE: "C'hwitadenn en ur zilec'hiañ ar restr pellgaset."
|
|
||||||
FILE_UPLOADED_SUCCESSFULLY: "Restr pellgaset gant berzh"
|
|
||||||
FILE_DELETED: "Restr dilamet"
|
|
||||||
FILE_COULD_NOT_BE_DELETED: "N'haller ket dilemel ar restr"
|
|
||||||
FILE_NOT_FOUND: "N'eus ket bet kavet ar restr"
|
|
||||||
NO_FILE_FOUND: "Restr ebet kavet"
|
|
||||||
GRAV_WAS_SUCCESSFULLY_UPDATED_TO: "Hizivaet eo bet Grav da"
|
|
||||||
GRAV_UPDATE_FAILED: "C'hwitadenn war hizivadenn Grav"
|
|
||||||
EVERYTHING_UPDATED: "Hizivaet pep tra"
|
|
||||||
UPDATES_FAILED: "C'hwitadenn war a hizivadennoù"
|
|
||||||
AVATAR_BY: "Avatar gant"
|
|
||||||
LAST_BACKUP: "Gwared diwezhañ"
|
|
||||||
FULL_NAME: "Anv klok"
|
|
||||||
USERNAME: "Anv arveriad"
|
|
||||||
EMAIL: "Chomlec'h postel"
|
|
||||||
PASSWORD: "Ger-tremen"
|
|
||||||
PASSWORD_CONFIRM: "Kadarnat ar ger-tremen"
|
|
||||||
TITLE: "Titl"
|
|
||||||
ACCOUNT: "Kont"
|
|
||||||
EMAIL_VALIDATION_MESSAGE: "Ret eo reiñ ur chomlec'h postel talvoudek"
|
|
||||||
PASSWORD_VALIDATION_MESSAGE: "Ret eo d'ar ger-tremen enderc'hel ur niverenn, ul lizherenn vras hag ul lizherenn vihan hag 8 arouezenn d'an nebeutañ"
|
|
||||||
LANGUAGE: "Yezh"
|
|
||||||
LANGUAGE_HELP: "Dibabit ar yezh"
|
|
||||||
DEFAULTS: "Dre ziouer"
|
|
||||||
SITE_TITLE: "Titl al lec'hienn"
|
|
||||||
SITE_TITLE_PLACEHOLDER: "Titl ledan al lec'hienn"
|
|
||||||
SITE_TITLE_HELP: "Titl dre ziouer ho lec'hienn, arveret en neuzioù"
|
|
||||||
SITE_DEFAULT_LANG: "Yezh defot"
|
|
||||||
DEFAULT_AUTHOR: "Aozer dre ziouer"
|
|
||||||
DEFAULT_AUTHOR_HELP: "Un anv aozer dre ziouer, arveret en neuzioù pe er pajennoù"
|
|
||||||
DEFAULT_EMAIL: "Chomlec'h postel dre ziouer"
|
|
||||||
DEFAULT_EMAIL_HELP: "Ur chomlec'h postel dre ziouer, arveret en neuze pe er pajennoù"
|
|
||||||
TAXONOMY_TYPES: "Doareoù rummadoù"
|
|
||||||
TAXONOMY_TYPES_HELP: "An doareoù rummadoù a rank bezañ erspizet amañ ma fell deoc'h arverañ anezho er pajennoù"
|
|
||||||
PAGE_SUMMARY: "Berradenn ar bajenn"
|
|
||||||
ENABLED: "Gweredekaet"
|
|
||||||
ENABLED_HELP: "Gweredekaat berradenn ar bajenn (ar verradenn a zistro an hevelep tra hag endalc'had ar bajenn)"
|
|
||||||
'YES': "Ya"
|
|
||||||
'NO': "Ket"
|
|
||||||
SUMMARY_SIZE: "Ment ar verradenn"
|
|
||||||
SUMMARY_SIZE_HELP: "An niverenn a arouezenn da arverañ evel berradenn ur bajenn"
|
|
||||||
FORMAT: "Mentrezh"
|
|
||||||
FORMAT_HELP: "berr = arverañ degouezh kentañ an disranner pe ment; hir = laosket e vo an disranner berradenn a-gostez"
|
|
||||||
SHORT: "Berr"
|
|
||||||
LONG: "Hir"
|
|
||||||
DELIMITER: "Disranner"
|
|
||||||
DELIMITER_HELP: "Disranner ar verradenn (diouer '===')"
|
|
||||||
METADATA: "Metaroadennoù"
|
|
||||||
METADATA_HELP: "Skrammet e vo ar gwerzhioù metaroadennoù dre ziouer war an holl bajennoù war-bouez m'eo flastret gant ar bajenn"
|
|
||||||
NAME: "Anv"
|
|
||||||
CONTENT: "Endalc'had"
|
|
||||||
REDIRECTS_AND_ROUTES: "Adheñchañ ha treugoù"
|
|
||||||
CUSTOM_REDIRECTS: "Adheñchañ personelaet"
|
|
||||||
CUSTOM_REDIRECTS_HELP: "treugoù da adheñchañ davet pajennoù all. Talvoudek eo an amsaviñ regex"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_KEY: "/un/anv"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_VALUE: "/un/adeñchañ"
|
|
||||||
CUSTOM_ROUTES: "Treugoù personelaet"
|
|
||||||
CUSTOM_ROUTES_HELP: "treugoù da adheñchañ davet pajennoù all. Talvoudek eo an amsaviñ Regex"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_KEY: "/ho/anv"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_VALUE: "/ho/treug"
|
|
||||||
FILE_STREAMS: "Lanvioù restroù"
|
|
||||||
DEFAULT: "Dre ziouer"
|
|
||||||
PAGE_MEDIA: "Media ar bajenn"
|
|
||||||
OPTIONS: "Dibarzhioù"
|
|
||||||
PUBLISHED: "Embannet"
|
|
||||||
PUBLISHED_HELP: "Dre ziouer eo embannet ur bajenn war-bouez m'eo lakaet da \"Embannet: ket\" pe dre un deiziad embann en dazont, pe un deiziad diembannañ tremenet"
|
|
||||||
DATE: "Deiziad"
|
|
||||||
DATE_HELP: "Ar vaezienn deiziad a laosk ac'hanoc'h da arventennañ un deiziad liammet gant ar bajenn."
|
|
||||||
PUBLISHED_DATE: "Deiziad embann"
|
|
||||||
PUBLISHED_DATE_HELP: "Gallout a rit reiñ un deiziad da embann ent emgefreek."
|
|
||||||
UNPUBLISHED_DATE: "Deiziad diembannañ"
|
|
||||||
UNPUBLISHED_DATE_HELP: "Gallout a rit reiñ un deiziad evit diembannañ ent emgefreek."
|
|
||||||
ROBOTS: "Robotoù"
|
|
||||||
TAXONOMIES: "Rummadoù"
|
|
||||||
TAXONOMY: "Rummad"
|
|
||||||
ADVANCED: "Kempleshoc'h"
|
|
||||||
SETTINGS: "Arventennoù"
|
|
||||||
FOLDER_NUMERIC_PREFIX: "Rakger niverel an teuliad"
|
|
||||||
FOLDER_NUMERIC_PREFIX_HELP: "Rakgerioù niverel evit urzhiañ gant an dorn ha emplegañ ar gwelusted"
|
|
||||||
FOLDER_NAME: "Anv an teuliad"
|
|
||||||
FOLDER_NAME_HELP: "Anv an teuliad a vo kadavet er reizhiad restroù evit ar bajenn"
|
|
||||||
PARENT: "Kar"
|
|
||||||
DEFAULT_OPTION_ROOT: "- Gwrizienn -"
|
|
||||||
DEFAULT_OPTION_SELECT: "- Diuzañ -"
|
|
||||||
DISPLAY_TEMPLATE: "Skrammañ ar patrom"
|
|
||||||
DISPLAY_TEMPLATE_HELP: "An doare pajenn a ziviz peseurt patrom twig a zeznaouo ar bajenn"
|
|
||||||
ORDERING: "Urzh"
|
|
||||||
PAGE_ORDER: "Urzh ar pajennoù"
|
|
||||||
OVERRIDES: "Flastrañ"
|
|
||||||
MENU: "Lañser"
|
|
||||||
MENU_HELP: "Ar chadennoù da arverañ el lañser. Ma n'eo ket arventennet, Titl a vo arveret."
|
|
||||||
SLUG: "Slug"
|
|
||||||
SLUG_HELP: "An argemenn slug a aotren ac'hanoc'h da arventennañ URL lodenn ar bajenn"
|
|
||||||
SLUG_VALIDATE_MESSAGE: "Lizherennoù bihan, sifroù ha tiredoù a c'hall bezañ er slug hepken"
|
|
||||||
PROCESS: "Keweriañ"
|
|
||||||
PROCESS_HELP: "Reoliañ penaos eo keweriet ar pajennoù. Gallout a ra bezañ lakaet dre bajenn kentoc'h eget en un doare hollek"
|
|
||||||
DEFAULT_CHILD_TYPE: "Doare bugel dre ziouer"
|
|
||||||
USE_GLOBAL: "Arverañ Hollek"
|
|
||||||
ROUTABLE: "Treugus"
|
|
||||||
ROUTABLE_HELP: "M'eo haezadus ar bajenn dre un URL"
|
|
||||||
CACHING: "Krubuilhiñ"
|
|
||||||
VISIBLE: "Gwelus"
|
|
||||||
VISIBLE_HELP: "Despizañ a ra gwelusted ur bajenn er merdeiñ."
|
|
||||||
DISABLED: "Diweredekaet"
|
|
||||||
ITEMS: "Ergorennoù"
|
|
||||||
ORDER_BY: "Urzhiañ dre"
|
|
||||||
ORDER: "Urzh"
|
|
||||||
FOLDER: "Teuliad"
|
|
||||||
ASCENDING: "War-gresk"
|
|
||||||
DESCENDING: "War-zigresk"
|
|
||||||
PAGE_TITLE: "Titl ar bajenn"
|
|
||||||
PAGE_TITLE_HELP: "Titl ar bajenn"
|
|
||||||
PAGE: "Pajenn"
|
|
||||||
FRONTMATTER: "Frontmatter"
|
|
||||||
FILENAME: "Anv ar restr"
|
|
||||||
PARENT_PAGE: "Pajenn gar"
|
|
||||||
HOME_PAGE: "Pennbajenn"
|
|
||||||
HOME_PAGE_HELP: "Pajenn arveret gant Grav evel pajenn degemer dre ziouer"
|
|
||||||
DEFAULT_THEME: "Neuz dre ziouer"
|
|
||||||
DEFAULT_THEME_HELP: "Arventennañ an neuz arveret gant Grav dre ziouer (Antimatter dre ziouer)"
|
|
||||||
TIMEZONE: "Gwerzhid-eur"
|
|
||||||
TIMEZONE_HELP: "Flastrañ gwerzhid-eur dre ziouer an dafariad"
|
|
||||||
SHORT_DATE_FORMAT: "Mentrezh skrammañ an deiziad berr"
|
|
||||||
SHORT_DATE_FORMAT_HELP: "Arventennan ar mentrezh deiziad berr da arverañ gant an neuzioù"
|
|
||||||
LONG_DATE_FORMAT: "Mentrezh deiziad hir"
|
|
||||||
LONG_DATE_FORMAT_HELP: "Arventennañ ar mentrezh deiziad hir a vo arveret en neuzioù"
|
|
||||||
DEFAULT_ORDERING: "Urzh dre ziouer"
|
|
||||||
DEFAULT_ORDERING_HELP: "Pajennoù er roll a vo skrammet en urzh-mañ war-bouez m'eo flastret"
|
|
||||||
DEFAULT_ORDERING_DEFAULT: "Dre ziouer - diazezet war anv an teuliad"
|
|
||||||
DEFAULT_ORDERING_FOLDER: "Teuliad - diazezet war anv an teuliad hep rakger"
|
|
||||||
DEFAULT_ORDERING_TITLE: "Titl - diazezet war vaezienn ditl an talbenn"
|
|
||||||
DEFAULT_ORDERING_DATE: "Deiziad - diazezet war vaezienn deiziad an talbenn"
|
|
||||||
DEFAULT_ORDER_DIRECTION: "Tu an urzh dre ziouer"
|
|
||||||
DEFAULT_ORDER_DIRECTION_HELP: "Tu ar pajennoù er roll"
|
|
||||||
DEFAULT_PAGE_COUNT: "Niver a bajennoù dre ziouer"
|
|
||||||
DEFAULT_PAGE_COUNT_HELP: "Niver a bajennoù en ur roll d'ar muiañ"
|
|
||||||
DATE_BASED_PUBLISHING: "Embannadenn diazezet war un deiziad"
|
|
||||||
DATE_BASED_PUBLISHING_HELP: "(Di)embann pennadoù ent emgefreek hervez o deiziad"
|
|
||||||
EVENTS: "Darvoudoù"
|
|
||||||
EVENTS_HELP: "(Di)weredekaat darvoudoù resis. Diweredekaat anezho a c'hall terriñ enlugelladoù"
|
|
||||||
REDIRECT_DEFAULT_ROUTE: "Adheñchañ an treug dre ziouer"
|
|
||||||
REDIRECT_DEFAULT_ROUTE_HELP: "Adheñchañ ent emgefreek d'un treug pajenn dre ziouer"
|
|
||||||
LANGUAGES: "Yezhoù"
|
|
||||||
SUPPORTED: "Skoret"
|
|
||||||
SUPPORTED_HELP: "Roll bonegoù yezh 2 lizherenn ennañ disrannet gant skejoù (skouer: 'br, cy, en')"
|
|
||||||
TRANSLATIONS_FALLBACK: "Troidigezh dre ziouer"
|
|
||||||
TRANSLATIONS_FALLBACK_HELP: "Arverañ un droidigezh all ma n'eus ket eus ar tezh oberiant"
|
|
||||||
ACTIVE_LANGUAGE_IN_SESSION: "Yezhoù oberiant en estez"
|
|
||||||
ACTIVE_LANGUAGE_IN_SESSION_HELP: "Kadaviñ ar yezh oberiant en estez"
|
|
||||||
HTTP_HEADERS: "Talbennoù HTTP"
|
|
||||||
EXPIRES: "Diamzer"
|
|
||||||
EXPIRES_HELP: "Arventennañ an talbenn diamzeriñ e eilennoù."
|
|
||||||
LAST_MODIFIED: "Kemmet da ziwezhañ"
|
|
||||||
LAST_MODIFIED_HELP: "Arventennañ an talbenn kemmet da ziwezhañ a c'hall skoazell da wellaat ar proksi ha krubuilh ar merdeer"
|
|
||||||
ETAG: "ETag"
|
|
||||||
ETAG_HELP: "Arventennañ an talbenn etag evit skoazell da c'houzout peur eo bet kemmet ur bajenn"
|
|
||||||
VARY_ACCEPT_ENCODING: "Vary accept encoding"
|
|
||||||
VARY_ACCEPT_ENCODING_HELP: "Arventennañ a ra an talbenn `Vary: Accept Encoding` evit skoazell gant ar proksi hag ar c'hrubuilh CDN"
|
|
||||||
MARKDOWN_EXTRA_HELP: "Gweredekaat ar skor dre ziouer evit Markdown Ectra - https://michelf.ca/projects/php-markdown/extra/"
|
|
||||||
AUTO_LINE_BREAKS: "Tremen d'al linenn ent emgefreek"
|
|
||||||
AUTO_LINE_BREAKS_HELP: "Gweredekaat skor tremen al linenn ent emgefreek e Markdown"
|
|
||||||
AUTO_URL_LINKS: "Ereoù URL emgefreek"
|
|
||||||
AUTO_URL_LINKS_HELP: "Gweredekaat amdroadur emgefreek an URLoù da ereoù HTML"
|
|
||||||
ESCAPE_MARKUP: "Gwareziñ an HTML"
|
|
||||||
ESCAPE_MARKUP_HELP: "Gwareziñ ar c'hlavioù e elfennoù HTML"
|
|
||||||
CACHING_HELP: "Trec'haoler hollek evit (di)weredekaat krubuilh Grav"
|
|
||||||
CACHE_CHECK_METHOD: "Hentenn gwiriekaat ar c'hrubuilh"
|
|
||||||
CACHE_CHECK_METHOD_HELP: "Dibab an hentenn arveret gant Grav evit gwiriekaat m'eo bet kemmer ar restoù pajenn."
|
|
||||||
CACHE_DRIVER: "Sturier Krubuilh"
|
|
||||||
CACHE_DRIVER_HELP: "Dibab pe sturier krubuilh a zo arveret Grav. 'Dinoiñ emgefreek' a glask kavout pe zoare a zo an hini gwellañ"
|
|
||||||
CACHE_PREFIX: "Rakger ar c'hrubuilh"
|
|
||||||
CACHE_PREFIX_HELP: "Lodenn naoudi an alc'hwez Grav. Na gemmit anezhi ma n'ouzit ket petra rit."
|
|
||||||
CACHE_PREFIX_PLACEHOLDER: "Deveret eus an URL diazez (flastret en un enkañ ur chadenn dargouezhek)"
|
|
||||||
LIFETIME: "Padelezh buhez"
|
|
||||||
LIFETIME_HELP: "Arventennañ padelezh ar c'hrubuilh e eilennoù. 0 = anvevenn"
|
|
||||||
GZIP_COMPRESSION: "Koazhadur Gzip"
|
|
||||||
GZIP_COMPRESSION_HELP: "Gweredekaat koazhadur Gzip ar bajenn Grav evit kreskiñ an digonusted."
|
|
||||||
TWIG_TEMPLATING: "Patromiñ Twig"
|
|
||||||
TWIG_CACHING: "Krubuilh Twig"
|
|
||||||
TWIG_CACHING_HELP: "Reoliañ wikefre krubuilh Twig. Laoskit gweredekaet evit an digonusted gwellañ."
|
|
||||||
TWIG_DEBUG: "Diveugañ Twig"
|
|
||||||
TWIG_DEBUG_HELP: "Aotren an dibarzh evit chom hep kargañ an askouezh diveugañ Twig"
|
|
||||||
DETECT_CHANGES: "Dinoiñ ar c'hemmoù"
|
|
||||||
DETECT_CHANGES_HELP: "Adkempunet e vo krubuilh Twig ent emgefreek ma vez dinoet kemmoù er patromoù Twig"
|
|
||||||
AUTOESCAPE_VARIABLES: "Gwareziñ an argemennoù ent emgefreek"
|
|
||||||
AUTOESCAPE_VARIABLES_HELP: "Gwareziñ an holl argemennoù ent emgefreek. Moarvat e torro ho lec'hienn"
|
|
||||||
ASSETS: "Madoù"
|
|
||||||
CSS_PIPELINE: "Arrevellañ CSS"
|
|
||||||
CSS_PIPELINE_HELP: "Arrevellañ ar CSS a zo unvanadur meur a loaz CSS en ur restr hepken"
|
|
||||||
CSS_PIPELINE_INCLUDE_EXTERNALS: "Ebarzhiñ restroù estren en arrevellañ CSS"
|
|
||||||
CSS_PIPELINE_INCLUDE_EXTERNALS_HELP: "URLoù diavaez a zo gant daveoù restroù daveel a-wechoù ha ne rankont ket bezañ arrevellet"
|
|
||||||
CSS_PIPELINE_BEFORE_EXCLUDES: "Deoueziñ an arrevellañ CSS da gentañ"
|
|
||||||
CSS_PIPELINE_BEFORE_EXCLUDES_HELP: "Deoueziñ an arrevellañ CSS a-raok kement dave CSS all ha n'int ket enkorfet"
|
|
||||||
CSS_MINIFY: "Bihanadur CSS"
|
|
||||||
CSS_MINIFY_HELP: "Bihanaat ar CSS e-pad an arrevellañ"
|
|
||||||
CSS_MINIFY_WINDOWS_OVERRIDE: "Amsaviñ bihanadur ar CSS Windows"
|
|
||||||
CSS_MINIFY_WINDOWS_OVERRIDE_HELP: "Amsaviñ ar bihanadur evit savennoù Windows. Faos dre ziouer abalamour da ThreadStackSize"
|
|
||||||
CSS_REWRITE: "Adskrivañ CSS"
|
|
||||||
CSS_REWRITE_HELP: "Adskrivañ kement URL daveel CSS e-pad an arrevellañ"
|
|
||||||
JAVASCRIPT_PIPELINE: "Arrevellañ Javascript"
|
|
||||||
JAVASCRIPT_PIPELINE_HELP: "An arrevellañ JS a zo unvanadur meur a restr JS en ur restr hepken"
|
|
||||||
JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS: "Enkorfañ ar JS diavaez evit an arrevellañ"
|
|
||||||
JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS_HELP: "Urloù diavaez o deus daveoù restroù daveel a-wechoù ha ne rankont ket bezañ arrevellet"
|
|
||||||
JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES: "Arrevellañ JS da gentañ"
|
|
||||||
JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES_HELP: "Deoueziñ an arrevellañ JS a-raok kement dave JS all ha n'int ket enkorfet"
|
|
||||||
JAVASCRIPT_MINIFY: "Bihanat ar javascript"
|
|
||||||
JAVASCRIPT_MINIFY_HELP: "Bihanaat ar JS e-pad an arrevellañ"
|
|
||||||
ENABLED_TIMESTAMPS_ON_ASSETS: "Gweredekaat ar boneg-amzer war al loazioù"
|
|
||||||
ENABLED_TIMESTAMPS_ON_ASSETS_HELP: "Gweredekaat bonegoù-amzer al loazioù"
|
|
||||||
COLLECTIONS: "Dastumadegoù"
|
|
||||||
ERROR_HANDLER: "Dornataour fazioù"
|
|
||||||
DISPLAY_ERRORS: "Skrammañ ar fazioù"
|
|
||||||
DISPLAY_ERRORS_HELP: "Skrammañ ur bajenn fazi gant munudoù"
|
|
||||||
LOG_ERRORS: "Kerzhlevr ar fazioù"
|
|
||||||
LOG_ERRORS_HELP: "Lakaat kerzhlevr ar fazioù en teuliad /logs"
|
|
||||||
DEBUGGER: "Diveuger"
|
|
||||||
DEBUGGER_HELP: "Gweredekaat diveuger Grav hag an arventennoù da heul"
|
|
||||||
DEBUG_TWIG: "Diveugañ Twig"
|
|
||||||
DEBUG_TWIG_HELP: "Gweredekaat diveugañ ar patromoù Twig"
|
|
||||||
SHUTDOWN_CLOSE_CONNECTION: "Shutdown a serr ar c'hennask"
|
|
||||||
SHUTDOWN_CLOSE_CONNECTION_HELP: "Serriñ ar c'hennask a-raok gervel onShutdown(). 'false' evit diveugañ"
|
|
||||||
DEFAULT_IMAGE_QUALITY: "Perzhded skeudenn dre ziouer"
|
|
||||||
DEFAULT_IMAGE_QUALITY_HELP: "Perzhded skeudenn dre ziouer da arverañ e-pad adstandilhonañ ar skeudennoù (85%)"
|
|
||||||
CACHE_ALL: "Lakaat an holl skeudennoù er c'hrubuilh"
|
|
||||||
CACHE_ALL_HELP: "Lakaat an holl skeudennoù da dremen dre reizhiad krubuilh Grav zoken ma n'o deus dornatadur media ebet"
|
|
||||||
IMAGES_DEBUG: "Rouedigell diveugañ ar skeudenn"
|
|
||||||
IMAGES_DEBUG_HELP: "Diskouez un diflugell a-us d'ar skeudennoù a ziskouez an donder piksel pa labourer war Retina da skouer"
|
|
||||||
UPLOAD_LIMIT: "Bevenn ment ar restroù da bellgas"
|
|
||||||
UPLOAD_LIMIT_HELP: "Lakaat ar ment restroù uhelañ e eizhbitoù (0 a zo anvevenn)"
|
|
||||||
ENABLE_MEDIA_TIMESTAMP: "Gweredekaat ar boneg-amzer war ar media"
|
|
||||||
ENABLE_MEDIA_TIMESTAMP_HELP: "Ouzhpennañ ur boneg-amzer diazezet war an deiziad kemmadur evit pep elfenn media"
|
|
||||||
SESSION: "Estez"
|
|
||||||
SESSION_ENABLED_HELP: "Gweredekaat skor an estez evit Grav"
|
|
||||||
SESSION_NAME_HELP: "Un naoudi arveret da stummañ anv toupin an estez"
|
|
||||||
ABSOLUTE_URLS: "URL dizave"
|
|
||||||
ABSOLUTE_URLS_HELP: "URLoù dizave pe daveel evit 'base_url'"
|
|
||||||
PARAMETER_SEPARATOR: "Disranner arventenn"
|
|
||||||
PARAMETER_SEPARATOR_HELP: "An disranner evit an arventennoù tremenet a c'hall bezañ kemmet evit Apache war Windows"
|
|
||||||
TASK_COMPLETED: "Trevell echuet"
|
|
||||||
EVERYTHING_UP_TO_DATE: "Pep tra a zo hizivaet"
|
|
||||||
UPDATES_ARE_AVAILABLE: "hizivadennoù hegerz"
|
|
||||||
IS_AVAILABLE_FOR_UPDATE: "a zo gant un hizivadenn hegerz"
|
|
||||||
IS_NOW_AVAILABLE: "a zo hegerz"
|
|
||||||
CURRENT: "Bremanel"
|
|
||||||
UPDATE_GRAV_NOW: "Hizivaat Grav bremañ"
|
|
||||||
GRAV_SYMBOLICALLY_LINKED: "Gant un ere arouezel eo staliet Grav. Dihegerz eo an hizivadenn"
|
|
||||||
UPDATING_PLEASE_WAIT: "Oc'h hizivaat... gortozit, emañ o pellgargañ"
|
|
||||||
OF_THIS: "eus an"
|
|
||||||
OF_YOUR: "eus ho"
|
|
||||||
HAVE_AN_UPDATE_AVAILABLE: "en deus un hizivadenn hegerz"
|
|
||||||
SAVE_AS: "Enrollañ evel"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_DESC: "Sur oc'h e fell deoc'h dilemel ar bajenn-mañ hag holl he bugale? M'eo troet ar bajenn en ur yezh all e vo miret an troidigezhioù a rankout a reot o dilemel en un doare distag. E mod all e vo dilamet teuliad ar bajenn gant an is-pajennoù. N'haller ket dizober ar gwered-mañ."
|
|
||||||
AND: "ha"
|
|
||||||
UPDATE_AVAILABLE: "Hizivadenn hegerz"
|
|
||||||
METADATA_KEY: "Alc'hwez (sk. 'Gerioù-alc'hwez')"
|
|
||||||
METADATA_VALUE: "Gwerzh (sk. 'Blog, Grav')"
|
|
||||||
USERNAME_HELP: "Etre 3 ha 16 arouezenn e rank an anv arveriad bezañ o kontañ al lizherennoù bihan, an niverennoù, an islinennoù hag ar barrennigoù. N'eo ket aotreet al lizherennoù bras, an esaouennoù hag an arouezennoù arbennik"
|
|
||||||
FULLY_UPDATED: "Hizivaet"
|
|
||||||
SAVE_LOCATION: "Lec'hiadur enrollañ"
|
|
||||||
PAGE_FILE: "Patrom pajenn"
|
|
||||||
PAGE_FILE_HELP: "Anv restr patrom ar bajenn, ha patrom skrammañ ar bajenn dre ziouer"
|
|
||||||
NO_USER_ACCOUNTS: "Kont arveriad ebet kavet, krouit unan da gentañ..."
|
|
||||||
REDIRECT_TRAILING_SLASH: "Adheñchañ ar veskell dibenn"
|
|
||||||
REDIRECT_TRAILING_SLASH_HELP: "Ober un adheñchañ 301 e-lerc'h merañ an beskell dibenn an URI en un doare treuzwelus."
|
|
||||||
DEFAULT_DATE_FORMAT: "Mentrezh deiziad ar bajenn"
|
|
||||||
DEFAULT_DATE_FORMAT_HELP: "Mentrezh deiziad ar bajenn arveret gant Grav. Dre ziouer, Grav a glask divinout mentrezh an deiziad met gallout a rit erspizañ unan gant kevreadur deiziad PHP (sk.: Y-m-d H:i)"
|
|
||||||
DEFAULT_DATE_FORMAT_PLACEHOLDER: "Divinout en emgefreek"
|
|
||||||
IGNORE_FILES: "Leuskel restroù a-gostez"
|
|
||||||
IGNORE_FILES_HELP: "Restroù da leuskel a-gostez e-pad keweriañ ar pajennoù"
|
|
||||||
IGNORE_FOLDERS: "Leuskel teuliadoù a-gostez"
|
|
||||||
IGNORE_FOLDERS_HELP: "Teuliadoù resis da leuskel a-gostez e-pad keweriañ ar pajennoù"
|
|
||||||
HTTP_ACCEPT_LANGUAGE: "Lakaat yezh ar merdeer"
|
|
||||||
HTTP_ACCEPT_LANGUAGE_HELP: "Gallout a rit klask arventennañ ar yezh gant hini ar talbenn `http_accept_language` ar merdeer"
|
|
||||||
OVERRIDE_LOCALE: "Flastrañ ar yezh"
|
|
||||||
OVERRIDE_LOCALE_HELP: "Flastrañ arventenn yezh PHP diazezet war ar yezh vremanel"
|
|
||||||
REDIRECT: "Adheñchañ ar bajenn"
|
|
||||||
REDIRECT_HELP: "Enankit hent ur bajenn pe un URL diavaez da adheñchañ ar bajenn. Sk. '/un/hent' pe 'http://ulload.bzh'"
|
|
||||||
PLUGIN_STATUS: "Stad an elugellad"
|
|
||||||
INCLUDE_DEFAULT_LANG: "Enkorfañ ar yezh dre ziouer"
|
|
||||||
INCLUDE_DEFAULT_LANG_HELP: "Ouzhpennañ a raio ar yezh dre ziouer en holl URLoù er yezh dre ziouer. Sk. '/br/blog/post'"
|
|
||||||
ALLOW_URL_TAXONOMY_FILTERS: "URL siloù rummad"
|
|
||||||
ALLOW_URL_TAXONOMY_FILTERS_HELP: "Dastumadegoù pajennoù a aotren ac'hanoc'h da silañ dre '/rummad:gwerzh'."
|
|
||||||
REDIRECT_DEFAULT_CODE: "Boneg adheñchan dre ziouer"
|
|
||||||
REDIRECT_DEFAULT_CODE_HELP: "Boneg stad HTTP da arverañ evit adheñchañ"
|
|
||||||
IGNORE_HIDDEN: "Leuskel ar re kuzhet a-gostez"
|
|
||||||
IGNORE_HIDDEN_HELP: "Leuskel an holl restroù ha teuliadoù a grog gant ur POENT"
|
|
||||||
WRAPPED_SITE: "Lec'hienn enkorfet"
|
|
||||||
WRAPPED_SITE_HELP: "Evit ma ouife an neuzioù/enlugelladoù m'eo enkorfet Grav en ur savenn all"
|
|
||||||
FALLBACK_TYPES: "Aotren doareoù fallback"
|
|
||||||
FALLBACK_TYPES_HELP: "Doareoù restr aotreet a c'hall bezañ kavet m'int haezet dre hent ar bajenn. An holl zoareoù media skoret dre ziouer."
|
|
||||||
INLINE_TYPES: "Doareoù fallback enkorfet"
|
|
||||||
INLINE_TYPES_HELP: "Ur roll doareoù restroù a rank bezañ skrammet en un doare enkorfet kentoc'h eget pellgarget"
|
|
||||||
APPEND_URL_EXT: "Ouzhpennañ an astenn d'an URL"
|
|
||||||
APPEND_URL_EXT_HELP: "Ouzhpennañ a raio un astenn personelaet da URL ar bajenn. Talvezout a ra e glasko Grav ur patrom anvet `<patrom>.<astenn>.twig`"
|
|
||||||
PAGE_MODES: "Modoù pajenn"
|
|
||||||
PAGE_TYPES: "Doareoù pajenn"
|
|
||||||
ACCESS_LEVELS: "Liveoù haeziñ"
|
|
||||||
GROUPS: "Strolladoù"
|
|
||||||
GROUPS_HELP: "Roll ar strolladoù gant an arveriad enno"
|
|
||||||
ADMIN_ACCESS: "Haeziñ ardoer"
|
|
||||||
SITE_ACCESS: "Haeziñ d'al lec'hienn"
|
|
||||||
INVALID_SECURITY_TOKEN: "Reveziadenn diogelroez didalvoudek"
|
|
||||||
ACTIVATE: "Gweredekaat"
|
|
||||||
TWIG_UMASK_FIX: "Ratreadur Umask"
|
|
||||||
TWIG_UMASK_FIX_HELP: "Twig a grou ar restroù krubuilh gant 0755 dre ziouer, ar ratreañ a lak anezho da 0755"
|
|
||||||
CACHE_PERMS: "Aotreoù ar c'hrubuilh"
|
|
||||||
CACHE_PERMS_HELP: "Aotreoù dre ziouer teuliad ar c'hrubuilh. 0755 pe 0775 peurvuiañ, hervez ar c'hefluniadur"
|
|
||||||
REMOVE_SUCCESSFUL: "Dilamet gant berzh"
|
|
||||||
REMOVE_FAILED: "C'hwitadenn war an dilemel"
|
|
||||||
HIDE_HOME_IN_URLS: "Kuzhat hent ar pennbajenn en URL"
|
|
||||||
HIDE_HOME_IN_URLS_HELP: "Gwiriekaat a raio n'eo ket daveet hent skoueriek an degemer gant hentoù dre ziouer ar pajennoù dindan an degemer"
|
|
||||||
TWIG_FIRST: "Keweriañ an Twig da gentañ"
|
|
||||||
TWIG_FIRST_HELP: "M'ho peus gweredekaat keweriañ ar bajenn Twig e c'hallit kefluniañ Twig evit e geweriañ a-raok pe goude ar Markdown"
|
|
||||||
SESSION_SECURE: "Diogel"
|
|
||||||
SESSION_SECURE_HELP: "M'eo gwir, diskouez a ra eo ret d'ar c'hehentiñ evit an toupin-mañ bezañ graet war un treuzkas diogel. DIWALLIT: Gweredekait an dra-se war lec'hiennoù e HTTPS nemetken"
|
|
||||||
SESSION_HTTPONLY: "HTTP nemetken"
|
|
||||||
SESSION_HTTPONLY_HELP: "M'eo gwir, diskouez a ra eo ret d'ar c'hehentiñ evit an toupin-mañ bezañ graet war un treuzkas HTTP ha n'eo ket aotreet kemmañ ar Javascript"
|
|
||||||
REVERSE_PROXY: "Proksi en tu-gin"
|
|
||||||
REVERSE_PROXY_HELP: "Gweredekait an dra-se m'hoc'h a-dreñv ur proksi en tu-gin hag ho peus diaesterioù gant an URLoù oc'h enderc'hel ur porzh didalvoudek"
|
|
||||||
INVALID_FRONTMATTER_COULD_NOT_SAVE: "Frontmatter didalvoudek, n'haller ket enrollan"
|
|
||||||
ADD_FOLDER: "Ouzhpennañ un teuliad"
|
|
||||||
PROXY_URL: "URL ar proksi"
|
|
||||||
PROXY_URL_HELP: "Enankit HERBERC'HIER pe IP ar proksi hag ar PORZH"
|
|
||||||
NOTHING_TO_SAVE: "Netra da enrollañ"
|
|
||||||
FILE_ERROR_ADD: "Degouezhet ez eus bet ur fazi en ur glask enrollañ ar restr"
|
|
||||||
FILE_ERROR_UPLOAD: "Degouezhet ez eus bet ur fazi en ur glask pellgas ar restr"
|
|
||||||
FILE_UNSUPPORTED: "Doare restr anskor"
|
|
||||||
ADD_ITEM: "Ouzhpennañ un elfenn"
|
|
||||||
FILE_TOO_LARGE: "Re leden eo ar restr evit bezañ pellgaset. %s eo an uhelañ aotreet hervez <br> hoc'h arventennoù PHP. Kreskit an arventenn PHP`post_max_size`"
|
|
||||||
INSTALLING: "O staliañ"
|
|
||||||
LOADING: "O kargañ.."
|
|
||||||
DEPENDENCIES_NOT_MET_MESSAGE: "Ret eo deoc'h staliañ an amzalc'hoù da-heul a-raok:"
|
|
||||||
ERROR_INSTALLING_PACKAGES: "Fazi en ur staliañ ar pakad(où)"
|
|
||||||
INSTALLING_DEPENDENCIES: "O staliañ an amzalc'hoù..."
|
|
||||||
INSTALLING_PACKAGES: "O staliañ ar pakad(où).."
|
|
||||||
PACKAGES_SUCCESSFULLY_INSTALLED: "Pakad(où) staliet gant berzh."
|
|
||||||
READY_TO_INSTALL_PACKAGES: "Prest da staliañ ar pakad(où)"
|
|
||||||
PACKAGES_NOT_INSTALLED: "N'eo ket stalied ar pakadoù"
|
|
||||||
PACKAGES_NEED_UPDATE: "Staliet eo ar pakadoù endeo, met re gozh eo"
|
|
||||||
PACKAGES_SUGGESTED_UPDATE: "Staliet eo ar pakadoù endeo, dereat eo an handelv, met hizivaet e vint evit ma vefec'h en handelv diwezhañ"
|
|
||||||
REMOVE_THE: "Dilemel an %s"
|
|
||||||
CONFIRM_REMOVAL: "Sur oc'h e fell deoc'h dilemel %s?"
|
|
||||||
REMOVED_SUCCESSFULLY: "%s dilamet gant berzh"
|
|
||||||
ERROR_REMOVING_THE: "Fazi en ur zilemel %s"
|
|
||||||
ADDITIONAL_DEPENDENCIES_CAN_BE_REMOVED: "An amzalc'hoù da heul a zo azgoulennet gant %s, met n'eo ket azgoulennet gant ur pakad all. Ma ne arverit ket anezho e c'hallit o dilemel adalek amañ."
|
|
||||||
READY_TO_UPDATE_PACKAGES: "Prest da hizivaat ar pakad(où)"
|
|
||||||
ERROR_UPDATING_PACKAGES: "Fazi en ur hizivaat ar pakad(où)"
|
|
||||||
UPDATING_PACKAGES: "Oc'h hizivaat ar pakad(où).."
|
|
||||||
PACKAGES_SUCCESSFULLY_UPDATED: "Pakad(où) hizivaet gant berzh."
|
|
||||||
UPDATING: "Hizivaet"
|
|
||||||
GPM_RELEASES: "Ermaeziadennoù GPM"
|
|
||||||
GPM_RELEASES_HELP: "Dibabit 'Amprouiñ' evit staliañ an handelv beta pe amprouiñ"
|
|
||||||
AUTO: "Oto"
|
|
||||||
FOPEN: "fopen"
|
|
||||||
CURL: "cURL"
|
|
||||||
STABLE: "Stabil"
|
|
||||||
TESTING: "Amprouiñ"
|
|
||||||
FRONTMATTER_PROCESS_TWIG: "Keweriañ frontmatter Twig"
|
|
||||||
FRONTMATTER_PROCESS_TWIG_HELP: "P'eo oberiant e c'hallit arverañ argemennoù kefluniañ Twig e frontmatter ar bajenn"
|
|
||||||
FRONTMATTER_IGNORE_FIELDS: "Leuskel maeziennoù Frontmatter a-gostez"
|
|
||||||
FRONTMATTER_IGNORE_FIELDS_HELP: "Maeziennoù Frontmatter a c'hall enderc'hel Twig met ne rankont ket bezañ keweriet, evel 'forms'"
|
|
||||||
PACKAGE_X_INSTALLED_SUCCESSFULLY: "Pakad %s staliet gant berzh"
|
|
||||||
ORDERING_DISABLED_BECAUSE_PARENT_SETTING_ORDER: "Urzh ar c'har, diweredekaet eo an urzhiañ"
|
|
||||||
ORDERING_DISABLED_BECAUSE_PAGE_NOT_VISIBLE: "Diwelus eo ar bajenn, diweredekaet eo an urzhiañ"
|
|
||||||
ORDERING_DISABLED_BECAUSE_TOO_MANY_SIBLINGS: "N'eo ket skoret an urzhiañ dre an ardeiñ dre ma zo ouzhpenn 200 c'hoar"
|
|
||||||
CANNOT_ADD_MEDIA_FILES_PAGE_NOT_SAVED: "EVEZHIADENN: n'hallit ket ouzhpennañ restroù media evit enrollañ ar bajenn. Klikit war 'Enrollañ' a-us"
|
|
||||||
CANNOT_ADD_FILES_PAGE_NOT_SAVED: "EVEZHIADENN: ret eo enrollañ ar bajenn a-raok pellgas restroù dezhi."
|
|
||||||
DROP_FILES_HERE_TO_UPLOAD: "Lakait ho restroù amañ pe <strong>klikit amañ</strong>"
|
|
||||||
INSERT: "Enlakaat"
|
|
||||||
UNDO: "Dizober"
|
|
||||||
REDO: "Adober"
|
|
||||||
HEADERS: "Talbennoù"
|
|
||||||
BOLD: "Tev"
|
|
||||||
ITALIC: "Stouet"
|
|
||||||
STRIKETHROUGH: "Barrennet"
|
|
||||||
SUMMARY_DELIMITER: "Bonner diverrad"
|
|
||||||
LINK: "Liamm"
|
|
||||||
IMAGE: "Skeudenn"
|
|
||||||
BLOCKQUOTE: "Meneg"
|
|
||||||
UNORDERED_LIST: "Roll dizurzh"
|
|
||||||
ORDERED_LIST: "Roll urzhiet"
|
|
||||||
EDITOR: "Embanner"
|
|
||||||
PREVIEW: "Alberz"
|
|
||||||
FULLSCREEN: "Skramm a-bezh"
|
|
||||||
NON_ROUTABLE: "Dihentus"
|
|
||||||
NON_VISIBLE: "Diwelus"
|
|
||||||
NON_PUBLISHED: "Diembannet"
|
|
||||||
CHARACTERS: "arouezioù"
|
|
||||||
PUBLISHING: "Embann"
|
|
||||||
LEGEND: "Alc'hwez ar bajenn"
|
|
||||||
MEMCACHE_SERVER: "Servijer Memcached"
|
|
||||||
MEMCACHE_SERVER_HELP: "Chomlec'h ar servijer Memcached"
|
|
||||||
MEMCACHE_PORT: "Porzh Memcached"
|
|
||||||
MEMCACHE_PORT_HELP: "Porzh ar servijer Memcached"
|
|
||||||
MEMCACHED_SERVER: "Servijer Memcached"
|
|
||||||
MEMCACHED_SERVER_HELP: "Chomlec'h ar servijer Memcached"
|
|
||||||
MEMCACHED_PORT: "Porzh Memcached"
|
|
||||||
MEMCACHED_PORT_HELP: "Porzh ar servijer Memcached"
|
|
||||||
REDIS_SERVER: "Servijer Redis"
|
|
||||||
REDIS_SERVER_HELP: "Chomlec'h ar servijer Redis"
|
|
||||||
REDIS_PORT: "Porzh Redis"
|
|
||||||
REDIS_PORT_HELP: "Porzh ar servijer Redis"
|
|
||||||
ALL: "Tout"
|
|
||||||
FROM: "eus"
|
|
||||||
TO: "da"
|
|
||||||
RESOURCE_FILTER: "Sil..."
|
|
||||||
FORCE_SSL: "Forsañ SSL"
|
|
||||||
DROPZONE_CANCEL_UPLOAD: 'Nullañ ar gargamant'
|
|
||||||
DROPZONE_REMOVE_FILE: "Dilemel ar fichenn"
|
|
||||||
PREMIUM_PRODUCT: "Premium"
|
|
||||||
ERROR_SIMPLE: "Fazi simpl"
|
|
||||||
ERROR_SYSTEM: "Fazi Sistem"
|
|
||||||
NOT_SET: "Pas termenet"
|
|
||||||
PERMISSIONS: "Permisionoù"
|
|
||||||
REINSTALL_PLUGIN: "Adstaliañ ar Plugin"
|
|
||||||
REINSTALL_THEME: "Adstaliañ an Tem"
|
|
||||||
REINSTALL_THE: "Adstaliañ ar %s"
|
|
||||||
REINSTALLATION_FAILED: "Adstaliañ c'hwitet"
|
|
||||||
TOOLS: "Ostilhoù"
|
|
||||||
DIRECT_INSTALL: "Staliañ war-eeun"
|
|
||||||
2FA_CODE_INPUT: "000000"
|
|
||||||
CONFIGURATION: "Kefluniadur"
|
|
||||||
TIMEOUT: "Diamzeriñ"
|
|
||||||
TIMEOUT_HELP: "Lakaat an amzer diamzeriñ e eilennoù"
|
|
||||||
DASHBOARD: "Taolenn labour"
|
|
||||||
NOTIFICATIONS: "Notifiadenn"
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,88 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
ADMIN_BETA_MSG: "Mae hwn yn fersiwn beta! Defnyddio hwn yn cynhyrchu ar risg eich hun..."
|
|
||||||
ADMIN_REPORT_ISSUE: "Canfod problem? Rhowch wybod ar GitHub."
|
|
||||||
LOGIN_BTN: "Mewngofnodi"
|
|
||||||
LOGIN_BTN_FORGOT: "Anghofio"
|
|
||||||
LOGIN_BTN_RESET: "Ailosod cyfrinair"
|
|
||||||
LOGIN_BTN_SEND_INSTRUCTIONS: "Anfon cyfarwyddiadau ailosod"
|
|
||||||
LOGIN_BTN_CLEAR: "Ffurflen clir"
|
|
||||||
LOGIN_BTN_CREATE_USER: "Creu defnyddiwr"
|
|
||||||
LOGIN_LOGGED_IN: "Wedi eich mewngofnodi llwyddiannus"
|
|
||||||
LOGIN_FAILED: "Wedi methu mewngofnodi"
|
|
||||||
LOGGED_OUT: "Chi allgofnodi"
|
|
||||||
RESET_LINK_EXPIRED: "Ailosod cysylltiad wedi dod i ben, rhowch gynnig arall arni"
|
|
||||||
RESET_PASSWORD_RESET: "Mae wedi'i ailosod cyfrinair"
|
|
||||||
RESET_INVALID_LINK: "Mae annilys yn ailosod cyswllt a ddefnyddir, rhowch gynnig arni eto"
|
|
||||||
FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Mae cyfarwyddiadau i ailosod eich cyfrinair wedi'u hanfon drwy e-bost at %s"
|
|
||||||
FORGOT_FAILED_TO_EMAIL: "Wedi methu anfon e-bost cyfarwyddiadau, rhowch gynnig arall arni rywbryd eto"
|
|
||||||
FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Does dim modd ailosod cyfrinair %s, pennir nad oes cyfeiriad e-bost"
|
|
||||||
FORGOT_USERNAME_DOES_NOT_EXIST: "Nid yw'r defnyddiwr gyda'r enw defnyddiwr <b>%s</b> yn bodoli"
|
|
||||||
FORGOT_EMAIL_NOT_CONFIGURED: "Does dim modd ailosod cyfrinair. Nid yw'r safle hwn wedi'i ffurfweddu i anfon negeseuon e-bost"
|
|
||||||
FORGOT_EMAIL_SUBJECT: "Cais ailosod cyfrinair %s"
|
|
||||||
FORGOT_EMAIL_BODY: "<h1>Ailosod cyfrinair</h1> <p>%1$s Annwyl,</p> <p>Gwnaed cais ar <b>%4$s</b> i ailosod eich cyfrinair.</p> <p>< br / > <a href=\"%2$s\" class=\"btn-primary\"> hyn i ailosod eich cyfrinair cliciwch</a> < br / > < br / ></p> <p>Fel arall, gopïo URL canlynol i'r bar cyfeiriad eich porwr:</p> <p>%2$s</p> <p>< br / > Cofion, < br / > < br / >%3$s</p>"
|
|
||||||
MANAGE_PAGES: "Rheoli tudalennau"
|
|
||||||
PAGES: "Tudalennau"
|
|
||||||
PLUGINS: "Ategion"
|
|
||||||
PLUGIN: "Ategyn"
|
|
||||||
THEMES: "Themâu"
|
|
||||||
LOGOUT: "Allgofnodi"
|
|
||||||
BACK: "Yn ôl"
|
|
||||||
ADD_PAGE: "Ychwanegu Tudalen"
|
|
||||||
MOVE: "Symud"
|
|
||||||
DELETE: "Dileu"
|
|
||||||
SAVE: "Cadw"
|
|
||||||
NORMAL: "Arferol"
|
|
||||||
EXPERT: "Arbenigol"
|
|
||||||
EXPAND_ALL: "Ehangu'r cyfan"
|
|
||||||
COLLAPSE_ALL: "Crebachu'r cyfan"
|
|
||||||
ERROR: "Gwall"
|
|
||||||
CLOSE: "Cau"
|
|
||||||
CANCEL: "Canslo"
|
|
||||||
CONTINUE: "Yn parhau"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Cadarnhad sydd yn ofynnol"
|
|
||||||
MODAL_CHANGED_DETECTED_TITLE: "Ganfod newidiadau"
|
|
||||||
MODAL_CHANGED_DETECTED_DESC: "Wedi ichi golli'r newidiadau. Ydych chi'n siŵr eich bod am adael heb arbed?"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE: "Cadarnhad sydd yn ofynnol"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC: "Ydych chi'n siŵr eich bod am ddileu'r ffeil hon? Ni ellir dad-wneud y cam gweithredu hwn."
|
|
||||||
ADD_FILTERS: "Ychwanegu hidlydd"
|
|
||||||
SEARCH_PAGES: "Tudalennau chwilio"
|
|
||||||
VERSION: "Fersiwn"
|
|
||||||
WAS_MADE_WITH: "Wedi greu hefo"
|
|
||||||
BY: "Gan"
|
|
||||||
AUTHOR: "Awdur"
|
|
||||||
HOMEPAGE: "Hafan"
|
|
||||||
KEYWORDS: "Allweddeiriau"
|
|
||||||
LICENSE: "Trwydded"
|
|
||||||
DESCRIPTION: "Disgrifiad"
|
|
||||||
THEME: "Thema"
|
|
||||||
BACK_TO_THEMES: "Ôl i themâu"
|
|
||||||
BACK_TO_PLUGINS: "Ôl i ategion"
|
|
||||||
CHECK_FOR_UPDATES: "Chwilio am ddiweddariadau"
|
|
||||||
ADD: "Ychwanegu"
|
|
||||||
CLEAR_CACHE: "Clirio storfa"
|
|
||||||
CLEAR_CACHE_ALL_CACHE: "Holl storfa"
|
|
||||||
CLEAR_CACHE_ASSETS_ONLY: "Asedau yn unig"
|
|
||||||
CLEAR_CACHE_IMAGES_ONLY: "Llyniau yn unig"
|
|
||||||
CLEAR_CACHE_CACHE_ONLY: "Storfa yn unig"
|
|
||||||
UPDATES_AVAILABLE: "Diweddariadau ar gael"
|
|
||||||
DAYS: "Diwrnod"
|
|
||||||
UPDATE: "Diweddaru"
|
|
||||||
STATISTICS: "Ystadegau"
|
|
||||||
TODAY: "Heddiw"
|
|
||||||
WEEK: "Wythnos"
|
|
||||||
MONTH: "Mis"
|
|
||||||
UPDATED: "Wedi'w ddiweddaru"
|
|
||||||
MON: "Llu"
|
|
||||||
TUE: "Maw"
|
|
||||||
WED: "Mer"
|
|
||||||
THU: "Iau"
|
|
||||||
FRI: "Gwe"
|
|
||||||
SAT: "Sad"
|
|
||||||
SUN: "Sul"
|
|
||||||
COPY: "Copi"
|
|
||||||
EDIT: "Golygu"
|
|
||||||
CREATE: "Creu"
|
|
||||||
AVAILABLE: "Ar gael"
|
|
||||||
CONFIGURATION: "Ffurfweddiad"
|
|
||||||
DASHBOARD: "Dangosfwrdd"
|
|
||||||
@@ -1,795 +0,0 @@
|
|||||||
---
|
|
||||||
PLUGIN_ADMIN:
|
|
||||||
ADMIN_NOSCRIPT_MSG: "Aktivér JavaScript i din browser."
|
|
||||||
ADMIN_BETA_MSG: "Dette er en beta-udgivelse! Brug i produktionsmiljøer er på egen risiko..."
|
|
||||||
ADMIN_REPORT_ISSUE: "Har du fundet et problem? Så bedes du rapportere det på GitHub."
|
|
||||||
EMAIL_FOOTER: "<a href=\"https://getgrav.org\">Drevet af Grav</a> - det moderne fladfil-CMS"
|
|
||||||
LOGIN_BTN: "Login"
|
|
||||||
LOGIN_BTN_FORGOT: "Glemt"
|
|
||||||
LOGIN_BTN_RESET: "Nulstil adgangskode"
|
|
||||||
LOGIN_BTN_SEND_INSTRUCTIONS: "Send nulstillingsinstruktioner"
|
|
||||||
LOGIN_BTN_CLEAR: "Ryd formular"
|
|
||||||
LOGIN_BTN_CREATE_USER: "Opret bruger"
|
|
||||||
LOGIN_LOGGED_IN: "Du er nu logget ind"
|
|
||||||
LOGIN_FAILED: "Login fejlede"
|
|
||||||
LOGGED_OUT: "Du er nu logget ud"
|
|
||||||
RESET_NEW_PASSWORD: "Skriv venligst en ny adgangskode"
|
|
||||||
RESET_LINK_EXPIRED: "Nulstillingslinket er udløbet; prøv venligst igen"
|
|
||||||
RESET_PASSWORD_RESET: "Adgangskoden er blevet nulstillet"
|
|
||||||
RESET_INVALID_LINK: "Du har benyttet et ugyldigt nulstillingslink; prøv venligst igen"
|
|
||||||
FORGOT_INSTRUCTIONS_SENT_VIA_EMAIL: "Vejledning i at nulstille din adgangskode er sendt via e-mail til %s"
|
|
||||||
FORGOT_FAILED_TO_EMAIL: "Mislykkedes at maile vejledninger, forsøg venligst igen senere"
|
|
||||||
FORGOT_CANNOT_RESET_EMAIL_NO_EMAIL: "Kan ikke nulstille adgangskode til %s; der er ikke angivet en e-mail-adresse"
|
|
||||||
FORGOT_USERNAME_DOES_NOT_EXIST: "Der findes ikke en bruger med brugernavnet <b>%s</b>"
|
|
||||||
FORGOT_EMAIL_NOT_CONFIGURED: "Kan ikke nulstille adgangskoden. Dette site er ikke konfigureret til at sende e-mails"
|
|
||||||
FORGOT_EMAIL_SUBJECT: "%s Anmodning om nulstilling af adgangskode"
|
|
||||||
FORGOT_EMAIL_BODY: "<h1>Adgangskodenulstilling</h1><p>Hej %1$s</p><p>Der blev den<b>%4$s</b> anmodet om at nulstille din adgangskode.</p><p><br /><a href=\"%2$s\" class=\"btn-primary\">Klik her for at gennemføre adgangskodenulstillingen</a><br /><br /></p><p>Alternativt kan du indsætte flg. URL i din browsers adressebjælke:</p> <p>%2$s</p><p><br />Venlig hilsen,<br /><br />%3$s</p>"
|
|
||||||
MANAGE_PAGES: "Administrer sider"
|
|
||||||
PAGES: "Sider"
|
|
||||||
PLUGINS: "Plugins"
|
|
||||||
PLUGIN: "Plugin"
|
|
||||||
THEMES: "Temaer"
|
|
||||||
LOGOUT: "Logud"
|
|
||||||
BACK: "Tilbage"
|
|
||||||
NEXT: "Næste"
|
|
||||||
PREVIOUS: "Foregående"
|
|
||||||
ADD_PAGE: "Tilføj side"
|
|
||||||
MOVE: "Flyt"
|
|
||||||
DELETE: "Slet"
|
|
||||||
UNSET: "Ikke-indstillet"
|
|
||||||
VIEW: "Se"
|
|
||||||
SAVE: "Gem"
|
|
||||||
NORMAL: "Normal"
|
|
||||||
EXPERT: "Ekspert"
|
|
||||||
EXPAND_ALL: "Udfold alle"
|
|
||||||
COLLAPSE_ALL: "Sammenfold alle"
|
|
||||||
ERROR: "Fejl"
|
|
||||||
CLOSE: "Luk"
|
|
||||||
CANCEL: "Annullér"
|
|
||||||
CONTINUE: "Fortsæt"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Bekræftelse kræves"
|
|
||||||
MODAL_CHANGED_DETECTED_TITLE: "Ændringer registreret"
|
|
||||||
MODAL_CHANGED_DETECTED_DESC: "Ændringer er ikke gemt. Sikker på, at du vil fortsætte uden at gemme?"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE: "Bekræftelse kræves"
|
|
||||||
MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_DESC: "Sikker på, at du vil slette denne fil? Handlingen kan ikke fortrydes."
|
|
||||||
ADD_FILTERS: "Tilføj filtre"
|
|
||||||
SEARCH_PAGES: "Søg efter sider"
|
|
||||||
VERSION: "Version"
|
|
||||||
WAS_MADE_WITH: "Blev lavet med"
|
|
||||||
BY: "Af"
|
|
||||||
UPDATE_THEME: "Opdatere tema"
|
|
||||||
UPDATE_PLUGIN: "Opdater Plugin"
|
|
||||||
OF_THIS_THEME_IS_NOW_AVAILABLE: "af dette tema er nu tilgængelig"
|
|
||||||
OF_THIS_PLUGIN_IS_NOW_AVAILABLE: "af dette plugin er nu tilgængelig"
|
|
||||||
AUTHOR: "Forfatter"
|
|
||||||
HOMEPAGE: "Websted"
|
|
||||||
DEMO: "Demo"
|
|
||||||
BUG_TRACKER: "Sporing af fejl"
|
|
||||||
KEYWORDS: "Nøgleord"
|
|
||||||
LICENSE: "Licens"
|
|
||||||
DESCRIPTION: "Beskrivelse"
|
|
||||||
README: "Læs-mig"
|
|
||||||
REMOVE_THEME: "Fjern Tema"
|
|
||||||
INSTALL_THEME: "Installer Tema"
|
|
||||||
THEME: "Tema"
|
|
||||||
BACK_TO_THEMES: "Tilbage til Temaer"
|
|
||||||
BACK_TO_PLUGINS: "Tilbage til Plugins"
|
|
||||||
CHECK_FOR_UPDATES: "Søg efter Opdateringer"
|
|
||||||
ADD: "Tilføj"
|
|
||||||
CLEAR_CACHE: "Ryd Cache"
|
|
||||||
CLEAR_CACHE_ALL_CACHE: "Alle Caches"
|
|
||||||
CLEAR_CACHE_ASSETS_ONLY: "Kun Aktiver"
|
|
||||||
CLEAR_CACHE_IMAGES_ONLY: "Kun Billeder"
|
|
||||||
CLEAR_CACHE_CACHE_ONLY: "Kun Cache"
|
|
||||||
CLEAR_CACHE_TMP_ONLY: "Kun tmp"
|
|
||||||
UPDATES_AVAILABLE: "Opdateringer tilgængelige"
|
|
||||||
DAYS: "Dage"
|
|
||||||
UPDATE: "Opdatér"
|
|
||||||
BACKUP: "Backup"
|
|
||||||
BACKUPS: "Sikkerhedskopier"
|
|
||||||
BACKUP_NOW: "Sikkerhedskopiér nu"
|
|
||||||
BACKUPS_STATS: "Sikkerhedskopieringsstatistik"
|
|
||||||
BACKUPS_HISTORY: "Sikkerhedskopieringshistorik"
|
|
||||||
BACKUPS_PURGE_CONFIG: "Opsætning, Sikkerhedskopieringsrensning"
|
|
||||||
BACKUPS_PROFILES: "Sikkerhedskopieringsprofiler"
|
|
||||||
BACKUPS_COUNT: "Antal Sikkerhedskopier"
|
|
||||||
BACKUPS_PROFILES_COUNT: "Antal Profiler"
|
|
||||||
BACKUPS_TOTAL_SIZE: "Forbrugt lagerplads"
|
|
||||||
BACKUPS_NEWEST: "Seneste sikkerhedskopi"
|
|
||||||
BACKUPS_OLDEST: "Ældste sikkerhedskopi"
|
|
||||||
BACKUPS_PURGE: "Rense"
|
|
||||||
BACKUPS_NOT_GENERATED: "Ingen sikkerhedskopier oprettet endnu..."
|
|
||||||
BACKUPS_PURGE_NUMBER: "Benytter %s af %s sikkerhedskopipladser"
|
|
||||||
BACKUPS_PURGE_TIME: "%s dages sikkerhedskopiering resterer"
|
|
||||||
BACKUPS_PURGE_SPACE: "Benytter %s af %s"
|
|
||||||
BACKUP_DELETED: "Sikkerhedskopi blev slettet"
|
|
||||||
BACKUP_NOT_FOUND: "Sikkerhedskopi ikke fundet"
|
|
||||||
BACKUP_DATE: "Sikkerhedskopieringsdato"
|
|
||||||
STATISTICS: "Statistikker"
|
|
||||||
TODAY: "I dag"
|
|
||||||
WEEK: "Uge"
|
|
||||||
MONTH: "Måned"
|
|
||||||
LATEST_PAGE_UPDATES: "Seneste Sideopdateringer"
|
|
||||||
MAINTENANCE: "Vedligeholdelse"
|
|
||||||
UPDATED: "Opdateret"
|
|
||||||
MON: "Man"
|
|
||||||
TUE: "Tirs"
|
|
||||||
WED: "Ons"
|
|
||||||
THU: "Tor"
|
|
||||||
FRI: "Fre"
|
|
||||||
SAT: "Lør"
|
|
||||||
SUN: "Søn"
|
|
||||||
COPY: "Kopiér"
|
|
||||||
EDIT: "Redigér"
|
|
||||||
CREATE: "Opret"
|
|
||||||
GRAV_ADMIN: "Grav Admin"
|
|
||||||
GRAV_OFFICIAL_PLUGIN: "Grav Officielt Plugin"
|
|
||||||
GRAV_OFFICIAL_THEME: "Grav Officielt Tema"
|
|
||||||
PLUGIN_SYMBOLICALLY_LINKED: "Dette plugin er symbolsk linket. Ændringer opdages ikke."
|
|
||||||
THEME_SYMBOLICALLY_LINKED: "Dette tema er symbolsk linket. Ændringer opdaget ikke"
|
|
||||||
REMOVE_PLUGIN: "Fjern Plugin"
|
|
||||||
INSTALL_PLUGIN: "Installér Plugin"
|
|
||||||
AVAILABLE: "Tilgængelig"
|
|
||||||
INSTALLED: "Installeret"
|
|
||||||
INSTALL: "Installér"
|
|
||||||
ACTIVE_THEME: "Aktivt tema"
|
|
||||||
SWITCHING_TO: "Skifte til"
|
|
||||||
SWITCHING_TO_DESCRIPTION: "Der er ingen garanti for, at alle layoutsider understøttes ved skift til andet tema, hvilket potentielt kan forårsage fejl under indlæsning af nævnte sider."
|
|
||||||
SWITCHING_TO_CONFIRMATION: "Vil du forsætte og skifte til temaet"
|
|
||||||
CREATE_NEW_USER: "Opret ny bruger"
|
|
||||||
REMOVE_USER: "Fjern bruger"
|
|
||||||
ACCESS_DENIED: "Adgang nægtet"
|
|
||||||
ACCOUNT_NOT_ADMIN: "din konto har ikke administratorrettigheder"
|
|
||||||
PHP_INFO: "PHP-info"
|
|
||||||
INSTALLER: "Installation"
|
|
||||||
AVAILABLE_THEMES: "Tilgængelige temaer"
|
|
||||||
AVAILABLE_PLUGINS: "Tilgængelige plugins"
|
|
||||||
INSTALLED_THEMES: "Installerede temaer"
|
|
||||||
INSTALLED_PLUGINS: "Installerede plugins"
|
|
||||||
BROWSE_ERROR_LOGS: "Gennemse Fejl-logs"
|
|
||||||
SITE: "Site"
|
|
||||||
INFO: "Info"
|
|
||||||
SYSTEM: "System"
|
|
||||||
USER: "Bruger"
|
|
||||||
ADD_ACCOUNT: "Tilføj konto"
|
|
||||||
SWITCH_LANGUAGE: "Skift Sprog"
|
|
||||||
SUCCESSFULLY_ENABLED_PLUGIN: "Plugin aktiveret"
|
|
||||||
SUCCESSFULLY_DISABLED_PLUGIN: "Plugin deaktiveret"
|
|
||||||
SUCCESSFULLY_CHANGED_THEME: "Standardtema ændret"
|
|
||||||
INSTALLATION_FAILED: "Installation mislykkedes"
|
|
||||||
INSTALLATION_SUCCESSFUL: "Installation fuldført"
|
|
||||||
UNINSTALL_FAILED: "Afinstallation mislykkedes"
|
|
||||||
UNINSTALL_SUCCESSFUL: "Afinstallation fuldført"
|
|
||||||
SUCCESSFULLY_SAVED: "Gemt"
|
|
||||||
SUCCESSFULLY_COPIED: "Kopieret"
|
|
||||||
REORDERING_WAS_SUCCESSFUL: "Rækkefølge ændret"
|
|
||||||
SUCCESSFULLY_DELETED: "Slettet"
|
|
||||||
SUCCESSFULLY_SWITCHED_LANGUAGE: "Sprog skiftet"
|
|
||||||
INSUFFICIENT_PERMISSIONS_FOR_TASK: "Du har ikke tilstrækkelige tilladelser til opgaven"
|
|
||||||
CACHE_CLEARED: "Cache ryddet"
|
|
||||||
METHOD: "Metode"
|
|
||||||
ERROR_CLEARING_CACHE: "Fejl under sletning af cache"
|
|
||||||
AN_ERROR_OCCURRED: "Der opstod en fejl"
|
|
||||||
YOUR_BACKUP_IS_READY_FOR_DOWNLOAD: "Din backup er klar til download"
|
|
||||||
DOWNLOAD_BACKUP: "Download backup"
|
|
||||||
PAGES_FILTERED: "Filtrerede sider"
|
|
||||||
NO_PAGE_FOUND: "Ingen side fundet"
|
|
||||||
INVALID_PARAMETERS: "Ugyldige parametre"
|
|
||||||
NO_FILES_SENT: "Ingen filer sendt"
|
|
||||||
EXCEEDED_FILESIZE_LIMIT: "Størrelsesbegrænsning for PHP-configurationsfil overskredet"
|
|
||||||
UNKNOWN_ERRORS: "Ukendt fejl"
|
|
||||||
EXCEEDED_GRAV_FILESIZE_LIMIT: "Størrelsesbegrænsning for Grav-configurationsfil overskredet"
|
|
||||||
UNSUPPORTED_FILE_TYPE: "Ikke-understøttet filtype"
|
|
||||||
FAILED_TO_MOVE_UPLOADED_FILE: "Kunne ikke flytte den uploadede fil."
|
|
||||||
FILE_UPLOADED_SUCCESSFULLY: "Fil-upload lykkedes"
|
|
||||||
FILE_DELETED: "Filen blev slettet"
|
|
||||||
FILE_COULD_NOT_BE_DELETED: "Filen kunne ikke slettes"
|
|
||||||
FILE_NOT_FOUND: "Filen blev ikke fundet"
|
|
||||||
NO_FILE_FOUND: "Ingen fil blev fundet"
|
|
||||||
FIELD_REORDER_SUCCESSFUL: "Medieordre opdateret for feltet '%s'"
|
|
||||||
FIELD_REORDER_FAILED: "En fejl opstod under lagring af medieordren for feltet '%s'"
|
|
||||||
GRAV_WAS_SUCCESSFULLY_UPDATED_TO: "Grav blev opdateret til"
|
|
||||||
GRAV_UPDATE_FAILED: "Opdatering af Grav mislykkedes"
|
|
||||||
EVERYTHING_UPDATED: "Alt opdateret"
|
|
||||||
UPDATES_FAILED: "Opdateringer mislykkedes"
|
|
||||||
AVATAR_BY: "Avatar af"
|
|
||||||
AVATAR_UPLOAD_OWN: "Eller upload din egen..."
|
|
||||||
LAST_BACKUP: "Seneste backup"
|
|
||||||
FULL_NAME: "Fulde navn"
|
|
||||||
USERNAME: "Brugernavn"
|
|
||||||
EMAIL: "E-mail"
|
|
||||||
USERNAME_EMAIL: "Brugernavn eller e-mail"
|
|
||||||
PASSWORD: "Adgangskode"
|
|
||||||
PASSWORD_CONFIRM: "Bekræft adgangskode"
|
|
||||||
TITLE: "Titel"
|
|
||||||
ACCOUNT: "Konto"
|
|
||||||
EMAIL_VALIDATION_MESSAGE: "Skal være en gyldig e-mail"
|
|
||||||
PASSWORD_VALIDATION_MESSAGE: "Adgangskode skal indeholde minimum ét ciffer, én versal, én minuskel samt udgøres af minimum otte tegn"
|
|
||||||
LANGUAGE: "Sprog"
|
|
||||||
LANGUAGE_HELP: "Opsæt foretrukne sprog"
|
|
||||||
LANGUAGE_DEBUG: "Fejlsøg sprog"
|
|
||||||
LANGUAGE_DEBUG_HELP: "Aktivér fejlsøgning af sprog, som bruger filteret |t twig ved at tilføje en span omkring dem, der kan stiliseres som hjælpe til problemdiagnosticeringer"
|
|
||||||
DEFAULTS: "Standarder"
|
|
||||||
SITE_TITLE: "Sitets Titel"
|
|
||||||
SITE_TITLE_PLACEHOLDER: "Overordnet webstedstitel"
|
|
||||||
SITE_TITLE_HELP: "Sitets standard-titel. Bruges ofte i temaer"
|
|
||||||
SITE_DEFAULT_LANG: "Standardsprog"
|
|
||||||
SITE_DEFAULT_LANG_PLACEHOLDER: "Standardsprog benyttet af temaets <HTML>-etiket"
|
|
||||||
SITE_DEFAULT_LANG_HELP: "Standardsprog benyttet af temaets <HTML>-etiket"
|
|
||||||
DEFAULT_AUTHOR: "Standard-forfatter"
|
|
||||||
DEFAULT_AUTHOR_HELP: "Standard-forfatternavn. Bruges ofte i temaer og sideindhold"
|
|
||||||
DEFAULT_EMAIL: "Standard-e-mail"
|
|
||||||
DEFAULT_EMAIL_HELP: "En standard-e-mail, som der kan henvises til i temaer og på sider"
|
|
||||||
TAXONOMY_TYPES: "Taksonomi-typer"
|
|
||||||
TAXONOMY_TYPES_HELP: "Taksonomi-typer skal defineres her hvis du vil bruge dem på sider"
|
|
||||||
PAGE_SUMMARY: "Side-resume"
|
|
||||||
ENABLED: "Aktiveret"
|
|
||||||
ENABLED_HELP: "Aktiver side-resume (resumeet returnerer det samme som sideindholdet)"
|
|
||||||
'YES': "Ja"
|
|
||||||
'NO': "Nej"
|
|
||||||
SUMMARY_SIZE: "Resume-længde"
|
|
||||||
SUMMARY_SIZE_HELP: "Det antal af en sides karakter, som skal bruges som resume"
|
|
||||||
FORMAT: "Format"
|
|
||||||
FORMAT_HELP: "kort = brug første forekomst af afgrænser eller størrelse; lang = afgrænser ignoreres"
|
|
||||||
SHORT: "Kort"
|
|
||||||
LONG: "Lang"
|
|
||||||
DELIMITER: "Afgrænser"
|
|
||||||
DELIMITER_HELP: "Resume-afgrænseren (standard: '===')"
|
|
||||||
METADATA: "Metadata"
|
|
||||||
METADATA_HELP: "Standard-metadataværdier, som vises på alle sider, medmindre de tilsidesættes af siden"
|
|
||||||
NAME: "Navn"
|
|
||||||
CONTENT: "Indhold"
|
|
||||||
SIZE: "Størrelse"
|
|
||||||
ACTION: "Handling"
|
|
||||||
REDIRECTS_AND_ROUTES: "Omdirigeringer og ruter"
|
|
||||||
CUSTOM_REDIRECTS: "Brugerdefinerede omdirigeringer"
|
|
||||||
CUSTOM_REDIRECTS_HELP: "ruter til omdirigering til andre sider. Gængse regex-erstatninger kan benyttes"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_KEY: "/dit/alias"
|
|
||||||
CUSTOM_REDIRECTS_PLACEHOLDER_VALUE: "/din/omdirigering"
|
|
||||||
CUSTOM_ROUTES: "Tilpassede ruter"
|
|
||||||
CUSTOM_ROUTES_HELP: "ruter til alias til andre sider. Gængs regex-erstatning er gyldig"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_KEY: "/dit/alias"
|
|
||||||
CUSTOM_ROUTES_PLACEHOLDER_VALUE: "/din/rute"
|
|
||||||
FILE_STREAMS: "Filstrømme"
|
|
||||||
DEFAULT: "Standard"
|
|
||||||
PAGE_MEDIA: "Sidemedier"
|
|
||||||
OPTIONS: "Indstillinger"
|
|
||||||
PUBLISHED: "Udgivet"
|
|
||||||
PUBLISHED_HELP: "Som standard offentliggøres en side medmindre du udtrykkeligt sætter published: false eller via en fremtidig publish_date eller fortidig unpublish_date"
|
|
||||||
DATE: "Dato"
|
|
||||||
DATE_HELP: "Dato-variablen tillader dig at sætte en specifik dato associeret med denne side."
|
|
||||||
PUBLISHED_DATE: "Udgivelsesdato"
|
|
||||||
PUBLISHED_DATE_HELP: "Kan give en dato for automatisk at udløse udgivelse."
|
|
||||||
UNPUBLISHED_DATE: "Afpubliceringsdato"
|
|
||||||
UNPUBLISHED_DATE_HELP: "Opsætning en dato for automatisk at afpublisere."
|
|
||||||
ROBOTS: "Robotter"
|
|
||||||
TAXONOMIES: "Taksonomier"
|
|
||||||
TAXONOMY: "Taksonomi"
|
|
||||||
ADVANCED: "Avanceret"
|
|
||||||
SETTINGS: "Indstillinger"
|
|
||||||
FOLDER_NUMERIC_PREFIX: "Numerisk Mappepræfiks"
|
|
||||||
FOLDER_NUMERIC_PREFIX_HELP: "Numerisk præfiks, der muliggør manuel sortering og indebærer synlighed"
|
|
||||||
FOLDER_NAME: "Mappenavn"
|
|
||||||
FOLDER_NAME_HELP: "Mappenavnet, som skal gemmes i filsystemet, for denne side"
|
|
||||||
PARENT: "Overordnet"
|
|
||||||
DEFAULT_OPTION_ROOT: "- Rod -"
|
|
||||||
DEFAULT_OPTION_SELECT: "- Vælg -"
|
|
||||||
DISPLAY_TEMPLATE: "Visningsskabelon"
|
|
||||||
DISPLAY_TEMPLATE_HELP: "Sidetypen, som oversættes til den twig-template, som viser siden"
|
|
||||||
ORDERING: "Soreting"
|
|
||||||
PAGE_ORDER: "Side-sortering"
|
|
||||||
OVERRIDES: "Tilsidesættelser"
|
|
||||||
MENU: "Menu"
|
|
||||||
MENU_HELP: "Den streng, som skal anvendes i en menu. Hvis ingen angives, bruges Title."
|
|
||||||
SLUG: "Slug"
|
|
||||||
SLUG_HELP: "Slug-variablen bruges til specifikt at angive sidens andel af URL'en"
|
|
||||||
SLUG_VALIDATE_MESSAGE: "En slug må kun indeholde små alfanumeriske karakterer og bindestreger"
|
|
||||||
PROCESS: "Processer"
|
|
||||||
PROCESS_HELP: "Kontroller hvordan sider processeres. Kan angives per side i stedet for globalt"
|
|
||||||
DEFAULT_CHILD_TYPE: "Standardtitel for underordnede"
|
|
||||||
USE_GLOBAL: "Anvend Global"
|
|
||||||
ROUTABLE: "Kan routes"
|
|
||||||
ROUTABLE_HELP: "Om denne side kan tilgås via en URL"
|
|
||||||
CACHING: "Caching"
|
|
||||||
VISIBLE: "Synlig"
|
|
||||||
VISIBLE_HELP: "Afgør om en side er synlig i navigationen."
|
|
||||||
DISABLED: "Deaktiveret"
|
|
||||||
ITEMS: "Elementer"
|
|
||||||
ORDER_BY: "Sortér Efter"
|
|
||||||
ORDER: "Sortering"
|
|
||||||
FOLDER: "Mappe"
|
|
||||||
ASCENDING: "Stigende"
|
|
||||||
DESCENDING: "Faldende"
|
|
||||||
PAGE_TITLE: "Sidetitel"
|
|
||||||
PAGE_TITLE_HELP: "Sidens titel"
|
|
||||||
PAGE: "Side"
|
|
||||||
FRONTMATTER: "Forskræp"
|
|
||||||
FILENAME: "Filnavn"
|
|
||||||
PARENT_PAGE: "Overordnet Side"
|
|
||||||
HOME_PAGE: "Hjem-side"
|
|
||||||
HOME_PAGE_HELP: "Siden som Grav bruger som standard-destinationsside"
|
|
||||||
DEFAULT_THEME: "Standardtema"
|
|
||||||
DEFAULT_THEME_HELP: "Gravs standardtema (som udgangspunkt Antimatter)"
|
|
||||||
TIMEZONE: "Tidszone"
|
|
||||||
TIMEZONE_HELP: "Tilsidesæt serverens standardtidszone"
|
|
||||||
SHORT_DATE_FORMAT: "Kort datoformat-visning"
|
|
||||||
SHORT_DATE_FORMAT_HELP: "Angiv det korte datoformat, der kan bruges af temaer"
|
|
||||||
LONG_DATE_FORMAT: "Lang datoformat-visning"
|
|
||||||
LONG_DATE_FORMAT_HELP: "Angiv det lange datoformat, der kan bruges af temaer"
|
|
||||||
DEFAULT_ORDERING: "Standardsortering"
|
|
||||||
DEFAULT_ORDERING_HELP: "Sider i en liste bliver vist i denne rækkefølge, medmindre den tilsidesættes"
|
|
||||||
DEFAULT_ORDERING_DEFAULT: "Standard - baseret på mappenavn"
|
|
||||||
DEFAULT_ORDERING_FOLDER: "Mappe - baseret på mappenavn uden præfiks"
|
|
||||||
DEFAULT_ORDERING_TITLE: "Titel - baseret på titel-felt i headeren"
|
|
||||||
DEFAULT_ORDERING_DATE: "Dato - baseret på dato-felt i headeren"
|
|
||||||
DEFAULT_ORDER_DIRECTION: "Standard-sorteringsretning"
|
|
||||||
DEFAULT_ORDER_DIRECTION_HELP: "Den retning, som siderne i en liste skal sorteres i"
|
|
||||||
DEFAULT_PAGE_COUNT: "Standard-sideantal"
|
|
||||||
DEFAULT_PAGE_COUNT_HELP: "Standard for maksimalt antal sider i en liste"
|
|
||||||
DATE_BASED_PUBLISHING: "Datobaseret publicering"
|
|
||||||
DATE_BASED_PUBLISHING_HELP: "(Af)publicer automatisk indhold baseret på dets dato"
|
|
||||||
EVENTS: "Begivenheder"
|
|
||||||
EVENTS_HELP: "Aktiver og deaktiver specifikke begivenheder. Deaktivering af disse kan ødelægge plugins"
|
|
||||||
REDIRECT_DEFAULT_ROUTE: "Standardrute for omdirigeringer"
|
|
||||||
REDIRECT_DEFAULT_ROUTE_HELP: "Omdiriger automatisk til en sides standardrute"
|
|
||||||
LANGUAGES: "Sprog"
|
|
||||||
SUPPORTED: "Understøttet"
|
|
||||||
SUPPORTED_HELP: "Kommasepareret liste af sprogkoder på hver to bogstaver (f.eks. 'en,da,fr')"
|
|
||||||
TRANSLATIONS_FALLBACK: "Fallback til oversættelser"
|
|
||||||
TRANSLATIONS_FALLBACK_HELP: "Fallback gennem understøttede oversættelser hvis det aktive sprog ikke findes"
|
|
||||||
ACTIVE_LANGUAGE_IN_SESSION: "Aktivt sprog i session"
|
|
||||||
ACTIVE_LANGUAGE_IN_SESSION_HELP: "Gem det aktive sprog i sessionen"
|
|
||||||
HTTP_HEADERS: "HTTP-headere"
|
|
||||||
EXPIRES: "Udløber"
|
|
||||||
EXPIRES_HELP: "Indstiller expires-headeren. Værdien angives i sekunder."
|
|
||||||
CACHE_CONTROL: "HTTP Cache-kontrol"
|
|
||||||
CACHE_CONTROL_HELP: "Angive en gyldig cache-kontrolværdi såsom 'no-cache, no-butik, must-revalidate'"
|
|
||||||
LAST_MODIFIED: "Senest ændret"
|
|
||||||
LAST_MODIFIED_HELP: "Angiver \"last modified\"-headeren, der kan hjælpe med at optimere proxy og browsercachelagring"
|
|
||||||
ETAG: "ETag"
|
|
||||||
ETAG_HELP: "Indstiller etag-header for at hjælpe med at identificere, hvornår en side er blevet ændret"
|
|
||||||
VARY_ACCEPT_ENCODING: "Vary accept encoding"
|
|
||||||
VARY_ACCEPT_ENCODING_HELP: "Angiver \"Vary: Accept Encoding\"-headeren, der hjælper med proxy og CDN-cachelagring"
|
|
||||||
MARKDOWN: "Markdown"
|
|
||||||
MARKDOWN_EXTRA: "Markdown Extra"
|
|
||||||
MARKDOWN_EXTRA_HELP: "Aktiver standardunderstøttelse for Markdown Extra - https://michelf.ca/projects/php-markdown/extra/"
|
|
||||||
MARKDOWN_EXTRA_ESCAPE_FENCES: "Escape HTML-elementer i Markdown Extra-låger"
|
|
||||||
MARKDOWN_EXTRA_ESCAPE_FENCES_HELP: "Escaper HTML-elementer i Markdown Extra-låger"
|
|
||||||
AUTO_LINE_BREAKS: "Automatiske linjeskift"
|
|
||||||
AUTO_LINE_BREAKS_HELP: "Aktiver understøttelse af automatiske linjeskift i markdown"
|
|
||||||
AUTO_URL_LINKS: "Automatiske URL-links"
|
|
||||||
AUTO_URL_LINKS_HELP: "Aktiver automatisk konvertering af URL'er til HTML-hyperlinks"
|
|
||||||
ESCAPE_MARKUP: "Escape markup"
|
|
||||||
ESCAPE_MARKUP_HELP: "Escape markup-tags til HMTL-entiteter"
|
|
||||||
CACHING_HELP: "Global TÆND/SLUK-kontakt til aktivering/deaktivering af Grav-caching"
|
|
||||||
CACHE_CHECK_METHOD: "Metode til cache-tjek"
|
|
||||||
CACHE_CHECK_METHOD_HELP: "Angiv den metode, som Grav skal bruge til at tjekke om en side er blevet ændret."
|
|
||||||
CACHE_DRIVER: "Cache-driver"
|
|
||||||
CACHE_DRIVER_HELP: "Angiv hvilken cache-driver, som Grav skal bruge. 'Auto-detekter' forsøger at finde den bedste for dig"
|
|
||||||
CACHE_PREFIX: "Cache-præfiks"
|
|
||||||
CACHE_PREFIX_HELP: "Identifikator for en del af Grav-nøglen. Ændr kun hvis du ved, hvad du laver."
|
|
||||||
CACHE_PREFIX_PLACEHOLDER: "Afledt af base-URL'en (tilsidesæt ved at indtaste en arbitrær streng)"
|
|
||||||
CACHE_PURGE_JOB: "Kør planlagt rensningsjob"
|
|
||||||
CACHE_PURGE_JOB_HELP: "Du kan med planlæggeren periodisk rydde ud gamle Doctrine-filcachemapper med dette job"
|
|
||||||
CACHE_CLEAR_JOB: "Kør planlagt rydningsjob"
|
|
||||||
CACHE_CLEAR_JOB_HELP: "Du kan med planlæggeren periodisk rydde Grav-cachen"
|
|
||||||
CACHE_JOB_TYPE: "Cache Jobtype"
|
|
||||||
CACHE_JOB_TYPE_HELP: "Ryd cachen enten for 'standard' eller 'alle' mapper"
|
|
||||||
CACHE_PURGE: "Rens gammel cache"
|
|
||||||
LIFETIME: "Livstid"
|
|
||||||
LIFETIME_HELP: "Angiver cache-livstiden i sekunder. 0 = uendelig"
|
|
||||||
GZIP_COMPRESSION: "Gzip-kompression"
|
|
||||||
GZIP_COMPRESSION_HELP: "Aktiver GZip komprimering af Grav siden for øget ydeevne."
|
|
||||||
TWIG_TEMPLATING: "Twig-skabeloner"
|
|
||||||
TWIG_CACHING: "Twig-cache"
|
|
||||||
TWIG_CACHING_HELP: "Indstil Twigs cache-mekanisme. Lad feltet være aktiveret for at opnå den bedste ydeevne."
|
|
||||||
TWIG_DEBUG: "Twig-debug"
|
|
||||||
TWIG_DEBUG_HELP: "Giver mulighed for ikke at indlæse Twigs debugger-udvidelse"
|
|
||||||
DETECT_CHANGES: "Registrer ændringer"
|
|
||||||
DETECT_CHANGES_HELP: "Twig genkompilerer automatisk sin cache hvis den registrerer ændringer i Twig-skabeloner"
|
|
||||||
AUTOESCAPE_VARIABLES: "Escape automatisk variabler"
|
|
||||||
AUTOESCAPE_VARIABLES_HELP: "Escaper automatisk alle variabler. Dette vil højst sandsynligt ødelægge dit site"
|
|
||||||
ASSETS: "Aktiver"
|
|
||||||
CSS_ASSETS: "CSS-aktiver"
|
|
||||||
CSS_PIPELINE: "CSS-pipeline"
|
|
||||||
CSS_PIPELINE_HELP: "CSS-pipelinen forener flere CSS-ressourcer i én fil"
|
|
||||||
CSS_PIPELINE_INCLUDE_EXTERNALS: "Inkluder eksterne enheder i CSS pipelinen"
|
|
||||||
CSS_PIPELINE_INCLUDE_EXTERNALS_HELP: "Eksterne URL'er har, til tider, relative fil referencer, og bør ikke blive pipelinet"
|
|
||||||
CSS_PIPELINE_BEFORE_EXCLUDES: "Pre-rendering af CSS pipelinen"
|
|
||||||
CSS_PIPELINE_BEFORE_EXCLUDES_HELP: "Render CSS pipelinen før alle andre CSS referencer, der ikke er inkluderet"
|
|
||||||
CSS_MINIFY: "CSS-minificering"
|
|
||||||
CSS_MINIFY_HELP: "Minificer CSS ved brug af pipeline"
|
|
||||||
CSS_MINIFY_WINDOWS_OVERRIDE: "Tilsidesæt Windows' CSS-minificering"
|
|
||||||
CSS_MINIFY_WINDOWS_OVERRIDE_HELP: "Tilsidesættelse af minificering på Windows-platforme. Standard = Fra pga. ThreadStackSize"
|
|
||||||
CSS_REWRITE: "CSS-omskrivning"
|
|
||||||
CSS_REWRITE_HELP: "Omskriv relative CSS-URL'er under pipelining"
|
|
||||||
JS_ASSETS: "JavaScript-aktiver"
|
|
||||||
JAVASCRIPT_PIPELINE: "Javascript-pipeline"
|
|
||||||
JAVASCRIPT_PIPELINE_HELP: "JS-pipelinen samler flere JS-ressourcer i én fil"
|
|
||||||
JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS: "Inkluder eksterne enheder i JS pipelinen"
|
|
||||||
JAVASCRIPT_PIPELINE_INCLUDE_EXTERNALS_HELP: "Eksterne URL'er har, til tider, relative fil referencer, og bør ikke blive pipelinet"
|
|
||||||
JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES: "Pre-rendering af JS pipelinen"
|
|
||||||
JAVASCRIPT_PIPELINE_BEFORE_EXCLUDES_HELP: "Render JS pipelinen før alle andre JS referencer, der ikke er inkluderet"
|
|
||||||
JS_MODULE_ASSETS: "JavaScript Modul-aktiver"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE: "JavaScript Modul-pipeline"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE_HELP: "JS-pipelinen samler flere JS-ressourcer i én fil"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE_INCLUDE_EXTERNALS: "Medtag eksterne enheder i JS Modul-pipelinen"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE_INCLUDE_EXTERNALS_HELP: "Eksterne URL'er har sommetider relative filreferencer, og bør ikke pipelines"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE_BEFORE_EXCLUDES: "Rendering af JS Modul-pipelinen først"
|
|
||||||
JAVASCRIPT_MODULE_PIPELINE_BEFORE_EXCLUDES_HELP: "Rendér JS-pipelinen før alle andre JS-referencer, som ikke er medtaget"
|
|
||||||
GENERAL_CONFIG: "Generel Aktivopsætning"
|
|
||||||
JAVASCRIPT_MINIFY: "Javascript-minificering"
|
|
||||||
JAVASCRIPT_MINIFY_HELP: "Minificer JS ved brug af pipeline"
|
|
||||||
ENABLED_TIMESTAMPS_ON_ASSETS: "Aktiver tidsstempler på aktiver"
|
|
||||||
ENABLED_TIMESTAMPS_ON_ASSETS_HELP: "Aktiver tidsstempler på aktiver"
|
|
||||||
COLLECTIONS: "Kollektioner"
|
|
||||||
ERROR_HANDLER: "Fejlbehandler"
|
|
||||||
DISPLAY_ERRORS: "Visningsfejl"
|
|
||||||
DISPLAY_ERRORS_HELP: "Vis fuld backtrace på fejlside"
|
|
||||||
LOG_ERRORS: "Log fejl"
|
|
||||||
LOG_ERRORS_HELP: "Log fejl i mappen /logs"
|
|
||||||
LOG_HANDLER: "Loghåndtering"
|
|
||||||
LOG_HANDLER_HELP: "Hvor loggerne skal placeres"
|
|
||||||
SYSLOG_FACILITY: "Syslog-facilitet"
|
|
||||||
SYSLOG_FACILITY_HELP: "Syslog-facilitet til output"
|
|
||||||
SYSLOG_TAG: "Syslog-tag"
|
|
||||||
SYSLOG_TAG_HELP: "Syslog-tag til output"
|
|
||||||
DEBUGGER: "Fejlfinder"
|
|
||||||
DEBUGGER_HELP: "Aktivér Grav-fejlfinder og flg. indstillinger"
|
|
||||||
DEBUG_TWIG: "Fejlfind i Twig"
|
|
||||||
DEBUG_TWIG_HELP: "Aktivér fejlfinding i Twig-skabeloner"
|
|
||||||
SHUTDOWN_CLOSE_CONNECTION: "Luk forbindelse ved nedlukning"
|
|
||||||
SHUTDOWN_CLOSE_CONNECTION_HELP: "Luk forbindelsen inden onShutdown()-kald. Slået fra ved debugging"
|
|
||||||
DEFAULT_IMAGE_QUALITY: "Standard-billedkvalitet"
|
|
||||||
DEFAULT_IMAGE_QUALITY_HELP: "Standardbilledkvalitet til brug ved cachelagring af billeder (85%)"
|
|
||||||
CACHE_ALL: "Cache alle billeder"
|
|
||||||
CACHE_ALL_HELP: "Kør alle billeder - også ikke-manipulerede - gennem Gravs cache-system"
|
|
||||||
IMAGES_DEBUG: "Vandmærke ved debugging af billeder"
|
|
||||||
IMAGES_DEBUG_HELP: "Vis overlejring på billeder. Overlejringen indikerer billedets pixel-dybde til brug ved f.eks. visning på retina-skærme"
|
|
||||||
IMAGES_DECODING: "Billedafkodningsadfærd"
|
|
||||||
IMAGES_DECODING_HELP: "Afkodningsattributten lader en webbrowser udsætte billedafkodninger fra skærmen, indtil brugerne ruller i nærheden af dem. Afkodning understøtter tre værdier: auto, sync, async"
|
|
||||||
#Removed in Grav 1.8
|
|
||||||
IMAGES_SEOFRIENDLY: "SEO-venlige billednavne"
|
|
||||||
IMAGES_SEOFRIENDLY_HELP: "Når aktiveret, vises billednavnet først, dernæst en mindre hash, der afspejler udførte operationer"
|
|
||||||
UPLOAD_LIMIT: "Fil-upload grænse"
|
|
||||||
UPLOAD_LIMIT_HELP: "Angiv maks. filstørrelse i bytes (0 = ubegrænset)"
|
|
||||||
ENABLE_MEDIA_TIMESTAMP: "Aktivér tidsstempler på medier"
|
|
||||||
ENABLE_MEDIA_TIMESTAMP_HELP: "Føjer et tidsstempel baseret på seneste ændringsdato til hvert medieemne"
|
|
||||||
SESSION: "Session"
|
|
||||||
SESSION_ENABLED_HELP: "Aktivér sessionsunderstøttelse i Grav"
|
|
||||||
SESSION_NAME_HELP: "En identifikator, der benytts til at danne navnet på sessionens-cookie'en"
|
|
||||||
SESSION_UNIQUENESS: "Unik streng"
|
|
||||||
SESSION_UNIQUENESS_HELP: "MD5-hash af Gravs rodsti, dvs. `GRAV_ROOT` (standard) eller én baseret på den tilfældige` security.salt`-streng."
|
|
||||||
ABSOLUTE_URLS: "Absolutte URL'er"
|
|
||||||
ABSOLUTE_URLS_HELP: "Absolutte eller relative URL'er til 'base_url'"
|
|
||||||
PARAMETER_SEPARATOR: "Parameterseparator"
|
|
||||||
PARAMETER_SEPARATOR_HELP: "Separator til godkendte parametre, som kan ændres til Apache på Windows"
|
|
||||||
TASK_COMPLETED: "Opgave fuldført"
|
|
||||||
EVERYTHING_UP_TO_DATE: "Alt er opdateret"
|
|
||||||
UPDATES_ARE_AVAILABLE: "opdatering(-er) er tilgængelige"
|
|
||||||
IS_AVAILABLE_FOR_UPDATE: "er tilgængelig for opdatering"
|
|
||||||
IS_NOW_AVAILABLE: "er nu tilgængelig"
|
|
||||||
CURRENT: "Aktuel"
|
|
||||||
UPDATE_GRAV_NOW: "Opdater Grav nu"
|
|
||||||
GRAV_SYMBOLICALLY_LINKED: "Grav er forbundet med symbolsk link. Opgraderingen vil ikke være tilgængelig"
|
|
||||||
UPDATING_PLEASE_WAIT: "Opdatering... Vent venligst; downloader"
|
|
||||||
OF_THIS: "af denne"
|
|
||||||
OF_YOUR: "af dit"
|
|
||||||
HAVE_AN_UPDATE_AVAILABLE: "har en tilgængelig opdatering"
|
|
||||||
SAVE_AS: "Gem som"
|
|
||||||
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_DESC: "Sikker på, at du vil slette denne side og alle dens undersider? Er siden oversat til andre sprog, vil disse oversættelser blive bevaret og skal slettes separat. I modsat fald bliver sidemappen og dens undersider slettet. Denne handling er irreversibel."
|
|
||||||
AND: "og"
|
|
||||||
UPDATE_AVAILABLE: "Opdatering tilgængelig"
|
|
||||||
METADATA_KEY: "Nøgle (f.eks. 'Nøgleord')"
|
|
||||||
METADATA_VALUE: "Værdi (f.eks. 'Blog, Grav')"
|
|
||||||
USERNAME_HELP: "Brugernavnet skal være mellem 3 og 16 karakterer og kan indeholde små bogstaver, tal, understreger og bindestreger. Store bogstaver, mellemrum og specielle karakter er ikke tilladt"
|
|
||||||
FULLY_UPDATED: "Fuldt opdateret"
|
|
||||||
SAVE_LOCATION: "Gemmeplacering"
|
|
||||||
PAGE_FILE: "Sideskabelon"
|
|
||||||
PAGE_FILE_HELP: "Sideskabelon filnavn, og standard visnings-skabelonen for denne side"
|
|
||||||
NO_USER_ACCOUNTS: "Der blev ikke fundet nogen brugerkonto; opret venligst en først..."
|
|
||||||
NO_USER_EXISTS: "Ingen lokalbruger til denne konto, kan ikke gemme..."
|
|
||||||
REDIRECT_TRAILING_SLASH: "Omdiriger efterstillet skråstreg"
|
|
||||||
REDIRECT_TRAILING_SLASH_HELP: "Udfør en 301-omdirigering i stedet for gennemsigtigt at håndtere URI'er med efterstillet skråstreg."
|
|
||||||
DEFAULT_DATE_FORMAT: "Sidedatoformat"
|
|
||||||
DEFAULT_DATE_FORMAT_HELP: "Det side-datoformat, som Grav skal bruge. Som standard forsøger Grav at gætte dit datoformat, men du kan specificeret et format med PHP's dato-syntaks (f.eks. Y-m-d H:i)"
|
|
||||||
DEFAULT_DATE_FORMAT_PLACEHOLDER: "Gæt automatisk"
|
|
||||||
IGNORE_FILES: "Ignorer filer"
|
|
||||||
IGNORE_FILES_HELP: "Specifikke filer, som skal ignoreres ved behandlingen af sider"
|
|
||||||
IGNORE_FOLDERS: "Ignorer mapper"
|
|
||||||
IGNORE_FOLDERS_HELP: "Specifikke mapper, som skal ignoreres ved behandlingen af sider"
|
|
||||||
HIDE_EMPTY_FOLDERS: "Skjul tomme mapper"
|
|
||||||
HIDE_EMPTY_FOLDERS_HELP: "Har mappen ikke en .md-fil, skal den være skjult i navigationen og være ikke-rootbar"
|
|
||||||
HTTP_ACCEPT_LANGUAGE: "Indstil sprog fra browser"
|
|
||||||
HTTP_ACCEPT_LANGUAGE_HELP: "Du kan forsøge at indstille sproget på basis af browserens \"http_accept_language\"-headertag"
|
|
||||||
OVERRIDE_LOCALE: "Tilsidesæt lokation"
|
|
||||||
OVERRIDE_LOCALE_HELP: "Tilsidesæt PHP's \"locale\"-indstilling baseret på det nuværende sprog"
|
|
||||||
REDIRECT: "Side-omdirigering"
|
|
||||||
REDIRECT_HELP: "Angiv en side-rute eller ekstern URL, som denne side skal omdirigere til, f.eks. \"/en/rute\" eller \"http://etsite.com\""
|
|
||||||
PLUGIN_STATUS: "Plugin-status"
|
|
||||||
INCLUDE_DEFAULT_LANG: "Inkluder standardsproget"
|
|
||||||
INCLUDE_DEFAULT_LANG_HELP: "Dette foranstiller standardsproget i alle standardsprogets URL'er, f.eks. \"/da/blog/mit-indlæg\""
|
|
||||||
PAGES_FALLBACK_ONLY: "Kun tilbagefaldsside"
|
|
||||||
PAGES_FALLBACK_ONLY_HELP: "Kun 'fallback' for at finde sideindhold via understøttede sprog. Standardadfærd er at vise et hvilket som helst tilgængeligt sprog, såfremt det aktivt sprog mangler"
|
|
||||||
ALLOW_URL_TAXONOMY_FILTERS: "URL-taksonomifiltre"
|
|
||||||
ALLOW_URL_TAXONOMY_FILTERS_HELP: "Sidebaserede samlingergør det muligt at filtrere via \"/taxonomy:værdi\"."
|
|
||||||
REDIRECT_DEFAULT_CODE: "Standardomdirigeringskode"
|
|
||||||
REDIRECT_DEFAULT_CODE_HELP: "HTTP-statuskode til brug ved omdirigeringer"
|
|
||||||
IGNORE_HIDDEN: "Ignorer skjulte"
|
|
||||||
IGNORE_HIDDEN_HELP: "Ignorer alle filer og mapper, der begynder med punktum"
|
|
||||||
WRAPPED_SITE: "Indpakket site"
|
|
||||||
WRAPPED_SITE_HELP: "Bruges af temaer/plugins til at bestemme, om Grav er pakket ind i en anden platform"
|
|
||||||
FALLBACK_TYPES: "Tilladte fallback-typer"
|
|
||||||
FALLBACK_TYPES_HELP: "Tilladte filtyper, der kan tilgås med en side-rute. Som standard sat til alle understøttede medietyper."
|
|
||||||
INLINE_TYPES: "Indlejrede fallback-typer"
|
|
||||||
INLINE_TYPES_HELP: "En liste over filtyper, der skal vises indlejret i stedet for hentes"
|
|
||||||
APPEND_URL_EXT: "Tilføj URL-efternavn"
|
|
||||||
APPEND_URL_EXT_HELP: "Tilføjer et brugerdefineret efternavn til sidens webadresse. Bemærk, at dette vil få Grav til at kigge efter \"<skabelon>. <efternavn>. twig\"-skabeloner"
|
|
||||||
PAGE_MODES: "Side-tilstande"
|
|
||||||
PAGE_TYPES: "Sidetyper"
|
|
||||||
PAGE_TYPES_HELP: "Bestemmer de sidetyper, som Grav understøtter, og rækkefølgen bestemmer fallback-typen, der skal benyttes, såfremt anmodningen er tvetydig"
|
|
||||||
ACCESS_LEVELS: "Adgangsniveauer"
|
|
||||||
GROUPS: "Grupper"
|
|
||||||
GROUPS_HELP: "Liste af grupper, som brugeren er medlem af"
|
|
||||||
ADMIN_ACCESS: "Admin-adgang"
|
|
||||||
SITE_ACCESS: "Webstedsadgang"
|
|
||||||
INVALID_SECURITY_TOKEN: "Ugyldigt sikkerhedstoken"
|
|
||||||
ACTIVATE: "Aktivér"
|
|
||||||
TWIG_UMASK_FIX: "Afmaskeringsfiks"
|
|
||||||
TWIG_UMASK_FIX_HELP: "Som standard opretter Twig cachede filer som 0755. Dette fiks skifter dette til 0775"
|
|
||||||
CACHE_PERMS: "Cachetilladelser"
|
|
||||||
CACHE_PERMS_HELP: "Standard cachemappetilladelser. Som regel 0755 eller 0775, afhængig af opsætningen"
|
|
||||||
REMOVE_SUCCESSFUL: "Fjernet"
|
|
||||||
REMOVE_FAILED: "Fjernelse mislykkedes"
|
|
||||||
HIDE_HOME_IN_URLS: "Skjul hjem-route i URL'er"
|
|
||||||
HIDE_HOME_IN_URLS_HELP: "Sikrer at standard-routes for enhver side under hjem ikke henviser til hjemsidens normale route"
|
|
||||||
TWIG_FIRST: "Behandl Twig først"
|
|
||||||
TWIG_FIRST_HELP: "Har du aktiveret Twig-sidebehandling, kan du opsætte Twig til at gøre dette før eller efter markdown"
|
|
||||||
SESSION_SECURE: "Sikker"
|
|
||||||
SESSION_SECURE_HELP: "Angiver, om kommunikation med denne cookie skal ske krypteret. ADVARSEL: Brug kun dette på sites, der kører udelukkende på HTTPS"
|
|
||||||
SESSION_HTTPONLY: "Kun HTTP"
|
|
||||||
SESSION_HTTPONLY_HELP: "Hvis denne indstilling er aktiveret bruges cookes kun over HTTP og Javascript-ændringer tillades ikke"
|
|
||||||
REVERSE_PROXY: "Omvendt proxy"
|
|
||||||
REVERSE_PROXY_HELP: "Aktiver denne hvis du er bag en omvendt proxy og har problemer med URL'er, der indeholder ukorrekte porte"
|
|
||||||
INVALID_FRONTMATTER_COULD_NOT_SAVE: "Ugyldigt forskræp; kunne ikke gemme"
|
|
||||||
ADD_FOLDER: "Tilføj mappe"
|
|
||||||
COPY_PAGE: "Kopiér side"
|
|
||||||
PROXY_URL: "Proxy-URL"
|
|
||||||
PROXY_URL_HELP: "Indtast proxyens host eller IP og port"
|
|
||||||
PROXY_CERT: "Proxy-certifikatsti"
|
|
||||||
PROXY_CERT_HELP: "Lokal sti til mappen indeholdende proxy-certifikat pem-fil"
|
|
||||||
NOTHING_TO_SAVE: "Intet at gemme"
|
|
||||||
FILE_ERROR_ADD: "Der opstod en fejl under forsøg på at tilføje filen"
|
|
||||||
FILE_ERROR_UPLOAD: "Der opstod en fejl under forsøget på at uploade filer"
|
|
||||||
FILE_UNSUPPORTED: "Ikke-understøttet filtype"
|
|
||||||
ADD_ITEM: "Tilføj element"
|
|
||||||
FILE_TOO_LARGE: "Filen er for stor til at blive uploadet, maksimal tilladt er %s ifølge <br>dine PHP-indstillinger. Øge din 'post_max_size' PHP indstilling"
|
|
||||||
INSTALLING: "Installerer"
|
|
||||||
LOADING: "Indlæser.."
|
|
||||||
DEPENDENCIES_NOT_MET_MESSAGE: "De følgende afhængigheder skal være opfyldt først:"
|
|
||||||
ERROR_INSTALLING_PACKAGES: "Fejl under installering af af pakke(r)"
|
|
||||||
INSTALLING_DEPENDENCIES: "Installerer afhængigheder..."
|
|
||||||
INSTALLING_PACKAGES: "Installerer pakke(r).."
|
|
||||||
PACKAGES_SUCCESSFULLY_INSTALLED: "Pakke(r) installeret korrekt."
|
|
||||||
READY_TO_INSTALL_PACKAGES: "Klar til at installere pakke(r)"
|
|
||||||
PACKAGES_NOT_INSTALLED: "Pakker ikke installeret"
|
|
||||||
PACKAGES_NEED_UPDATE: "Pakker allerede installeret, men forældede"
|
|
||||||
PACKAGES_SUGGESTED_UPDATE: "Pakker allerede installeret, og versionen er i orden, men vil blive opdateret for at holde dig up to date"
|
|
||||||
REMOVE_THE: "Fjern %s"
|
|
||||||
CONFIRM_REMOVAL: "Er du sikker på, at du ønsker at slette %s?"
|
|
||||||
REMOVED_SUCCESSFULLY: "%s fjernet korrekt"
|
|
||||||
ERROR_REMOVING_THE: "Fejl i forsøget på at fjerne %s"
|
|
||||||
ADDITIONAL_DEPENDENCIES_CAN_BE_REMOVED: "%s krævede følgende afhængigheder, som ikke er påkrævet af andre pakker. Hvis du ikke bruger dem, kan du fjerne dem her."
|
|
||||||
READY_TO_UPDATE_PACKAGES: "Klar til at opdatere pakke(r)"
|
|
||||||
ERROR_UPDATING_PACKAGES: "Fejl under opdatering af pakke(r)"
|
|
||||||
UPDATING_PACKAGES: "Opdaterer pakke(r).."
|
|
||||||
PACKAGES_SUCCESSFULLY_UPDATED: "Pakke(r) opdateret korrekt."
|
|
||||||
UPDATING: "Updaterer"
|
|
||||||
GPM_SECTION: "GPM-afsnit"
|
|
||||||
GPM_RELEASES: "GPM udgivelser"
|
|
||||||
GPM_RELEASES_HELP: "Vælg 'Test' for at installere beta eller testversioner"
|
|
||||||
GPM_METHOD: "Fjernhentningsmetode"
|
|
||||||
GPM_METHOD_HELP: "Når indstillet til Auto afgør Grav, om fopen er tilgængelig og benytter den, ellers benyttes cURL. For at gennemtvinge brugen af den ene eller den, skift indstillingen."
|
|
||||||
HTTP_SECTION: "HTTP-afsnit"
|
|
||||||
SSL_ENABLE_PROXY: "Aktivér proxyserver"
|
|
||||||
SSL_VERIFY_PEER: "Fjernbekræft Peer"
|
|
||||||
SSL_VERIFY_PEER_HELP: "Nogle kan mislykkes under bekræftelsen af SSL-certifikater"
|
|
||||||
SSL_VERIFY_HOST: "Fjernbekræft Vært"
|
|
||||||
SSL_VERIFY_HOST_HELP: "Nogle kan mislykkes under bekræftelsen af SSL-certifikater"
|
|
||||||
HTTP_CONNECTIONS: "HTTPS-forbindelser"
|
|
||||||
HTTP_CONNECTIONS_HELP: "Antallet af samtidige HTTP-forbindelser under multipleksede forespørgsler"
|
|
||||||
MISC_SECTION: "Diverse-afsnit"
|
|
||||||
AUTO: "Auto"
|
|
||||||
FOPEN: "fopen"
|
|
||||||
CURL: "cURL"
|
|
||||||
STABLE: "Stabil"
|
|
||||||
TESTING: "Tester"
|
|
||||||
FRONTMATTER_PROCESS_TWIG: "Processer frontmatter Twig"
|
|
||||||
FRONTMATTER_PROCESS_TWIG_HELP: "Når aktiveret kan du bruge Twig's konfigurationsvariabler i sidens frontmatter"
|
|
||||||
FRONTMATTER_IGNORE_FIELDS: "Ignorer frontmatter felter"
|
|
||||||
FRONTMATTER_IGNORE_FIELDS_HELP: "Visse frontmatter felter kan indeholde Twig, men skal ikke behandles. Så som \"formularer\""
|
|
||||||
PACKAGE_X_INSTALLED_SUCCESSFULLY: "Pakke %s installeret"
|
|
||||||
ORDERING_DISABLED_BECAUSE_PARENT_SETTING_ORDER: "Overordnet rækkefølge-indstilling, orden de-aktiveret"
|
|
||||||
ORDERING_DISABLED_BECAUSE_PAGE_NOT_VISIBLE: "Siden er ikke synlig, orden de-aktiveret"
|
|
||||||
ORDERING_DISABLED_BECAUSE_TOO_MANY_SIBLINGS: "Sortering af rækkefølge via administrationen er ikke tilgængelig, fordi der er mere end 200 under-elementer"
|
|
||||||
ORDERING_DISABLED_BECAUSE_PAGE_NO_PREFIX: "Sidebestilling er deaktiveret for denne side, da <strong>Numerisk Mappenpræfiks</strong> ikke er aktiveret"
|
|
||||||
CANNOT_ADD_MEDIA_FILES_PAGE_NOT_SAVED: "OBS: Du kan ikke tilføje medie-filer før du har gemt siden. Klik på \"Gem\" øverst"
|
|
||||||
CANNOT_ADD_FILES_PAGE_NOT_SAVED: "OBS: Siden skal gemmes før du kan tilføje filer til den."
|
|
||||||
DROP_FILES_HERE_TO_UPLOAD: "Smid dine filer her eller, <strong>Klik i dette område</strong>"
|
|
||||||
INSERT: "Indsæt"
|
|
||||||
UNDO: "Fortryd"
|
|
||||||
REDO: "Gendan"
|
|
||||||
HEADERS: "Overskrifter"
|
|
||||||
BOLD: "Fed"
|
|
||||||
ITALIC: "Kursiv"
|
|
||||||
STRIKETHROUGH: "Gennemstreget"
|
|
||||||
SUMMARY_DELIMITER: "Sammendragsafgrænser"
|
|
||||||
LINK: "Link"
|
|
||||||
IMAGE: "Billede"
|
|
||||||
BLOCKQUOTE: "Citatblok"
|
|
||||||
UNORDERED_LIST: "Usorteret liste"
|
|
||||||
ORDERED_LIST: "Sorteret liste"
|
|
||||||
EDITOR: "Editor"
|
|
||||||
PREVIEW: "Eksempelvisning"
|
|
||||||
FULLSCREEN: "Fuld skærm"
|
|
||||||
NON_ROUTABLE: "Ikke tilgængelig"
|
|
||||||
NON_VISIBLE: "Ikke-synlig"
|
|
||||||
NON_PUBLISHED: "Ikke udgivet"
|
|
||||||
CHARACTERS: "tegn"
|
|
||||||
PUBLISHING: "Udgivelse"
|
|
||||||
LEGEND: "Sideoversigt"
|
|
||||||
MEMCACHE_SERVER: "Memcache-server"
|
|
||||||
MEMCACHE_SERVER_HELP: "Memcache-serveradressen"
|
|
||||||
MEMCACHE_PORT: "Memcache-port"
|
|
||||||
MEMCACHE_PORT_HELP: "Memcache-serverporten"
|
|
||||||
MEMCACHED_SERVER: "Memcachet-server"
|
|
||||||
MEMCACHED_SERVER_HELP: "Memcachet-serveradresse"
|
|
||||||
MEMCACHED_PORT: "Memcache-port"
|
|
||||||
MEMCACHED_PORT_HELP: "Memcachet-serverport"
|
|
||||||
REDIS_SERVER: "Redis-server"
|
|
||||||
REDIS_SERVER_HELP: "Redis-serveradressen"
|
|
||||||
REDIS_PORT: "Redis-port"
|
|
||||||
REDIS_PORT_HELP: "Redis-serverport"
|
|
||||||
REDIS_PASSWORD: "Redis-adgangskode/hemmelighed"
|
|
||||||
ALL: "Alle"
|
|
||||||
FROM: "fra"
|
|
||||||
TO: "til"
|
|
||||||
RELEASE_DATE: "Udgivelsesdato"
|
|
||||||
SORT_BY: "Sortér efter"
|
|
||||||
RESOURCE_FILTER: "Filtrér..."
|
|
||||||
FORCE_SSL: "Gennemtving SSL"
|
|
||||||
FORCE_SSL_HELP: "Gennemtving SSL globalt, hvis aktiveret, når webstedet nås via HTTP, Grav sender en omdirigering til HTTPS-siden"
|
|
||||||
NEWS_FEED: "Nyhedsfeed"
|
|
||||||
EXTERNAL_URL: "Ekstern URL"
|
|
||||||
CUSTOM_BASE_URL: "Tilpasset basis-URL"
|
|
||||||
CUSTOM_BASE_URL_HELP: "Benyt, hvis du ønsker at omskrive webstedsdomæne eller benytte en anden undermappe end den, Grav benytter. Eksempel: http://localhost"
|
|
||||||
FILEUPLOAD_PREVENT_SELF: 'Kan ikke benytte "%s" uden for sider.'
|
|
||||||
FILEUPLOAD_UNABLE_TO_UPLOAD: 'Kan ikke uploade fil %s: %s'
|
|
||||||
FILEUPLOAD_UNABLE_TO_MOVE: 'Kan ikke flytte fil %s til "%s"'
|
|
||||||
DROPZONE_CANCEL_UPLOAD: 'Annullér upload'
|
|
||||||
DROPZONE_CANCEL_UPLOAD_CONFIRMATION: 'Sikker på, at du vil annullere denne upload?'
|
|
||||||
DROPZONE_DEFAULT_MESSAGE: 'Slip dine filer hér eller, <strong>klik i dette område</strong>'
|
|
||||||
DROPZONE_FALLBACK_MESSAGE: 'Din browser understøtter ikke træk-og-slip fil-uploads.'
|
|
||||||
DROPZONE_FALLBACK_TEXT: 'Benyt venligst formularen nedenfor for alternativt at uploade filer ''som i gamle dage''.'
|
|
||||||
DROPZONE_FILE_TOO_BIG: 'Filen er for stor ({{filesize}}MiB). Maks. filstørrelse: {{maxFilesize}}MiB.'
|
|
||||||
DROPZONE_INVALID_FILE_TYPE: "Filer af denne type kan ikke uploades."
|
|
||||||
DROPZONE_MAX_FILES_EXCEEDED: "Der kan ikke uploades flere filer."
|
|
||||||
DROPZONE_REMOVE_FILE: "Fjern fil"
|
|
||||||
DROPZONE_RESPONSE_ERROR: "Serveren svarede med koden {{statusCode}}."
|
|
||||||
PREMIUM_PRODUCT: "Premium"
|
|
||||||
DESTINATION_NOT_SPECIFIED: "Destination er ikke angivet"
|
|
||||||
UPLOAD_ERR_NO_TMP_DIR: "Mangler en midlertidige mappe"
|
|
||||||
SESSION_SPLIT: "Sessionsopdeling"
|
|
||||||
SESSION_SPLIT_HELP: "Opdel sessioner uafhængigt mellem websted og andre plugins (f.eks. Admin)"
|
|
||||||
ERROR_FULL_BACKTRACE: "Vis detaljeret Backtrace fejlinfo"
|
|
||||||
ERROR_SIMPLE: "Vis simpel fejlinfo"
|
|
||||||
ERROR_SYSTEM: "Systemfejl"
|
|
||||||
IMAGES_AUTO_FIX_ORIENTATION: "Korrigér orientering automatisk"
|
|
||||||
IMAGES_AUTO_FIX_ORIENTATION_HELP: "Korrigér automatisk billedretningen baseret på Exif-dataene"
|
|
||||||
REDIS_SOCKET: "Redis socket"
|
|
||||||
REDIS_SOCKET_HELP: "Redis socket"
|
|
||||||
NOT_SET: "Ikke indstillet"
|
|
||||||
PERMISSIONS: "Rettigheder"
|
|
||||||
NEVER_CACHE_TWIG: "Mellemlagre aldrig Twig"
|
|
||||||
NEVER_CACHE_TWIG_HELP: "Cache kun indhold og behandle Twig for hver side. Ignorerer twig_first-indstilling."
|
|
||||||
ALLOW_WEBSERVER_GZIP: "Tillad WebServer Gzip"
|
|
||||||
ALLOW_WEBSERVER_GZIP_HELP: "Deaktiveret som standard. Når aktiveret, vil WebServer-konfigureret Gzip-/Deflate-kompression fungere, men HTTP-forbindelsen vil ikke blive lukket før onShutDown() begivenheden forårsager langsommere sideindlæsning"
|
|
||||||
OFFLINE_WARNING: "Kan ikke etablere forbindelse til GPM"
|
|
||||||
CLEAR_IMAGES_BY_DEFAULT: "Ryd som standard billede-cachen"
|
|
||||||
CLEAR_IMAGES_BY_DEFAULT_HELP: "Som standard ryddes behandlede billeder for alle caches. Dette kan deaktiveres"
|
|
||||||
CLI_COMPATIBILITY: "CLI-kompatibilitet"
|
|
||||||
CLI_COMPATIBILITY_HELP: "Sikrer, at kun ikke-flygtig Cache-drivere benyttes (fil, redis, memcache etc.)"
|
|
||||||
REINSTALL_PLUGIN: "Geninstallere plugin"
|
|
||||||
REINSTALL_THEME: "Geninstallere tema"
|
|
||||||
REINSTALL_THE: "Geninstallér %s"
|
|
||||||
CONFIRM_REINSTALL: "Sikker på, at du vil geninstallere dette %s?"
|
|
||||||
REINSTALLED_SUCCESSFULLY: "%s geninstalleret"
|
|
||||||
ERROR_REINSTALLING_THE: "Fejl under geninstallering af %s"
|
|
||||||
PACKAGE_X_REINSTALLED_SUCCESSFULLY: "Pakke %s geninstalleret"
|
|
||||||
REINSTALLATION_FAILED: "Geninstallation mislykkedes"
|
|
||||||
WARNING_REINSTALL_NOT_LATEST_RELEASE: "Den installerede version er ikke den seneste udgivelse. Ved at klikke på Fortsæt fjerner du fjerne den aktuelle version og installerer den senest tilgængelige version"
|
|
||||||
TOOLS: "Værktøjer"
|
|
||||||
NO_PACKAGE_NAME: "Pakkenavn ikke angivet"
|
|
||||||
PACKAGE_EXTRACTION_FAILED: "Pakkeudpakning mislykkedes"
|
|
||||||
NOT_VALID_GRAV_PACKAGE: "Ikke en gyldig Grav-pakke"
|
|
||||||
NAME_COULD_NOT_BE_DETERMINED: "Navn kunne ikke fastslås"
|
|
||||||
CANNOT_OVERWRITE_SYMLINKS: "Kan ikke overskrive symlinks"
|
|
||||||
ZIP_PACKAGE_NOT_FOUND: "ZIP-pakke blev ikke fundet"
|
|
||||||
GPM_OFFICIAL_ONLY: "Kun officiel GPM"
|
|
||||||
GPM_OFFICIAL_ONLY_HELP: "Tillade kun direkte installationer fra det officielle GPM-repositorie."
|
|
||||||
NO_CHILD_TYPE: "Ingen underordnet type for denne rawroute"
|
|
||||||
SORTABLE_PAGES: "Sorterbare sider:"
|
|
||||||
ADMIN_SPECIFIC_OVERRIDES: "Admin-specifikke tilsidesætter"
|
|
||||||
ADMIN_CHILDREN_DISPLAY_ORDER: "Underordnedes visningsrækkefølge"
|
|
||||||
ADMIN_CHILDREN_DISPLAY_ORDER_HELP: "Rækkefølgen, hvori undersider til denne side skal vises i visningen 'Sider' i Admin-plugin"
|
|
||||||
PWD_PLACEHOLDER: "kompleks streng minimum 8 tegn lang"
|
|
||||||
PWD_REGEX: "Adgangskode Regex"
|
|
||||||
PWD_REGEX_HELP: "Adgangskode skal som standard indeholde mindst ét ciffer, én versal og én minuskel samt udgøres af minimum otte tegn"
|
|
||||||
USERNAME_PLACEHOLDER: "kun minuskler, f.eks. 'admin'"
|
|
||||||
USERNAME_REGEX: "Brugernavn Regex"
|
|
||||||
USERNAME_REGEX_HELP: "Som standard kun minuskler, cifre, bindestreger og understregninger på 3-16 tegn"
|
|
||||||
ENABLE_AUTO_METADATA: "Auto-metadata fra Exif"
|
|
||||||
ENABLE_AUTO_METADATA_HELP: "Automatisk generere metadatafiler til billeder med exif-oplysninger"
|
|
||||||
2FA_TITLE: "Totrinsautentificering"
|
|
||||||
2FA_INSTRUCTIONS: "### 2-faktor Autentificering \nDu har **2FA** aktiveret for denne konto. Benyt venligst din **2FA**-app til at angive den aktuelle **6-cifrede kode** for at fuldføre loginprocessen."
|
|
||||||
2FA_LABEL: "Admin-adgang"
|
|
||||||
2FA_FAILED: "Ugyldig 2-faktor autentificeringskode, forsøg venligst igen..."
|
|
||||||
2FA_ENABLED: "2FA aktiveret"
|
|
||||||
2FA_CODE_INPUT: "000000"
|
|
||||||
2FA_SECRET: "2FA hemmelighed"
|
|
||||||
2FA_REGENERATE: "Regenerér"
|
|
||||||
YUBIKEY_ID: "YubiKey ID"
|
|
||||||
YUBIKEY_OTP_INPUT: "YubiKey OTP"
|
|
||||||
YUBIKEY_HELP: "Indsæt YubiKey i computeren og klik på knappen for at generere en OTP. De første 12 tegn er klient-ID'en, der vil blive gemt."
|
|
||||||
FORCE_LOWERCASE_URLS: "Brug små bogstaver i URL'er"
|
|
||||||
VIEW_SITE_TIP: "Vis site"
|
|
||||||
TOOLS_DIRECT_INSTALL_TITLE: "Direkte installation af Grav-pakker"
|
|
||||||
TOOLS_DIRECT_INSTALL_UPLOAD_BUTTON: "Upload og installer"
|
|
||||||
OPEN_NEW_TAB: "Åbn i nyt faneblad"
|
|
||||||
STRICT_YAML_COMPAT: "YAML Kompatibilitet"
|
|
||||||
STRICT_TWIG_COMPAT: "Twig Kompatibilitet"
|
|
||||||
SCHEDULER_RUNAT_HELP: "Cron-formateret 'at' syntaks. BEMÆRK: Alle tidsangivelser er UTC!"
|
|
||||||
SCHEDULER_OUTPUT: "Output Fil"
|
|
||||||
SCHEDULER_EMAIL: "E-mail"
|
|
||||||
SECURITY: "Sikkerhed"
|
|
||||||
REPORTS: "Rapporter"
|
|
||||||
LOGS: "Logfiler"
|
|
||||||
BACKUPS_MAX_COUNT: "Maksimalt Antal Sikkerhedskopier"
|
|
||||||
BACKUPS_MAX_COUNT_HELP: "0 er ubegrænset"
|
|
||||||
BACKUPS_PROFILE_NAME: "Backup navn"
|
|
||||||
COMMAND: "Kommando"
|
|
||||||
CONFIGURATION: "Opsætning"
|
|
||||||
ADMIN_CACHING: "Aktivere Admin-cachelagring"
|
|
||||||
ADMIN_CACHING_HELP: "Cachelagring i admin kan styres uafhængigt af frontend-webstedet"
|
|
||||||
CONTENT_PADDING: "Indholdsrammer"
|
|
||||||
CONTENT_PADDING_HELP: "Aktivér/Deaktivér indholdsrammer omkring indholdsområde for at give mere plads"
|
|
||||||
TIMEOUT: "Timeout"
|
|
||||||
TIMEOUT_HELP: "Angiver sessionstimeout i sekunder"
|
|
||||||
DASHBOARD: "Kontrolpanel"
|
|
||||||
NOTIFICATIONS: "Notifikationer"
|
|
||||||
CONTENT_HIGHLIGHT_HELP: "Indholdsfremhævning"
|
|
||||||
REDIRECT_OPTION_NO_REDIRECT: "Ingen omdirigering"
|
|
||||||
REDIRECT_OPTION_DEFAULT_REDIRECT: "Benyt standardomdirigeringskode"
|
|
||||||
REDIRECT_OPTION_301: "301 - Flyttet permanent"
|
|
||||||
REDIRECT_OPTION_302: "302 - Flyttet midlertidigt"
|
|
||||||
REDIRECT_OPTION_303: "303 - Se andre"
|
|
||||||
IMAGES_CLS_TITLE: "Cumative Layer Shift (CLS)"
|
|
||||||
IMAGES_CLS_AUTO_SIZES: "Aktivér Auto-størrelser"
|
|
||||||
IMAGES_CLS_AUTO_SIZES_HELP: "Føj automatisk 'bredde'- og 'højde'-attributter til billeder for at adressere CLS"
|
|
||||||
IMAGES_CLS_ASPECT_RATIO: "Aktivér Størrelsesforhold"
|
|
||||||
IMAGES_CLS_ASPECT_RATIO_HELP: "Valgfri CSS-variabel, der bliver anvendt via en 'stil'-attribut, der kan bruges i CSS til tilpasset styling"
|
|
||||||
IMAGES_CLS_RETINA_SCALE: "Retinaskaleringsfaktor"
|
|
||||||
IMAGES_CLS_RETINA_SCALE_HELP: "Vil tage den beregnede størrelse og dividere med skaleringsfaktoren for at vise et billede med højere opløsning ved en mindre pixelstørrelse for bedre håndtering af HiDPI-opløsninger"
|
|
||||||
AUTOREGENERATE_FOLDER_SLUG: "Auto-regenerér baseret på sidetitel"
|
|
||||||
ENABLE: Aktivér
|
|
||||||
PLUGINS_MUST_BE_ENABLED: "Plugin skal være aktiveret for at opsætte"
|
|
||||||
ACTIVATION_REQUIRED: "Aktivering krævet for at opsætte"
|
|
||||||
SESSION_SECURE_HTTPS: "Sikker (HTTPS)"
|
|
||||||
SESSION_SECURE_HTTPS_HELP: "Opsæt sikker session for HTTPS, men ikke for HTTP. Har ingen effekt, hvis indstillinger over Sikker er sat til sand. Indstil til falsk, hvis webstedet hopper mellem HTTP og HTTPS."
|
|
||||||
AVATAR: "Avatargenerator"
|
|
||||||
AVATAR_HELP: "Multiavatar er en lokalt genereret avatar. Gravatar er en ekstern tjeneste, der bruger din e-mailadresse til at trække en præopsat Avatar eksternt"
|
|
||||||
AVATAR_HASH: "BEMÆRK: Valgfri tilpasset Avatar 'hash'-streng"
|
|
||||||
IMAGES_TITLE: "Billeder"
|
|
||||||
LEGACY_MEDIA_MUTATION: "Kompatibilitet til redigering af ældre medier"
|
|
||||||
LEGACY_MEDIA_MUTATION_HELP: "Aktivér kun denne indstilling, hvis billedemanipulation fejlede efter Grav-opdatering."
|
|
||||||
BACKWARD_COMPATIBILITY: "Bagudkompatibilitet"
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user