Update Kirby and dependencies
This commit is contained in:
parent
750b9cc83e
commit
8c71a258b6
59 changed files with 2143 additions and 813 deletions
6
kirby/.vscode/extensions.json
vendored
6
kirby/.vscode/extensions.json
vendored
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
4
kirby/.vscode/settings.json
vendored
4
kirby/.vscode/settings.json
vendored
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
}
|
|
@ -28,7 +28,7 @@ Please post all bug reports in our [issue tracker](https://github.com/getkirby/k
|
|||
If you have ideas for a feature or enhancement for Kirby, please use our [feedback platform](https://feedback.getkirby.com).
|
||||
|
||||
**Translations, bug fixes, code contributions ...**
|
||||
Read about how to contribute to the development in our [contributing guide](/.github/CONTRIBUTING.md).
|
||||
Read about how to contribute to the development in our [contributing guide](/CONTRIBUTING.md).
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
##
|
||||
## Bundle of CA Root Certificates
|
||||
##
|
||||
## Certificate data from Mozilla as of: Fri Mar 18 12:29:51 2022 GMT
|
||||
## Certificate data from Mozilla as of: Tue Apr 26 03:12:05 2022 GMT
|
||||
##
|
||||
## This is a bundle of X.509 certificates of public Certificate Authorities
|
||||
## (CA). These were automatically extracted from Mozilla's root certificates
|
||||
|
@ -14,7 +14,7 @@
|
|||
## Just configure this file as the SSLCACertificateFile.
|
||||
##
|
||||
## Conversion done with mk-ca-bundle.pl version 1.29.
|
||||
## SHA256: 187ef9dc231135324fe78830cf4462f1ecdeab3e6c9d5e38d623391e88dc5d3c
|
||||
## SHA256: 34a54d5191775c1bd37be6cfd3f09e831e072555dc3a2e51f4a2c4b0f8ada5cc
|
||||
##
|
||||
|
||||
|
||||
|
@ -3279,3 +3279,69 @@ PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C
|
|||
r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh
|
||||
4rsUecrNIdSUtUlD
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Telia Root CA v2
|
||||
================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT
|
||||
AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2
|
||||
MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK
|
||||
DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI
|
||||
hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7
|
||||
6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q
|
||||
9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn
|
||||
pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl
|
||||
tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW
|
||||
5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr
|
||||
RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E
|
||||
BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4
|
||||
M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau
|
||||
BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W
|
||||
xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD
|
||||
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
|
||||
8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5
|
||||
tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H
|
||||
eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C
|
||||
y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC
|
||||
QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15
|
||||
h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70
|
||||
sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9
|
||||
xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ
|
||||
raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
D-TRUST BR Root CA 1 2020
|
||||
=========================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
|
||||
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy
|
||||
MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
|
||||
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG
|
||||
ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7
|
||||
dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu
|
||||
QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t
|
||||
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
|
||||
bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
|
||||
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
|
||||
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
|
||||
AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom
|
||||
AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
D-TRUST EV Root CA 1 2020
|
||||
=========================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
|
||||
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy
|
||||
MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
|
||||
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG
|
||||
ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8
|
||||
ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ
|
||||
raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL
|
||||
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
|
||||
bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
|
||||
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
|
||||
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
|
||||
AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR
|
||||
AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW
|
||||
-----END CERTIFICATE-----
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"description": "The Kirby 3 core",
|
||||
"license": "proprietary",
|
||||
"type": "kirby-cms",
|
||||
"version": "3.6.3",
|
||||
"version": "3.6.6",
|
||||
"keywords": [
|
||||
"kirby",
|
||||
"cms",
|
||||
|
@ -31,12 +31,12 @@
|
|||
"claviska/simpleimage": "3.6.5",
|
||||
"filp/whoops": "2.14.5",
|
||||
"getkirby/composer-installer": "^1.2.1",
|
||||
"laminas/laminas-escaper": "2.9.0",
|
||||
"laminas/laminas-escaper": "2.10.0",
|
||||
"michelf/php-smartypants": "1.8.1",
|
||||
"phpmailer/phpmailer": "6.5.4",
|
||||
"psr/log": "1.1.4",
|
||||
"symfony/polyfill-intl-idn": "1.24.0",
|
||||
"symfony/polyfill-mbstring": "1.24.0"
|
||||
"symfony/polyfill-intl-idn": "1.25.0",
|
||||
"symfony/polyfill-mbstring": "1.25.0"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/polyfill-php72": "*"
|
||||
|
|
36
kirby/composer.lock
generated
36
kirby/composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "d4cf75084dae428fe0ab54124637d51f",
|
||||
"content-hash": "cb6bffc372828b6d36107d104c0b2a3e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "claviska/simpleimage",
|
||||
|
@ -175,33 +175,33 @@
|
|||
},
|
||||
{
|
||||
"name": "laminas/laminas-escaper",
|
||||
"version": "2.9.0",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-escaper.git",
|
||||
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f"
|
||||
"reference": "58af67282db37d24e584a837a94ee55b9c7552be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/891ad70986729e20ed2e86355fcf93c9dc238a5f",
|
||||
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be",
|
||||
"reference": "58af67282db37d24e584a837a94ee55b9c7552be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
"ext-ctype": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-escaper": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.26.6",
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"psalm/plugin-phpunit": "^0.12.2",
|
||||
"vimeo/psalm": "^3.16"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "*",
|
||||
"ext-mbstring": "*"
|
||||
"maglnet/composer-require-checker": "^3.8.0",
|
||||
"phpunit/phpunit": "^9.5.18",
|
||||
"psalm/plugin-phpunit": "^0.16.1",
|
||||
"vimeo/psalm": "^4.22.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -233,7 +233,7 @@
|
|||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2021-09-02T17:10:53+00:00"
|
||||
"time": "2022-03-08T20:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/color-extractor",
|
||||
|
@ -477,7 +477,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
|
@ -544,7 +544,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -648,7 +648,7 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
|
@ -711,7 +711,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
|
@ -16,8 +16,7 @@ return [
|
|||
'page.changeSort' => [
|
||||
'pattern' => 'pages/(:any)/changeSort',
|
||||
'load' => function (string $id) {
|
||||
$page = Find::page($id);
|
||||
$position = null;
|
||||
$page = Find::page($id);
|
||||
|
||||
if ($page->blueprint()->num() !== 'default') {
|
||||
throw new PermissionException([
|
||||
|
|
|
@ -5,6 +5,7 @@ fields:
|
|||
images:
|
||||
label: field.blocks.gallery.images.label
|
||||
type: files
|
||||
query: model.images
|
||||
multiple: true
|
||||
layout: cards
|
||||
size: tiny
|
||||
|
|
|
@ -13,6 +13,7 @@ fields:
|
|||
image:
|
||||
label: field.blocks.image.name
|
||||
type: files
|
||||
query: model.images
|
||||
multiple: false
|
||||
image:
|
||||
back: black
|
||||
|
|
|
@ -168,7 +168,7 @@ return [
|
|||
* @return \Kirby\Cms\Collection|bool
|
||||
*/
|
||||
'search' => function (App $kirby, Collection $collection, string $query = null, $params = []) {
|
||||
if (empty(trim($query)) === true) {
|
||||
if (empty(trim($query ?? '')) === true) {
|
||||
return $collection->limit(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,14 +69,13 @@ return [
|
|||
return $value;
|
||||
}
|
||||
|
||||
$value = trim($value);
|
||||
$converter = $this->converters()[$this->converter()];
|
||||
|
||||
if (is_array($value) === true) {
|
||||
return array_map($converter, $value);
|
||||
}
|
||||
|
||||
return call_user_func($converter, $value);
|
||||
return call_user_func($converter, trim($value ?? ''));
|
||||
},
|
||||
'converters' => function (): array {
|
||||
return [
|
||||
|
|
|
@ -112,11 +112,11 @@ return function (App $app) {
|
|||
* Converts the field value to a timestamp or a formatted date
|
||||
*
|
||||
* @param \Kirby\Cms\Field $field
|
||||
* @param string|null $format PHP date formatting string
|
||||
* @param string|\IntlDateFormatter|null $format PHP date formatting string
|
||||
* @param string|null $fallback Fallback string for `strtotime` (since 3.2)
|
||||
* @return string|int
|
||||
*/
|
||||
'toDate' => function (Field $field, string $format = null, string $fallback = null) use ($app) {
|
||||
'toDate' => function (Field $field, $format = null, string $fallback = null) use ($app) {
|
||||
if (empty($field->value) === true && $fallback === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ return [
|
|||
'form' => function () {
|
||||
$fields = $this->fields;
|
||||
$disabled = $this->model->permissions()->update() === false;
|
||||
$content = $this->model->content()->toArray();
|
||||
$lang = $this->model->kirby()->languageCode();
|
||||
$content = $this->model->content($lang)->toArray();
|
||||
|
||||
if ($disabled === true) {
|
||||
foreach ($fields as $key => $props) {
|
||||
|
|
|
@ -6,9 +6,16 @@ return [
|
|||
'props' => [
|
||||
/**
|
||||
* The headline for the section. This can be a simple string or a template with additional info from the parent page.
|
||||
* @todo deprecate in 3.7
|
||||
*/
|
||||
'headline' => function ($headline = null) {
|
||||
return I18n::translate($headline, $headline);
|
||||
},
|
||||
/**
|
||||
* label is the new official replacement for headline
|
||||
*/
|
||||
'label' => function ($label = null) {
|
||||
return I18n::translate($label, $label);
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
|
@ -17,6 +24,10 @@ return [
|
|||
return $this->model()->toString($this->headline);
|
||||
}
|
||||
|
||||
if ($this->label) {
|
||||
return $this->model()->toString($this->label);
|
||||
}
|
||||
|
||||
return ucfirst($this->name);
|
||||
}
|
||||
]
|
||||
|
|
|
@ -396,7 +396,7 @@
|
|||
"next": "Næste",
|
||||
"no": "nej",
|
||||
"off": "Sluk",
|
||||
"on": "Tænd",
|
||||
"on": "Aktiveret",
|
||||
"open": "Åben",
|
||||
"open.newWindow": "Åben i et nyt vindue",
|
||||
"options": "Indstillinger",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"account.changeName": "Modifier votre nom",
|
||||
"account.delete": "Supprimer votre compte",
|
||||
"account.delete.confirm": "Voulez-vous vraiment supprimer votre compte ? Vous serez déconnecté immédiatement. Votre compte ne pourra pas être récupéré.",
|
||||
"account.delete.confirm": "Voulez-vous vraiment supprimer votre compte ? Vous serez déconnecté immédiatement. Votre compte ne pourra pas être récupéré.",
|
||||
|
||||
"add": "Ajouter",
|
||||
"author": "Auteur",
|
||||
|
@ -61,7 +61,7 @@
|
|||
"error.avatar.dimensions.invalid": "Veuillez choisir une image de profil de largeur et hauteur inférieures à 3000 pixels",
|
||||
"error.avatar.mime.forbidden": "L'image du profil utilisateur doit être un fichier JPEG ou PNG",
|
||||
|
||||
"error.blueprint.notFound": "Le blueprint « {name} » n’a pu être chargé",
|
||||
"error.blueprint.notFound": "Le blueprint « {name} » n’a pu être chargé",
|
||||
|
||||
"error.blocks.max.plural": "Vous ne devez pas ajouter plus de {max} blocs",
|
||||
"error.blocks.max.singular": "Vous ne devez pas ajouter plus d'un bloc",
|
||||
|
@ -69,29 +69,29 @@
|
|||
"error.blocks.min.singular": "Vous devez ajouter au moins un bloc",
|
||||
"error.blocks.validation": "Il y a une erreur dans le bloc {index}",
|
||||
|
||||
"error.email.preset.notFound": "La configuration de courriel « {name} » n’a pu être trouvé",
|
||||
"error.email.preset.notFound": "La configuration de courriel « {name} » n’a pu être trouvé ",
|
||||
|
||||
"error.field.converter.invalid": "Convertisseur « {converter} » incorrect",
|
||||
"error.field.converter.invalid": "Convertisseur « {converter} » incorrect",
|
||||
|
||||
"error.file.changeName.empty": "Le nom ne peut être vide",
|
||||
"error.file.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de « {filename} »",
|
||||
"error.file.duplicate": "Un fichier nommé « {filename} » existe déjà",
|
||||
"error.file.extension.forbidden": "L’extension « {extension} » n’est pas autorisée",
|
||||
"error.file.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de « {filename} »",
|
||||
"error.file.duplicate": "Un fichier nommé « {filename} » existe déjà",
|
||||
"error.file.extension.forbidden": "L’extension « {extension} » n’est pas autorisée",
|
||||
"error.file.extension.invalid": "Extension non valide : {extension}",
|
||||
"error.file.extension.missing": "L’extension pour « {filename} » est manquante",
|
||||
"error.file.extension.missing": "L’extension pour « {filename} » est manquante",
|
||||
"error.file.maxheight": "La hauteur de l'image ne doit pas excéder {height} pixels",
|
||||
"error.file.maxsize": "Le fichier est trop volumineux",
|
||||
"error.file.maxwidth": "La largeur de l'image ne doit pas excéder {width} pixels",
|
||||
"error.file.mime.differs": "Le fichier transféré doit être du même type de média « {mime} »",
|
||||
"error.file.mime.forbidden": "Le type de média « {mime} » n’est pas autorisé",
|
||||
"error.file.mime.differs": "Le fichier transféré doit être du même type de média « {mime} »",
|
||||
"error.file.mime.forbidden": "Le type de média « {mime} » n’est pas autorisé",
|
||||
"error.file.mime.invalid": "Type de média non valide : {mime}",
|
||||
"error.file.mime.missing": "Le type de média de « {filename} » n’a pu être détecté",
|
||||
"error.file.mime.missing": "Le type de média de « {filename} » n’a pu être détecté",
|
||||
"error.file.minheight": "La hauteur de l'image doit être au moins {height} pixels",
|
||||
"error.file.minsize": "Le fichier n'est pas assez volumineux",
|
||||
"error.file.minwidth": "La largeur de l'image doit être au moins {width} pixels",
|
||||
"error.file.name.missing": "Veuillez entrer un titre",
|
||||
"error.file.notFound": "Le fichier « {filename} » n’a pu être trouvé",
|
||||
"error.file.orientation": "L'orientation de l'image doit être \"{orientation}\"",
|
||||
"error.file.notFound": "Le fichier « {filename} » n’a pu être trouvé",
|
||||
"error.file.orientation": "L'orientation de l'image doit être « {orientation} »",
|
||||
"error.file.type.forbidden": "Vous n’êtes pas autorisé à transférer des fichiers {type}",
|
||||
"error.file.type.invalid": "Type de fichier non valide : {type}",
|
||||
"error.file.undefined": "Le fichier n’a pu être trouvé",
|
||||
|
@ -113,43 +113,43 @@
|
|||
|
||||
"error.offline": "Le Panel est actuellement hors ligne",
|
||||
|
||||
"error.page.changeSlug.permission": "Vous n’êtes pas autorisé à modifier l’identifiant d’URL pour « {slug} »",
|
||||
"error.page.changeSlug.permission": "Vous n’êtes pas autorisé à modifier l’identifiant d’URL pour « {slug} »",
|
||||
"error.page.changeStatus.incomplete": "La page comporte des erreurs et ne peut pas être publiée",
|
||||
"error.page.changeStatus.permission": "Le statut de cette page ne peut être modifié",
|
||||
"error.page.changeStatus.toDraft.invalid": "La page « {slug} » ne peut être convertie en brouillon",
|
||||
"error.page.changeTemplate.invalid": "Le modèle de la page « {slug} » ne peut être changé",
|
||||
"error.page.changeTemplate.permission": "Vous n’êtes pas autorisé à changer le modèle de « {slug} »",
|
||||
"error.page.changeStatus.toDraft.invalid": "La page « {slug} » ne peut être convertie en brouillon",
|
||||
"error.page.changeTemplate.invalid": "Le modèle de la page « {slug} » ne peut être changé",
|
||||
"error.page.changeTemplate.permission": "Vous n’êtes pas autorisé à changer le modèle de « {slug} »",
|
||||
"error.page.changeTitle.empty": "Le titre ne peut être vide",
|
||||
"error.page.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre de « {slug} »",
|
||||
"error.page.create.permission": "Vous n’êtes pas autorisé à créer « {slug} »",
|
||||
"error.page.delete": "La page « {slug} » ne peut être supprimée",
|
||||
"error.page.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre de « {slug} »",
|
||||
"error.page.create.permission": "Vous n’êtes pas autorisé à créer « {slug} »",
|
||||
"error.page.delete": "La page « {slug} » ne peut être supprimée",
|
||||
"error.page.delete.confirm": "Veuillez saisir le titre de la page pour confirmer",
|
||||
"error.page.delete.hasChildren": "La page comporte des sous-pages et ne peut pas être supprimée",
|
||||
"error.page.delete.permission": "Vous n’êtes pas autorisé à supprimer « {slug} »",
|
||||
"error.page.draft.duplicate": "Un brouillon avec l’identifiant d’URL « {slug} » existe déjà",
|
||||
"error.page.duplicate": "Une page avec l’identifiant d’URL « {slug} » existe déjà",
|
||||
"error.page.duplicate.permission": "Vous n'êtes pas autorisé à dupliquer « {slug} »",
|
||||
"error.page.notFound": "La page « {slug} » n’a pu être trouvée",
|
||||
"error.page.delete.permission": "Vous n’êtes pas autorisé à supprimer « {slug} »",
|
||||
"error.page.draft.duplicate": "Un brouillon avec l’identifiant d’URL « {slug} » existe déjà",
|
||||
"error.page.duplicate": "Une page avec l’identifiant d’URL « {slug} » existe déjà",
|
||||
"error.page.duplicate.permission": "Vous n'êtes pas autorisé à dupliquer « {slug} »",
|
||||
"error.page.notFound": "La page « {slug} » n’a pu être trouvée",
|
||||
"error.page.num.invalid": "Veuillez saisir un numéro de position valide. Les numéros ne doivent pas être négatifs.",
|
||||
"error.page.slug.invalid": "Veuillez entrer un identifiant d’URL valide",
|
||||
"error.page.slug.maxlength": "L’identifiant d’URL doit faire moins de \"{length}\" caractères",
|
||||
"error.page.sort.permission": "La page « {slug} » ne peut être réordonnée",
|
||||
"error.page.slug.maxlength": "L’identifiant d’URL doit faire moins de « {length} » caractères",
|
||||
"error.page.sort.permission": "La page « {slug} » ne peut être réordonnée",
|
||||
"error.page.status.invalid": "Veuillez choisir un statut de page valide",
|
||||
"error.page.undefined": "La page n’a pu être trouvée",
|
||||
"error.page.update.permission": "Vous n’êtes pas autorisé à modifier « {slug} »",
|
||||
"error.page.update.permission": "Vous n’êtes pas autorisé à modifier « {slug} »",
|
||||
|
||||
"error.section.files.max.plural": "Vous ne pouvez ajouter plus de {max} fichier(s) à la section « {section} »",
|
||||
"error.section.files.max.singular": "Vous ne pouvez ajouter plus d’un fichier à la section « {section} »",
|
||||
"error.section.files.min.plural": "La section « {section}\" » requiert au moins {min} fichiers",
|
||||
"error.section.files.min.singular": "La section « {section}\" » requiert au moins un fichier",
|
||||
"error.section.files.max.plural": "Vous ne pouvez ajouter plus de {max} fichier(s) à la section « {section} »",
|
||||
"error.section.files.max.singular": "Vous ne pouvez ajouter plus d’un fichier à la section « {section} »",
|
||||
"error.section.files.min.plural": "La section « {section} » requiert au moins {min} fichiers",
|
||||
"error.section.files.min.singular": "La section « {section} » requiert au moins un fichier",
|
||||
|
||||
"error.section.pages.max.plural": "Vous ne pouvez ajouter plus de {max} pages à la section « {section} »",
|
||||
"error.section.pages.max.singular": "Vous ne pouvez ajouter plus d’une page à la section « {section} »",
|
||||
"error.section.pages.min.plural": "La section « {section}\" » requiert au moins {min} pages",
|
||||
"error.section.pages.min.singular": "La section « {section}\" » requiert au moins une page",
|
||||
"error.section.pages.max.plural": "Vous ne pouvez ajouter plus de {max} pages à la section « {section} »",
|
||||
"error.section.pages.max.singular": "Vous ne pouvez ajouter plus d’une page à la section « {section} »",
|
||||
"error.section.pages.min.plural": "La section « {section} » requiert au moins {min} pages",
|
||||
"error.section.pages.min.singular": "La section « {section} » requiert au moins une page",
|
||||
|
||||
"error.section.notLoaded": "La section « {name} » n’a pu être chargée",
|
||||
"error.section.type.invalid": "Le type de section « {type} » est incorrect",
|
||||
"error.section.notLoaded": "La section « {name} » n’a pu être chargée",
|
||||
"error.section.type.invalid": "Le type de section « {type} » est incorrect",
|
||||
|
||||
"error.site.changeTitle.empty": "Le titre ne peut être vide",
|
||||
"error.site.changeTitle.permission": "Vous n’êtes pas autorisé à modifier le titre du site",
|
||||
|
@ -157,46 +157,46 @@
|
|||
|
||||
"error.template.default.notFound": "Le modèle par défaut n’existe pas",
|
||||
|
||||
"error.unexpected": "Une erreur inattendue est survenue ! Activez le mode de débogage pour plus d'informations : https://getkirby.com/docs/reference/system/options/debug",
|
||||
"error.unexpected": "Une erreur inattendue est survenue ! Activez le mode de débogage pour plus d'informations : https://getkirby.com/docs/reference/system/options/debug",
|
||||
|
||||
"error.user.changeEmail.permission": "Vous n’êtes pas autorisé à modifier le courriel de l’utilisateur « {name} »",
|
||||
"error.user.changeLanguage.permission": "Vous n’êtes pas autorisé à changer la langue de l’utilisateur « {name} »",
|
||||
"error.user.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de l’utilisateur « {name} »",
|
||||
"error.user.changePassword.permission": "Vous n’êtes pas autorisé à changer le mot de passe de l’utilisateur « {name} »",
|
||||
"error.user.changeEmail.permission": "Vous n’êtes pas autorisé à modifier le courriel de l’utilisateur « {name} »",
|
||||
"error.user.changeLanguage.permission": "Vous n’êtes pas autorisé à changer la langue de l’utilisateur « {name} »",
|
||||
"error.user.changeName.permission": "Vous n’êtes pas autorisé à modifier le nom de l’utilisateur « {name} »",
|
||||
"error.user.changePassword.permission": "Vous n’êtes pas autorisé à changer le mot de passe de l’utilisateur « {name} »",
|
||||
"error.user.changeRole.lastAdmin": "Le rôle du dernier administrateur ne peut être modifié",
|
||||
"error.user.changeRole.permission": "Vous n’êtes pas autorisé à changer le rôle de l’utilisateur « {name} »",
|
||||
"error.user.changeRole.permission": "Vous n’êtes pas autorisé à changer le rôle de l’utilisateur « {name} »",
|
||||
"error.user.changeRole.toAdmin": "Vous n’êtes pas autorisé à attribuer le rôle d’administrateur aux utilisateurs",
|
||||
"error.user.create.permission": "Vous n’êtes pas autorisé à créer cet utilisateur",
|
||||
"error.user.delete": "L’utilisateur « {name} » ne peut être supprimé",
|
||||
"error.user.delete": "L’utilisateur « {name} » ne peut être supprimé",
|
||||
"error.user.delete.lastAdmin": "Le dernier administrateur ne peut être supprimé",
|
||||
"error.user.delete.lastUser": "Le dernier utilisateur ne peut être supprimé",
|
||||
"error.user.delete.permission": "Vous n’êtes pas autorisé à supprimer l’utilisateur « {name} »",
|
||||
"error.user.duplicate": "Un utilisateur avec le courriel « {email} » existe déjà",
|
||||
"error.user.delete.permission": "Vous n’êtes pas autorisé à supprimer l’utilisateur « {name} »",
|
||||
"error.user.duplicate": "Un utilisateur avec le courriel « {email} » existe déjà",
|
||||
"error.user.email.invalid": "Veuillez saisir un courriel valide",
|
||||
"error.user.language.invalid": "Veuillez saisir une langue valide",
|
||||
"error.user.notFound": "L’utilisateur « {name} » n’a pu être trouvé",
|
||||
"error.user.notFound": "L’utilisateur « {name} » n’a pu être trouvé",
|
||||
"error.user.password.invalid": "Veuillez saisir un mot de passe valide. Les mots de passe doivent comporter au moins 8 caractères.",
|
||||
"error.user.password.notSame": "Les mots de passe ne sont pas identiques",
|
||||
"error.user.password.undefined": "Cet utilisateur n’a pas de mot de passe",
|
||||
"error.user.password.wrong": "Mot de passe incorrect",
|
||||
"error.user.role.invalid": "Veuillez saisir un rôle valide",
|
||||
"error.user.undefined": "L’utilisateur n’a pu être trouvé",
|
||||
"error.user.update.permission": "Vous n’êtes pas autorisé à modifier l’utilisateur « {name} »",
|
||||
"error.user.update.permission": "Vous n’êtes pas autorisé à modifier l’utilisateur « {name} »",
|
||||
|
||||
"error.validation.accepted": "Veuillez confirmer",
|
||||
"error.validation.alpha": "Veuillez saisir uniquement des caractères alphabétiques minuscules",
|
||||
"error.validation.alphanum": "Veuillez ne saisir que des minuscules de a à z et des chiffres de 0 à 9",
|
||||
"error.validation.between": "Veuillez saisir une valeur entre « {min} » et « {max} »",
|
||||
"error.validation.between": "Veuillez saisir une valeur entre « {min} » et « {max} »",
|
||||
"error.validation.boolean": "Veuillez confirmer ou refuser",
|
||||
"error.validation.contains": "Veuillez saisir une valeur contenant « {needle} »",
|
||||
"error.validation.contains": "Veuillez saisir une valeur contenant « {needle} »",
|
||||
"error.validation.date": "Veuillez saisir une date valide",
|
||||
"error.validation.date.after": "Veuillez saisir une date après {date}",
|
||||
"error.validation.date.before": "Veuillez saisir une date avant {date}",
|
||||
"error.validation.date.between": "Veuillez saisir une date entre {min} et {max}",
|
||||
"error.validation.denied": "Veuillez refuser",
|
||||
"error.validation.different": "La valeur ne doit pas être « {other} »",
|
||||
"error.validation.different": "La valeur ne doit pas être « {other} »",
|
||||
"error.validation.email": "Veuillez saisir un courriel valide",
|
||||
"error.validation.endswith": "La valeur doit se terminer par « {end} »",
|
||||
"error.validation.endswith": "La valeur doit se terminer par « {end} »",
|
||||
"error.validation.filename": "Veuillez saisir un nom de fichier valide",
|
||||
"error.validation.in": "Veuillez saisir l’un des éléments suivants: ({in})",
|
||||
"error.validation.integer": "Veuillez saisir un entier valide",
|
||||
|
@ -210,14 +210,14 @@
|
|||
"error.validation.minlength": "Veuillez saisir une valeur plus longue (min. {min} caractères)",
|
||||
"error.validation.minwords": "Veuillez saisir au moins {min} mot(s)",
|
||||
"error.validation.more": "Veuillez saisir une valeur supérieure à {min}",
|
||||
"error.validation.notcontains": "Veuillez saisir une valeur ne contenant pas « {needle} »",
|
||||
"error.validation.notcontains": "Veuillez saisir une valeur ne contenant pas « {needle} »",
|
||||
"error.validation.notin": "Veuillez ne saisir aucun des éléments suivants: ({notIn})",
|
||||
"error.validation.option": "Veuillez sélectionner une option valide",
|
||||
"error.validation.num": "Veuillez saisir un nombre valide",
|
||||
"error.validation.required": "Veuillez saisir quelque chose",
|
||||
"error.validation.same": "Veuillez saisir « {other} »",
|
||||
"error.validation.size": "La grandeur de la valeur doit être « {size} »",
|
||||
"error.validation.startswith": "La valeur doit commencer par « {start} »",
|
||||
"error.validation.same": "Veuillez saisir « {other} »",
|
||||
"error.validation.size": "La grandeur de la valeur doit être « {size} »",
|
||||
"error.validation.startswith": "La valeur doit commencer par « {start} »",
|
||||
"error.validation.time": "Veuillez saisir une heure valide",
|
||||
"error.validation.time.after": "Veuillez entrer une heure après {time}",
|
||||
"error.validation.time.before": "Veuillez entrer une heure avant {time}",
|
||||
|
@ -232,9 +232,9 @@
|
|||
"field.blocks.code.name": "Code",
|
||||
"field.blocks.code.language": "Langue",
|
||||
"field.blocks.code.placeholder": "Votre code…",
|
||||
"field.blocks.delete.confirm": "Voulez-vous vraiment supprimer ce bloc ?",
|
||||
"field.blocks.delete.confirm.all": "Voulez-vous vraiment supprimer tous les blocs ?",
|
||||
"field.blocks.delete.confirm.selected": "Voulez-vous vraiment supprimer les blocs sélectionnés ?",
|
||||
"field.blocks.delete.confirm": "Voulez-vous vraiment supprimer ce bloc ?",
|
||||
"field.blocks.delete.confirm.all": "Voulez-vous vraiment supprimer tous les blocs ?",
|
||||
"field.blocks.delete.confirm.selected": "Voulez-vous vraiment supprimer les blocs sélectionnés ?",
|
||||
"field.blocks.empty": "Pas encore de blocs",
|
||||
"field.blocks.fieldsets.label": "Veuillez sélectionner un type de bloc…",
|
||||
"field.blocks.fieldsets.paste": "Presser <kbd>{{ shortcut }}</kbd> pour coller/importer des blocks depuis votre presse-papier",
|
||||
|
@ -275,17 +275,17 @@
|
|||
"field.files.empty": "Pas encore de fichier sélectionné",
|
||||
|
||||
"field.layout.delete": "Supprimer cette disposition",
|
||||
"field.layout.delete.confirm": "Voulez-vous vraiment supprimer cette disposition ?",
|
||||
"field.layout.delete.confirm": "Voulez-vous vraiment supprimer cette disposition ?",
|
||||
"field.layout.empty": "Pas encore de rangées",
|
||||
"field.layout.select": "Choisir une disposition",
|
||||
|
||||
"field.pages.empty": "Pas encore de page sélectionnée",
|
||||
"field.structure.delete.confirm": "Voulez-vous vraiment supprimer cette ligne?",
|
||||
"field.structure.delete.confirm": "Voulez-vous vraiment supprimer cette ligne ?",
|
||||
"field.structure.empty": "Pas encore d’entrée",
|
||||
"field.users.empty": "Pas encore d’utilisateur sélectionné",
|
||||
|
||||
"file.blueprint": "Ce fichier n’a pas encore de blueprint. Vous pouvez en définir les paramètres dans <strong>/site/blueprints/files/{blueprint}.yml</strong>",
|
||||
"file.delete.confirm": "Voulez-vous vraiment supprimer <br><strong>{filename}</strong> ?",
|
||||
"file.delete.confirm": "Voulez-vous vraiment supprimer <br><strong>{filename}</strong> ?",
|
||||
"file.sort": "Modifier la position",
|
||||
|
||||
"files": "Fichiers",
|
||||
|
@ -315,9 +315,9 @@
|
|||
"language": "Langue",
|
||||
"language.code": "Code",
|
||||
"language.convert": "Choisir comme langue par défaut",
|
||||
"language.convert.confirm": "<p>Souhaitez-vous vraiment convertir <strong>{name}</strong> vers la langue par défaut ? Cette action ne peut pas être annulée.</p><p>Si <strong>{name}</strong> a un contenu non traduit, il n’y aura plus de solution de secours possible et certaines parties de votre site pourraient être vides.</p>",
|
||||
"language.convert.confirm": "<p>Souhaitez-vous vraiment convertir <strong>{name}</strong> vers la langue par défaut ? Cette action ne peut pas être annulée.</p><p>Si <strong>{name}</strong> a un contenu non traduit, il n’y aura plus de solution de secours possible et certaines parties de votre site pourraient être vides.</p>",
|
||||
"language.create": "Ajouter une nouvelle langue",
|
||||
"language.delete.confirm": "Voulez-vous vraiment supprimer la langue <strong>{name}</strong>, ainsi que toutes ses traductions ? Cette action ne peut être annulée !",
|
||||
"language.delete.confirm": "Voulez-vous vraiment supprimer la langue <strong>{name}</strong>, ainsi que toutes ses traductions ? Cette action ne peut être annulée !",
|
||||
"language.deleted": "La langue a été supprimée",
|
||||
"language.direction": "Sens de lecture",
|
||||
"language.direction.ltr": "De gauche à droite",
|
||||
|
@ -367,7 +367,7 @@
|
|||
"login.reset": "Réinitialiser le mot de passe",
|
||||
"login.toggleText.code.email": "Se connecter par courriel",
|
||||
"login.toggleText.code.email-password": "Se connecter avec un mot de passe",
|
||||
"login.toggleText.password-reset.email": "Mot de passe oublié ?",
|
||||
"login.toggleText.password-reset.email": "Mot de passe oublié ?",
|
||||
"login.toggleText.password-reset.email-password": "← Retour à la connexion",
|
||||
|
||||
"logout": "Se déconnecter",
|
||||
|
@ -414,7 +414,7 @@
|
|||
"page.changeStatus.position": "Veuillez sélectionner une position",
|
||||
"page.changeStatus.select": "Sélectionner un nouveau statut",
|
||||
"page.changeTemplate": "Changer de modèle",
|
||||
"page.delete.confirm": "Voulez-vous vraiment supprimer <strong>{title}</strong> ?",
|
||||
"page.delete.confirm": "Voulez-vous vraiment supprimer <strong>{title}</strong> ?",
|
||||
"page.delete.confirm.subpages": "<strong>Cette page contient des sous-pages</strong>. <br>Toutes les sous-pages seront également supprimées.",
|
||||
"page.delete.confirm.title": "Veuillez saisir le titre de la page pour confirmer",
|
||||
"page.draft.create": "Créer un brouillon",
|
||||
|
@ -450,7 +450,7 @@
|
|||
"replace": "Remplacer",
|
||||
"retry": "Essayer à nouveau",
|
||||
"revert": "Revenir",
|
||||
"revert.confirm": "Voulez-vous vraiment <strong>supprimer toutes les modifications non-enregistrées</strong> ?",
|
||||
"revert.confirm": "Voulez-vous vraiment <strong>supprimer toutes les modifications non-enregistrées</strong> ?",
|
||||
|
||||
"role": "Rôle",
|
||||
"role.admin.description": "L’administrateur dispose de tous les droits",
|
||||
|
@ -539,7 +539,7 @@
|
|||
"user.changeRole.select": "Sélectionner un nouveau rôle",
|
||||
"user.create": "Ajouter un nouvel utilisateur",
|
||||
"user.delete": "Supprimer cet utilisateur",
|
||||
"user.delete.confirm": "Voulez-vous vraiment supprimer <br><strong>{email}</strong>?",
|
||||
"user.delete.confirm": "Voulez-vous vraiment supprimer <br><strong>{email}</strong> ?",
|
||||
|
||||
"users": "Utilisateurs",
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
|
||||
"error.template.default.notFound": "Het standaard template bestaat niet",
|
||||
|
||||
"error.unexpected": "An unexpected error occurred! Enable debug mode for more info: https://getkirby.com/docs/reference/system/options/debug",
|
||||
"error.unexpected": "Een onverwacht fout heeft plaats gevonden! Schakel debug-modus in voor meer informatie: https://getkirby.com/docs/reference/system/options/debug",
|
||||
|
||||
"error.user.changeEmail.permission": "Je hebt geen rechten om het e-mailadres van gebruiker \"{name}\" te wijzigen",
|
||||
"error.user.changeLanguage.permission": "Je hebt geen rechten om de taal voor gebruiker \"{name}\" te wijzigen",
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:cypress/recommended",
|
||||
"plugin:vue/recommended",
|
||||
"prettier"
|
||||
],
|
||||
rules: {
|
||||
"vue/attributes-order": "error",
|
||||
"vue/component-definition-name-casing": "off",
|
||||
"vue/html-closing-bracket-newline": [
|
||||
"error",
|
||||
{
|
||||
singleline: "never",
|
||||
multiline: "always"
|
||||
}
|
||||
],
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/require-default-prop": "off",
|
||||
"vue/require-prop-types": "error"
|
||||
}
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"trailingComma": "none"
|
||||
}
|
2
kirby/panel/dist/css/style.css
vendored
2
kirby/panel/dist/css/style.css
vendored
File diff suppressed because one or more lines are too long
2
kirby/panel/dist/js/index.js
vendored
2
kirby/panel/dist/js/index.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,115 +0,0 @@
|
|||
/* eslint-env node */
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { defineConfig } from "vite";
|
||||
import { createVuePlugin } from "vite-plugin-vue2";
|
||||
import postcssAutoprefixer from "autoprefixer";
|
||||
import postcssCsso from "postcss-csso";
|
||||
import postcssDirPseudoClass from "postcss-dir-pseudo-class";
|
||||
import postcssLogical from "postcss-logical";
|
||||
import pluginRewriteAll from "vite-plugin-rewrite-all";
|
||||
|
||||
let custom;
|
||||
try {
|
||||
custom = require("./vite.config.custom.js");
|
||||
} catch (err) {
|
||||
custom = {};
|
||||
}
|
||||
|
||||
export default defineConfig(({ command }) => {
|
||||
// Tell Kirby that we are in dev mode
|
||||
if (command === "serve") {
|
||||
// Create the flag file on start
|
||||
const runningPath = __dirname + "/.vite-running";
|
||||
fs.closeSync(fs.openSync(runningPath, "w"));
|
||||
|
||||
// Delete the flag file on any kind of exit
|
||||
for (const eventType of ["exit", "SIGINT", "uncaughtException"]) {
|
||||
process.on(eventType, function (err) {
|
||||
if (fs.existsSync(runningPath) === true) {
|
||||
fs.unlinkSync(runningPath);
|
||||
}
|
||||
|
||||
if (eventType === "uncaughtException") {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const proxy = {
|
||||
target: process.env.VUE_APP_DEV_SERVER || "http://sandbox.test",
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
};
|
||||
|
||||
return {
|
||||
plugins: [createVuePlugin(), pluginRewriteAll()],
|
||||
define: {
|
||||
// Fix vuelidate error
|
||||
"process.env.BUILD": JSON.stringify("production")
|
||||
},
|
||||
build: {
|
||||
minify: "terser",
|
||||
cssCodeSplit: false,
|
||||
rollupOptions: {
|
||||
input: "./src/index.js",
|
||||
output: {
|
||||
entryFileNames: "js/[name].js",
|
||||
chunkFileNames: "js/[name].js",
|
||||
assetFileNames: "[ext]/[name].[ext]"
|
||||
}
|
||||
}
|
||||
},
|
||||
optimizeDeps: {
|
||||
entries: "src/**/*.{js,vue}",
|
||||
exclude: [
|
||||
"vitest"
|
||||
]
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
postcssLogical(),
|
||||
postcssDirPseudoClass(),
|
||||
postcssCsso(),
|
||||
postcssAutoprefixer()
|
||||
]
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: "vue",
|
||||
replacement: "vue/dist/vue.esm.js"
|
||||
},
|
||||
{
|
||||
find: "@",
|
||||
replacement: path.resolve(__dirname, "src")
|
||||
}
|
||||
]
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
"/api": proxy,
|
||||
"/env": proxy,
|
||||
"/media": proxy
|
||||
},
|
||||
...custom
|
||||
},
|
||||
test: {
|
||||
environment: "jsdom",
|
||||
include: ["**/*.test.js"],
|
||||
coverage: {
|
||||
all: true,
|
||||
exclude: ["**/*.e2e.js", "**/*.test.js"],
|
||||
extension: ["js", "vue"],
|
||||
src: "src",
|
||||
reporter: ["text", "lcov"]
|
||||
},
|
||||
setupFiles: ["vitest.setup.js"]
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,4 +0,0 @@
|
|||
import Vue from "vue";
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.config.devtools = false;
|
|
@ -10,6 +10,7 @@ use Kirby\Exception\NotFoundException;
|
|||
use Kirby\Filesystem\Dir;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Http\Request;
|
||||
use Kirby\Http\Response;
|
||||
use Kirby\Http\Router;
|
||||
use Kirby\Http\Server;
|
||||
use Kirby\Http\Uri;
|
||||
|
@ -709,14 +710,25 @@ class App
|
|||
return $this->io(new NotFoundException());
|
||||
}
|
||||
|
||||
// Response Configuration
|
||||
// (Modified) global response configuration, e.g. in routes
|
||||
if (is_a($input, 'Kirby\Cms\Responder') === true) {
|
||||
// return the passed object unmodified (without injecting headers
|
||||
// from the global object) to allow a complete response override
|
||||
// https://github.com/getkirby/kirby/pull/4144#issuecomment-1034766726
|
||||
return $input->send();
|
||||
}
|
||||
|
||||
// Responses
|
||||
if (is_a($input, 'Kirby\Http\Response') === true) {
|
||||
return $input;
|
||||
$data = $input->toArray();
|
||||
|
||||
// inject headers from the global response configuration
|
||||
// lazily (only if they are not already set);
|
||||
// the case-insensitive nature of headers will be
|
||||
// handled by PHP's `header()` function
|
||||
$data['headers'] = array_merge($response->headers(), $data['headers']);
|
||||
|
||||
return new Response($data);
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
|
|
@ -203,12 +203,14 @@ class Blueprint
|
|||
return $props;
|
||||
}
|
||||
|
||||
try {
|
||||
$mixin = static::find($extends);
|
||||
$mixin = static::extend($mixin);
|
||||
$props = A::merge($mixin, $props, A::MERGE_REPLACE);
|
||||
} catch (Exception $e) {
|
||||
// keep the props unextended if the snippet wasn't found
|
||||
foreach (A::wrap($extends) as $extend) {
|
||||
try {
|
||||
$mixin = static::find($extend);
|
||||
$mixin = static::extend($mixin);
|
||||
$props = A::merge($mixin, $props, A::MERGE_REPLACE);
|
||||
} catch (Exception $e) {
|
||||
// keep the props unextended if the snippet wasn't found
|
||||
}
|
||||
}
|
||||
|
||||
// remove the extends flag
|
||||
|
@ -287,13 +289,16 @@ class Blueprint
|
|||
$file = $kirby->extension('blueprints', $name);
|
||||
}
|
||||
|
||||
// callback option can be return array or blueprint file path
|
||||
if (is_callable($file) === true) {
|
||||
$file = $file($kirby);
|
||||
}
|
||||
|
||||
// now ensure that we always return the data array
|
||||
if (is_string($file) === true && F::exists($file) === true) {
|
||||
return static::$loaded[$name] = Data::read($file);
|
||||
} elseif (is_array($file) === true) {
|
||||
return static::$loaded[$name] = $file;
|
||||
} elseif (is_callable($file) === true) {
|
||||
return static::$loaded[$name] = $file($kirby);
|
||||
}
|
||||
|
||||
// neither a valid file nor array data
|
||||
|
|
|
@ -54,7 +54,7 @@ class Fieldset extends Item
|
|||
$this->editable = $params['editable'] ?? true;
|
||||
$this->icon = $params['icon'] ?? null;
|
||||
$this->model = $this->parent;
|
||||
$this->name = $this->createName($params['name'] ?? Str::ucfirst($this->type));
|
||||
$this->name = $this->createName($params['title'] ?? $params['name'] ?? Str::ucfirst($this->type));
|
||||
$this->label = $this->createLabel($params['label'] ?? null);
|
||||
$this->preview = $params['preview'] ?? null;
|
||||
$this->tabs = $this->createTabs($params);
|
||||
|
|
|
@ -353,12 +353,12 @@ class File extends ModelWithContent
|
|||
/**
|
||||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string|null $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string|null $handler date, intl or strftime
|
||||
* @param string|null $languageCode
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(string $format = null, string $handler = null, string $languageCode = null)
|
||||
public function modified($format = null, string $handler = null, string $languageCode = null)
|
||||
{
|
||||
$file = $this->modifiedFile();
|
||||
$content = $this->modifiedContent($languageCode);
|
||||
|
|
|
@ -80,15 +80,30 @@ class FileRules
|
|||
*/
|
||||
public static function create(File $file, BaseFile $upload): bool
|
||||
{
|
||||
// We want to ensure that we are not creating duplicate files.
|
||||
// If a file with the same name already exists
|
||||
if ($file->exists() === true) {
|
||||
if ($file->sha1() !== $upload->sha1()) {
|
||||
throw new DuplicateException([
|
||||
'key' => 'file.duplicate',
|
||||
'data' => [
|
||||
'filename' => $file->filename()
|
||||
]
|
||||
]);
|
||||
// $file will be based on the props of the new file,
|
||||
// to compare templates, we need to get the props of
|
||||
// the already existing file from meta content file
|
||||
$existing = $file->parent()->file($file->filename());
|
||||
|
||||
// if the new upload is the exact same file
|
||||
// and uses the same template, we can continue
|
||||
if (
|
||||
$file->sha1() === $upload->sha1() &&
|
||||
$file->template() === $existing->template()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise throw an error for duplicate file
|
||||
throw new DuplicateException([
|
||||
'key' => 'file.duplicate',
|
||||
'data' => [
|
||||
'filename' => $file->filename()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
if ($file->permissions()->create() !== true) {
|
||||
|
|
|
@ -347,6 +347,7 @@ abstract class ModelWithContent extends Model
|
|||
$result = Str::query($query, [
|
||||
'kirby' => $this->kirby(),
|
||||
'site' => is_a($this, 'Kirby\Cms\Site') ? $this : $this->site(),
|
||||
'model' => $this,
|
||||
static::CLASS_ALIAS => $this
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
|
|
|
@ -25,7 +25,7 @@ class PageBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'changeSlug' => null,
|
||||
|
@ -50,10 +50,10 @@ class PageBlueprint extends Blueprint
|
|||
);
|
||||
|
||||
// normalize the ordering number
|
||||
$this->props['num'] = $this->normalizeNum($props['num'] ?? 'default');
|
||||
$this->props['num'] = $this->normalizeNum($this->props['num'] ?? 'default');
|
||||
|
||||
// normalize the available status array
|
||||
$this->props['status'] = $this->normalizeStatus($props['status'] ?? null);
|
||||
$this->props['status'] = $this->normalizeStatus($this->props['status'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,14 +97,20 @@ class Roles extends Collection
|
|||
*/
|
||||
public static function load(string $root = null, array $inject = [])
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$roles = new static();
|
||||
|
||||
// load roles from plugins
|
||||
foreach (App::instance()->extensions('blueprints') as $blueprintName => $blueprint) {
|
||||
foreach ($kirby->extensions('blueprints') as $blueprintName => $blueprint) {
|
||||
if (substr($blueprintName, 0, 6) !== 'users/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// callback option can be return array or blueprint file path
|
||||
if (is_callable($blueprint) === true) {
|
||||
$blueprint = $blueprint($kirby);
|
||||
}
|
||||
|
||||
if (is_array($blueprint) === true) {
|
||||
$role = Role::factory($blueprint, $inject);
|
||||
} else {
|
||||
|
|
|
@ -26,7 +26,7 @@ class SiteBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'changeTitle' => null,
|
||||
|
|
|
@ -445,7 +445,7 @@ class System
|
|||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
$response = Remote::get('https://licenses.getkirby.com/register', [
|
||||
$response = Remote::get('https://hub.getkirby.com/register', [
|
||||
'data' => [
|
||||
'license' => $license,
|
||||
'email' => Str::lower(trim($email)),
|
||||
|
|
|
@ -30,7 +30,7 @@ class UserBlueprint extends Blueprint
|
|||
|
||||
// normalize all available page options
|
||||
$this->props['options'] = $this->normalizeOptions(
|
||||
$props['options'] ?? true,
|
||||
$this->props['options'] ?? true,
|
||||
// defaults
|
||||
[
|
||||
'create' => null,
|
||||
|
|
|
@ -775,7 +775,11 @@ class Query
|
|||
|
||||
// apply it to the dataset and retrieve all rows. make sure to use Collection as the iterator to be able to attach the pagination object
|
||||
$iterator = $this->iterator;
|
||||
$collection = $this->offset($pagination->offset())->limit($pagination->limit())->iterator('Collection')->all();
|
||||
$collection = $this
|
||||
->offset($pagination->offset())
|
||||
->limit($pagination->limit())
|
||||
->iterator('Kirby\Toolkit\Collection')
|
||||
->all();
|
||||
|
||||
$this->iterator($iterator);
|
||||
|
||||
|
@ -968,6 +972,11 @@ class Query
|
|||
$this->bindings($sql['bindings']);
|
||||
} elseif (is_callable($args[0]) === true) {
|
||||
$query = clone $this;
|
||||
|
||||
// since the callback uses its own where condition
|
||||
// it is necessary to clear/reset the cloned where condition
|
||||
$query->where = null;
|
||||
|
||||
call_user_func($args[0], $query);
|
||||
|
||||
// copy over the bindings from the nested query
|
||||
|
|
|
@ -853,8 +853,14 @@ abstract class Sql
|
|||
$query = [];
|
||||
$bindings = [];
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$fields[] = $this->columnName($table, $key, $enforceQualified);
|
||||
foreach ($values as $column => $value) {
|
||||
$key = $this->columnName($table, $column, $enforceQualified);
|
||||
|
||||
if ($key === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields[] = $key;
|
||||
|
||||
if (in_array($value, static::$literals, true) === true) {
|
||||
$query[] = $value ?: 'null';
|
||||
|
@ -896,6 +902,10 @@ abstract class Sql
|
|||
foreach ($values as $column => $value) {
|
||||
$key = $this->columnName($table, $column, $enforceQualified);
|
||||
|
||||
if ($key === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($value, static::$literals, true) === true) {
|
||||
$query[] = $key . ' = ' . ($value ?: 'null');
|
||||
continue;
|
||||
|
|
|
@ -137,7 +137,7 @@ class Sqlite extends Sql
|
|||
public function tables(): array
|
||||
{
|
||||
return [
|
||||
'query' => 'SELECT name FROM sqlite_master WHERE type = "table"',
|
||||
'query' => 'SELECT name FROM sqlite_master WHERE type = "table" OR type = "view"',
|
||||
'bindings' => []
|
||||
];
|
||||
}
|
||||
|
|
|
@ -463,11 +463,11 @@ class F
|
|||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $format
|
||||
* @param string $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string $handler date, intl or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public static function modified(string $file, string $format = null, string $handler = 'date')
|
||||
public static function modified(string $file, $format = null, string $handler = 'date')
|
||||
{
|
||||
if (file_exists($file) !== true) {
|
||||
return false;
|
||||
|
|
|
@ -372,11 +372,11 @@ class File
|
|||
/**
|
||||
* Returns the file's last modification time
|
||||
*
|
||||
* @param string $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string|null $handler date, intl or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(?string $format = null, ?string $handler = null)
|
||||
public function modified($format = null, ?string $handler = null)
|
||||
{
|
||||
$kirby = $this->kirby();
|
||||
|
||||
|
|
|
@ -268,7 +268,14 @@ class Server
|
|||
public static function requestUri(): array
|
||||
{
|
||||
$uri = static::get('REQUEST_URI', '');
|
||||
$uri = parse_url($uri);
|
||||
|
||||
if (Url::isAbsolute($uri) === true) {
|
||||
$uri = parse_url($uri);
|
||||
} else {
|
||||
// the fake domain is needed to make sure the URL parsing is
|
||||
// always correct. Even if there's a colon in the path for params
|
||||
$uri = parse_url('http://getkirby.com' . $uri);
|
||||
}
|
||||
|
||||
return [
|
||||
'path' => $uri['path'] ?? null,
|
||||
|
|
|
@ -130,7 +130,7 @@ class Uri
|
|||
* Creates a new URI object
|
||||
*
|
||||
* @param array|string $props
|
||||
* @param array $inject
|
||||
* @param array $inject Additional props to inject if a URL string is passed
|
||||
*/
|
||||
public function __construct($props = [], array $inject = [])
|
||||
{
|
||||
|
@ -144,10 +144,7 @@ class Uri
|
|||
|
||||
// parse the path and extract params
|
||||
if (empty($props['path']) === false) {
|
||||
$extract = Params::extract($props['path']);
|
||||
$props['params'] ??= $extract['params'];
|
||||
$props['path'] = $extract['path'];
|
||||
$props['slash'] ??= $extract['slash'];
|
||||
$props = static::parsePath($props);
|
||||
}
|
||||
|
||||
$this->setProperties($this->props = $props);
|
||||
|
@ -372,11 +369,17 @@ class Uri
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \Kirby\Http\Params|string|array|null $params
|
||||
* @param \Kirby\Http\Params|string|array|false|null $params
|
||||
* @return $this
|
||||
*/
|
||||
public function setParams($params = null)
|
||||
{
|
||||
// ensure that the special constructor value of `false`
|
||||
// is never passed through as it's not supported by `Params`
|
||||
if ($params === false) {
|
||||
$params = [];
|
||||
}
|
||||
|
||||
$this->params = is_a($params, 'Kirby\Http\Params') === true ? $params : new Params($params);
|
||||
return $this;
|
||||
}
|
||||
|
@ -539,4 +542,33 @@ class Uri
|
|||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the path inside the props and extracts
|
||||
* the params unless disabled
|
||||
*
|
||||
* @param array $props
|
||||
* @return array Modified props array
|
||||
*/
|
||||
protected static function parsePath(array $props): array
|
||||
{
|
||||
// extract params, the rest is the path;
|
||||
// only do this if not explicitly disabled (set to `false`)
|
||||
if (isset($props['params']) === false || $props['params'] !== false) {
|
||||
$extract = Params::extract($props['path']);
|
||||
$props['params'] ??= $extract['params'];
|
||||
$props['path'] = $extract['path'];
|
||||
$props['slash'] ??= $extract['slash'];
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
// use the full path;
|
||||
// automatically detect the trailing slash from it if possible
|
||||
if (is_string($props['path']) === true) {
|
||||
$props['slash'] = substr($props['path'], -1, 1) === '/';
|
||||
}
|
||||
|
||||
return $props;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ use Throwable;
|
|||
*/
|
||||
class File extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\File
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -423,11 +428,11 @@ class File extends Model
|
|||
return [
|
||||
'next' => function () use ($file, $siblings): ?array {
|
||||
$next = $siblings->nth($siblings->indexOf($file) + 1);
|
||||
return $next ? $next->panel()->toLink('filename') : null;
|
||||
return $this->toPrevNextLink($next, 'filename');
|
||||
},
|
||||
'prev' => function () use ($file, $siblings): ?array {
|
||||
$prev = $siblings->nth($siblings->indexOf($file) - 1);
|
||||
return $prev ? $prev->panel()->toLink('filename') : null;
|
||||
return $this->toPrevNextLink($prev, 'filename');
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kirby\Panel;
|
||||
|
||||
use Kirby\Form\Form;
|
||||
use Kirby\Http\Uri;
|
||||
use Kirby\Toolkit\A;
|
||||
|
||||
/**
|
||||
|
@ -387,6 +388,36 @@ abstract class Model
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns link url and tooltip
|
||||
* for optional sibling model and
|
||||
* preserves tab selection
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param \Kirby\Cms\ModelWithContent|null $model
|
||||
* @param string $tooltip
|
||||
* @return array
|
||||
*/
|
||||
protected function toPrevNextLink($model = null, string $tooltip = 'title'): ?array
|
||||
{
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $model->panel()->toLink($tooltip);
|
||||
|
||||
if ($tab = get('tab')) {
|
||||
$uri = new Uri($data['link'], [
|
||||
'query' => ['tab' => $tab]
|
||||
]);
|
||||
|
||||
$data['link'] = $uri->toString();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url to the editing view
|
||||
* in the Panel
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class Page extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\Page
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -309,14 +314,8 @@ class Page extends Model
|
|||
};
|
||||
|
||||
return [
|
||||
'next' => function () use ($siblings) {
|
||||
$next = $siblings('next')->first();
|
||||
return $next ? $next->panel()->toLink('title') : null;
|
||||
},
|
||||
'prev' => function () use ($siblings) {
|
||||
$prev = $siblings('prev')->last();
|
||||
return $prev ? $prev->panel()->toLink('title') : null;
|
||||
}
|
||||
'next' => fn () => $this->toPrevNextLink($siblings('next')->first()),
|
||||
'prev' => fn () => $this->toPrevNextLink($siblings('prev')->last())
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class Site extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\Site
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Returns the setup for a dropdown option
|
||||
* which is used in the changes dropdown
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace Kirby\Panel;
|
|||
*/
|
||||
class User extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Kirby\Cms\User
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* Breadcrumb array
|
||||
*
|
||||
|
@ -193,14 +198,8 @@ class User extends Model
|
|||
$user = $this->model;
|
||||
|
||||
return [
|
||||
'next' => function () use ($user) {
|
||||
$next = $user->next();
|
||||
return $next ? $next->panel()->toLink('username') : null;
|
||||
},
|
||||
'prev' => function () use ($user) {
|
||||
$prev = $user->prev();
|
||||
return $prev ? $prev->panel()->toLink('username') : null;
|
||||
}
|
||||
'next' => fn () => $this->toPrevNextLink($user->next(), 'username'),
|
||||
'prev' => fn () => $this->toPrevNextLink($user->prev(), 'username')
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -335,6 +335,29 @@ class A
|
|||
return array_pop($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number of random elements from an array,
|
||||
* either in original or shuffled order
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $count
|
||||
* @param bool $shuffle
|
||||
* @return array
|
||||
*/
|
||||
public static function random(array $array, int $count = 1, bool $shuffle = false): array
|
||||
{
|
||||
if ($shuffle) {
|
||||
return array_slice(self::shuffle($array), 0, $count);
|
||||
}
|
||||
|
||||
if ($count === 1) {
|
||||
$key = array_rand($array);
|
||||
return [$key => $array[$key]];
|
||||
}
|
||||
|
||||
return self::get($array, array_rand($array, $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an array up with additional elements to certain amount.
|
||||
*
|
||||
|
@ -726,4 +749,37 @@ class A
|
|||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the array using the given callback
|
||||
* using both value and key
|
||||
* @since 3.6.5
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $callback
|
||||
* @return array
|
||||
*/
|
||||
public static function filter(array $array, callable $callback): array
|
||||
{
|
||||
return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove key(s) from an array
|
||||
* @since 3.6.5
|
||||
*
|
||||
* @param array $array
|
||||
* @param int|string|array $keys
|
||||
* @return array
|
||||
*/
|
||||
public static function without(array $array, $keys): array
|
||||
{
|
||||
if (is_int($keys) || is_string($keys)) {
|
||||
$keys = static::wrap($keys);
|
||||
}
|
||||
|
||||
return static::filter($array, function ($value, $key) use ($keys) {
|
||||
return in_array($key, $keys, true) === false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -870,6 +870,25 @@ class Collection extends Iterator implements Countable
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new collection consisting of random elements,
|
||||
* from the original collection, shuffled or ordered
|
||||
*
|
||||
* @param int $count
|
||||
* @param bool $shuffle
|
||||
* @return static
|
||||
*/
|
||||
public function random(int $count = 1, bool $shuffle = false)
|
||||
{
|
||||
if ($shuffle) {
|
||||
return $this->shuffle()->slice(0, $count);
|
||||
}
|
||||
|
||||
$collection = clone $this;
|
||||
$collection->data = A::random($collection->data, $count);
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element from the array by key
|
||||
*
|
||||
|
|
|
@ -500,11 +500,7 @@ class Html extends Xml
|
|||
($attr['allowfullscreen'] ?? true) === true
|
||||
) {
|
||||
$attr['allow'] = 'fullscreen';
|
||||
}
|
||||
|
||||
// remove deprecated attribute
|
||||
if (isset($attr['allowfullscreen']) === true) {
|
||||
unset($attr['allowfullscreen']);
|
||||
$attr['allowfullscreen'] = true;
|
||||
}
|
||||
|
||||
return $attr;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Kirby\Toolkit;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -62,14 +63,31 @@ class Obj extends stdClass
|
|||
}
|
||||
|
||||
/**
|
||||
* Property Getter
|
||||
* Gets one or multiple properties of the object
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $fallback
|
||||
* @param string|array $property
|
||||
* @param mixed $fallback If multiple properties are requested:
|
||||
* Associative array of fallback values per key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $property, $fallback = null)
|
||||
public function get($property, $fallback = null)
|
||||
{
|
||||
if (is_array($property)) {
|
||||
if ($fallback === null) {
|
||||
$fallback = [];
|
||||
}
|
||||
|
||||
if (!is_array($fallback)) {
|
||||
throw new InvalidArgumentException('The fallback value must be an array when getting multiple properties');
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($property as $key) {
|
||||
$result[$key] = $this->$key ?? $fallback[$key] ?? null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->$property ?? $fallback;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,12 @@ class Pagination
|
|||
|
||||
$params = [];
|
||||
|
||||
if (is_array($a) === true) {
|
||||
if (is_a($a, static::class) === true) {
|
||||
/**
|
||||
* First argument is a pagination/self object
|
||||
*/
|
||||
return $a;
|
||||
} elseif (is_array($a) === true) {
|
||||
|
||||
/**
|
||||
* First argument is an option array
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Kirby\Toolkit;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use IntlDateFormatter;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
|
@ -264,17 +266,33 @@ class Str
|
|||
* according to locale settings
|
||||
*
|
||||
* @param int|null $time
|
||||
* @param string|null $format
|
||||
* @param string $handler date or strftime
|
||||
* @param string|\IntlDateFormatter|null $format
|
||||
* @param string $handler date, intl or strftime
|
||||
* @return string|int
|
||||
*/
|
||||
public static function date(?int $time = null, ?string $format = null, string $handler = 'date')
|
||||
public static function date(?int $time = null, $format = null, string $handler = 'date')
|
||||
{
|
||||
if (is_null($format) === true) {
|
||||
return $time;
|
||||
}
|
||||
|
||||
// separately handle strftime to be able
|
||||
// $format is an IntlDateFormatter instance
|
||||
if (is_a($format, 'IntlDateFormatter') === true) {
|
||||
return $format->format($time ?? time());
|
||||
}
|
||||
|
||||
// `intl` handler
|
||||
if ($handler === 'intl') {
|
||||
$datetime = new DateTime();
|
||||
|
||||
if ($time !== null) {
|
||||
$datetime->setTimestamp($time);
|
||||
}
|
||||
|
||||
return IntlDateFormatter::formatObject($datetime, $format);
|
||||
}
|
||||
|
||||
// handle `strftime` to be able
|
||||
// to suppress deprecation warning
|
||||
// TODO: remove strftime support for PHP 9.0
|
||||
if ($handler === 'strftime') {
|
||||
|
|
56
kirby/vendor/composer/installed.json
vendored
56
kirby/vendor/composer/installed.json
vendored
|
@ -178,36 +178,36 @@
|
|||
},
|
||||
{
|
||||
"name": "laminas/laminas-escaper",
|
||||
"version": "2.9.0",
|
||||
"version_normalized": "2.9.0.0",
|
||||
"version": "2.10.0",
|
||||
"version_normalized": "2.10.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-escaper.git",
|
||||
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f"
|
||||
"reference": "58af67282db37d24e584a837a94ee55b9c7552be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/891ad70986729e20ed2e86355fcf93c9dc238a5f",
|
||||
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/58af67282db37d24e584a837a94ee55b9c7552be",
|
||||
"reference": "58af67282db37d24e584a837a94ee55b9c7552be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
"ext-ctype": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-escaper": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.26.6",
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"psalm/plugin-phpunit": "^0.12.2",
|
||||
"vimeo/psalm": "^3.16"
|
||||
"maglnet/composer-require-checker": "^3.8.0",
|
||||
"phpunit/phpunit": "^9.5.18",
|
||||
"psalm/plugin-phpunit": "^0.16.1",
|
||||
"vimeo/psalm": "^4.22.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "*",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"time": "2021-09-02T17:10:53+00:00",
|
||||
"time": "2022-03-08T20:15:36+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -495,8 +495,8 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.24.0",
|
||||
"version_normalized": "1.24.0.0",
|
||||
"version": "v1.25.0",
|
||||
"version_normalized": "1.25.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
|
@ -529,12 +529,12 @@
|
|||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
|
@ -565,7 +565,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -672,8 +672,8 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.24.0",
|
||||
"version_normalized": "1.24.0.0",
|
||||
"version": "v1.25.0",
|
||||
"version_normalized": "1.25.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
|
@ -707,12 +707,12 @@
|
|||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
|
@ -738,7 +738,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
22
kirby/vendor/composer/installed.php
vendored
22
kirby/vendor/composer/installed.php
vendored
|
@ -1,7 +1,7 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'pretty_version' => '3.6.3',
|
||||
'version' => '3.6.3.0',
|
||||
'pretty_version' => '3.6.6',
|
||||
'version' => '3.6.6.0',
|
||||
'type' => 'kirby-cms',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
@ -29,8 +29,8 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'getkirby/cms' => array(
|
||||
'pretty_version' => '3.6.3',
|
||||
'version' => '3.6.3.0',
|
||||
'pretty_version' => '3.6.6',
|
||||
'version' => '3.6.6.0',
|
||||
'type' => 'kirby-cms',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
@ -47,12 +47,12 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'laminas/laminas-escaper' => array(
|
||||
'pretty_version' => '2.9.0',
|
||||
'version' => '2.9.0.0',
|
||||
'pretty_version' => '2.10.0',
|
||||
'version' => '2.10.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../laminas/laminas-escaper',
|
||||
'aliases' => array(),
|
||||
'reference' => '891ad70986729e20ed2e86355fcf93c9dc238a5f',
|
||||
'reference' => '58af67282db37d24e584a837a94ee55b9c7552be',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'league/color-extractor' => array(
|
||||
|
@ -98,8 +98,8 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-intl-idn' => array(
|
||||
'pretty_version' => 'v1.24.0',
|
||||
'version' => '1.24.0.0',
|
||||
'pretty_version' => 'v1.25.0',
|
||||
'version' => '1.25.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
|
||||
'aliases' => array(),
|
||||
|
@ -116,8 +116,8 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-mbstring' => array(
|
||||
'pretty_version' => 'v1.24.0',
|
||||
'version' => '1.24.0.0',
|
||||
'pretty_version' => 'v1.25.0',
|
||||
'version' => '1.25.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||
'aliases' => array(),
|
||||
|
|
|
@ -16,22 +16,30 @@
|
|||
"forum": "https://discourse.laminas.dev"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
"sort-packages": true,
|
||||
"platform": {
|
||||
"php": "7.4.99"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"composer/package-versions-deprecated": true,
|
||||
"infection/extension-installer": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ~8.0.0 || ~8.1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "*",
|
||||
"php": "^7.4 || ~8.0.0 || ~8.1.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.26.6",
|
||||
"laminas/laminas-coding-standard": "~2.3.0",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"psalm/plugin-phpunit": "^0.12.2",
|
||||
"vimeo/psalm": "^3.16"
|
||||
"maglnet/composer-require-checker": "^3.8.0",
|
||||
"phpunit/phpunit": "^9.5.18",
|
||||
"psalm/plugin-phpunit": "^0.16.1",
|
||||
"vimeo/psalm": "^4.22.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
1877
kirby/vendor/laminas/laminas-escaper/composer.lock
generated
vendored
1877
kirby/vendor/laminas/laminas-escaper/composer.lock
generated
vendored
File diff suppressed because it is too large
Load diff
|
@ -6,10 +6,8 @@ namespace Laminas\Escaper;
|
|||
|
||||
use function bin2hex;
|
||||
use function ctype_digit;
|
||||
use function function_exists;
|
||||
use function hexdec;
|
||||
use function htmlspecialchars;
|
||||
use function iconv;
|
||||
use function in_array;
|
||||
use function mb_convert_encoding;
|
||||
use function ord;
|
||||
|
@ -38,7 +36,7 @@ class Escaper
|
|||
* entities that XML supports. Using HTML entities would result in this error:
|
||||
* XML Parsing Error: undefined entity
|
||||
*
|
||||
* @var array
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected static $htmlNamedEntityMap = [
|
||||
34 => 'quot', // quotation mark
|
||||
|
@ -67,6 +65,7 @@ class Escaper
|
|||
* Static Matcher which escapes characters for HTML Attribute contexts
|
||||
*
|
||||
* @var callable
|
||||
* @psalm-var callable(array<array-key, string>):string
|
||||
*/
|
||||
protected $htmlAttrMatcher;
|
||||
|
||||
|
@ -74,6 +73,7 @@ class Escaper
|
|||
* Static Matcher which escapes characters for Javascript contexts
|
||||
*
|
||||
* @var callable
|
||||
* @psalm-var callable(array<array-key, string>):string
|
||||
*/
|
||||
protected $jsMatcher;
|
||||
|
||||
|
@ -81,6 +81,7 @@ class Escaper
|
|||
* Static Matcher which escapes characters for CSS Attribute contexts
|
||||
*
|
||||
* @var callable
|
||||
* @psalm-var callable(array<array-key, string>):string
|
||||
*/
|
||||
protected $cssMatcher;
|
||||
|
||||
|
@ -255,7 +256,7 @@ class Escaper
|
|||
* Callback function for preg_replace_callback that applies HTML Attribute
|
||||
* escaping to all matches.
|
||||
*
|
||||
* @param array $matches
|
||||
* @param array<array-key, string> $matches
|
||||
* @return string
|
||||
*/
|
||||
protected function htmlAttrMatcher($matches)
|
||||
|
@ -302,7 +303,7 @@ class Escaper
|
|||
* Callback function for preg_replace_callback that applies Javascript
|
||||
* escaping to all matches.
|
||||
*
|
||||
* @param array $matches
|
||||
* @param array<array-key, string> $matches
|
||||
* @return string
|
||||
*/
|
||||
protected function jsMatcher($matches)
|
||||
|
@ -325,7 +326,7 @@ class Escaper
|
|||
* Callback function for preg_replace_callback that applies CSS
|
||||
* escaping to all matches.
|
||||
*
|
||||
* @param array $matches
|
||||
* @param array<array-key, string> $matches
|
||||
* @return string
|
||||
*/
|
||||
protected function cssMatcher($matches)
|
||||
|
@ -391,32 +392,21 @@ class Escaper
|
|||
}
|
||||
|
||||
/**
|
||||
* Encoding conversion helper which wraps iconv and mbstring where they exist or throws
|
||||
* and exception where neither is available.
|
||||
* Encoding conversion helper which wraps mb_convert_encoding
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $to
|
||||
* @param array|string $from
|
||||
* @throws Exception\RuntimeException
|
||||
* @return string
|
||||
*/
|
||||
protected function convertEncoding($string, $to, $from)
|
||||
{
|
||||
if (function_exists('iconv')) {
|
||||
$result = iconv($from, $to, $string);
|
||||
} elseif (function_exists('mb_convert_encoding')) {
|
||||
$result = mb_convert_encoding($string, $to, $from);
|
||||
} else {
|
||||
throw new Exception\RuntimeException(
|
||||
static::class
|
||||
. ' requires either the iconv or mbstring extension to be installed'
|
||||
. ' when escaping for non UTF-8 strings.'
|
||||
);
|
||||
}
|
||||
$result = mb_convert_encoding($string, $to, $from);
|
||||
|
||||
if ($result === false) {
|
||||
return ''; // return non-fatal blank string on encoding errors from users
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue