Upgrade to rc5
This commit is contained in:
@@ -48,7 +48,7 @@ return [
|
||||
return $file->next();
|
||||
},
|
||||
'nextWithTemplate' => function (File $file) {
|
||||
$files = $file->templateSiblings()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
$files = $file->templateSiblings()->sort('sort', 'asc', 'filename', 'asc');
|
||||
$index = $files->indexOf($file);
|
||||
|
||||
return $files->nth($index + 1);
|
||||
@@ -72,7 +72,7 @@ return [
|
||||
return $file->prev();
|
||||
},
|
||||
'prevWithTemplate' => function (File $file) {
|
||||
$files = $file->templateSiblings()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
$files = $file->templateSiblings()->sort('sort', 'asc', 'filename', 'asc');
|
||||
$index = $files->indexOf($file);
|
||||
|
||||
return $files->nth($index - 1);
|
||||
|
@@ -27,7 +27,7 @@ return [
|
||||
return $page->errors();
|
||||
},
|
||||
'files' => function (Page $page) {
|
||||
return $page->files()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
return $page->files()->sort('sort', 'asc', 'filename', 'asc');
|
||||
},
|
||||
'hasChildren' => function (Page $page) {
|
||||
return $page->hasChildren();
|
||||
@@ -47,9 +47,9 @@ return [
|
||||
'next' => function (Page $page) {
|
||||
return $page
|
||||
->nextAll()
|
||||
->filterBy('intendedTemplate', $page->intendedTemplate())
|
||||
->filterBy('status', $page->status())
|
||||
->filterBy('isReadable', true)
|
||||
->filter('intendedTemplate', $page->intendedTemplate())
|
||||
->filter('status', $page->status())
|
||||
->filter('isReadable', true)
|
||||
->first();
|
||||
},
|
||||
'num' => function (Page $page) {
|
||||
@@ -73,9 +73,9 @@ return [
|
||||
'prev' => function (Page $page) {
|
||||
return $page
|
||||
->prevAll()
|
||||
->filterBy('intendedTemplate', $page->intendedTemplate())
|
||||
->filterBy('status', $page->status())
|
||||
->filterBy('isReadable', true)
|
||||
->filter('intendedTemplate', $page->intendedTemplate())
|
||||
->filter('status', $page->status())
|
||||
->filter('isReadable', true)
|
||||
->last();
|
||||
},
|
||||
'previewUrl' => function (Page $page) {
|
||||
|
@@ -24,7 +24,7 @@ return [
|
||||
return $site->drafts();
|
||||
},
|
||||
'files' => function (Site $site) {
|
||||
return $site->files()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
return $site->files()->sort('sort', 'asc', 'filename', 'asc');
|
||||
},
|
||||
'options' => function (Site $site) {
|
||||
return $site->permissions()->toArray();
|
||||
|
@@ -35,6 +35,21 @@ return [
|
||||
'license' => function (System $system) {
|
||||
return $system->license();
|
||||
},
|
||||
'loginMethods' => function (System $system) {
|
||||
return array_keys($system->loginMethods());
|
||||
},
|
||||
'pendingChallenge' => function () {
|
||||
if ($this->session()->get('kirby.challenge.email') === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// fake the email challenge if no challenge was created
|
||||
// to avoid leaking whether the user exists
|
||||
return $this->session()->get('kirby.challenge.type', 'email');
|
||||
},
|
||||
'pendingEmail' => function () {
|
||||
return $this->session()->get('kirby.challenge.email');
|
||||
},
|
||||
'requirements' => function (System $system) {
|
||||
return $system->toArray();
|
||||
},
|
||||
@@ -86,6 +101,9 @@ return [
|
||||
'isOk',
|
||||
'isInstallable',
|
||||
'isInstalled',
|
||||
'loginMethods',
|
||||
'pendingChallenge',
|
||||
'pendingEmail',
|
||||
'title',
|
||||
'translation'
|
||||
],
|
||||
|
@@ -24,7 +24,7 @@ return [
|
||||
return $user->email();
|
||||
},
|
||||
'files' => function (User $user) {
|
||||
return $user->files()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
return $user->files()->sort('sort', 'asc', 'filename', 'asc');
|
||||
},
|
||||
'id' => function (User $user) {
|
||||
return $user->id();
|
||||
|
@@ -19,7 +19,7 @@ return [
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/login',
|
||||
'pattern' => 'auth/code',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
@@ -30,11 +30,7 @@ return [
|
||||
throw new InvalidArgumentException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
$email = $this->requestBody('email');
|
||||
$long = $this->requestBody('long');
|
||||
$password = $this->requestBody('password');
|
||||
|
||||
$user = $this->kirby()->auth()->login($email, $password, $long);
|
||||
$user = $auth->verifyChallenge($this->requestBody('code'));
|
||||
|
||||
return [
|
||||
'code' => 200,
|
||||
@@ -43,6 +39,65 @@ return [
|
||||
];
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/login',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$auth = $this->kirby()->auth();
|
||||
$methods = $this->kirby()->system()->loginMethods();
|
||||
|
||||
// csrf token check
|
||||
if ($auth->type() === 'session' && $auth->csrf() === false) {
|
||||
throw new InvalidArgumentException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
$email = $this->requestBody('email');
|
||||
$long = $this->requestBody('long');
|
||||
$password = $this->requestBody('password');
|
||||
|
||||
if ($password) {
|
||||
if (isset($methods['password']) !== true) {
|
||||
throw new InvalidArgumentException('Login with password is not enabled');
|
||||
}
|
||||
|
||||
if (
|
||||
isset($methods['password']['2fa']) === true &&
|
||||
$methods['password']['2fa'] === true
|
||||
) {
|
||||
$challenge = $auth->login2fa($email, $password, $long);
|
||||
} else {
|
||||
$user = $auth->login($email, $password, $long);
|
||||
}
|
||||
} else {
|
||||
if (isset($methods['code']) === true) {
|
||||
$mode = 'login';
|
||||
} elseif (isset($methods['password-reset']) === true) {
|
||||
$mode = 'password-reset';
|
||||
} else {
|
||||
throw new InvalidArgumentException('Login without password is not enabled');
|
||||
}
|
||||
|
||||
$challenge = $auth->createChallenge($email, $long, $mode);
|
||||
}
|
||||
|
||||
if (isset($user)) {
|
||||
return [
|
||||
'code' => 200,
|
||||
'status' => 'ok',
|
||||
'user' => $this->resolve($user)->view('auth')->toArray()
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'code' => 200,
|
||||
'status' => 'ok',
|
||||
|
||||
// don't leak users that don't exist at this point
|
||||
'challenge' => $challenge ?? 'email'
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/logout',
|
||||
'method' => 'POST',
|
||||
|
@@ -27,7 +27,7 @@ return [
|
||||
'pattern' => '(:all)/files',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $path) {
|
||||
return $this->parent($path)->files()->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
return $this->parent($path)->files()->sort('sort', 'asc', 'filename', 'asc');
|
||||
}
|
||||
],
|
||||
[
|
||||
@@ -110,7 +110,7 @@ return [
|
||||
$files = $this
|
||||
->site()
|
||||
->index(true)
|
||||
->filterBy('isReadable', true)
|
||||
->filter('isReadable', true)
|
||||
->files();
|
||||
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
|
@@ -78,7 +78,7 @@ return [
|
||||
$pages = $this
|
||||
->site()
|
||||
->index(true)
|
||||
->filterBy('isReadable', true);
|
||||
->filter('isReadable', true);
|
||||
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
return $pages->search($this->requestQuery('q'));
|
||||
|
@@ -11,7 +11,7 @@ return [
|
||||
'pattern' => 'users',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
return $this->users();
|
||||
return $this->users()->sort('username', 'asc', 'email', 'asc');
|
||||
}
|
||||
],
|
||||
[
|
||||
|
1
kirby/config/blocks/code/code.php
Executable file
1
kirby/config/blocks/code/code.php
Executable file
@@ -0,0 +1 @@
|
||||
<pre><code class="language-<?= $block->language()->or('text') ?>"><?= $block->code()->html(false) ?></code></pre>
|
59
kirby/config/blocks/code/code.yml
Executable file
59
kirby/config/blocks/code/code.yml
Executable file
@@ -0,0 +1,59 @@
|
||||
name: field.blocks.code.name
|
||||
icon: code
|
||||
wysiwyg: true
|
||||
preview: code
|
||||
fields:
|
||||
code:
|
||||
label: field.blocks.code.name
|
||||
type: textarea
|
||||
placeholder: field.blocks.code.placeholder
|
||||
buttons: false
|
||||
font: monospace
|
||||
language:
|
||||
label: field.blocks.code.language
|
||||
type: select
|
||||
default: text
|
||||
options:
|
||||
bash: Bash
|
||||
basic: BASIC
|
||||
c: C
|
||||
clojure: Clojure
|
||||
cpp: C++
|
||||
csharp: C#
|
||||
css: CSS
|
||||
diff: Diff
|
||||
elixir: Elixir
|
||||
elm: Elm
|
||||
erlang: Erlang
|
||||
go: Go
|
||||
graphql: GraphQL
|
||||
haskell: Haskell
|
||||
html: HTML
|
||||
java: Java
|
||||
js: JavaScript
|
||||
json: JSON
|
||||
latext: LaTeX
|
||||
less: Less
|
||||
lisp: Lisp
|
||||
lua: Lua
|
||||
makefile: Makefile
|
||||
markdown: Markdown
|
||||
markup: Markup
|
||||
objectivec: Objective-C
|
||||
pascal: Pascal
|
||||
perl: Perl
|
||||
php: PHP
|
||||
text: Plain Text
|
||||
python: Python
|
||||
r: R
|
||||
ruby: Ruby
|
||||
rust: Rust
|
||||
sass: Sass
|
||||
scss: SCSS
|
||||
shell: Shell
|
||||
sql: SQL
|
||||
swift: Swift
|
||||
typescript: TypeScript
|
||||
vbnet: VB.net
|
||||
xml: XML
|
||||
yaml: YAML
|
9
kirby/config/blocks/gallery/gallery.php
Executable file
9
kirby/config/blocks/gallery/gallery.php
Executable file
@@ -0,0 +1,9 @@
|
||||
<figure>
|
||||
<ul>
|
||||
<?php foreach ($block->images()->toFiles() as $image): ?>
|
||||
<li>
|
||||
<?= $image ?>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</figure>
|
15
kirby/config/blocks/gallery/gallery.yml
Executable file
15
kirby/config/blocks/gallery/gallery.yml
Executable file
@@ -0,0 +1,15 @@
|
||||
name: field.blocks.gallery.name
|
||||
icon: dashboard
|
||||
preview: gallery
|
||||
fields:
|
||||
images:
|
||||
label: field.blocks.gallery.images.label
|
||||
type: files
|
||||
multiple: true
|
||||
layout: cards
|
||||
size: tiny
|
||||
empty: field.blocks.gallery.images.empty
|
||||
uploads:
|
||||
template: blocks/image
|
||||
image:
|
||||
ratio: 1/1
|
1
kirby/config/blocks/heading/heading.php
Executable file
1
kirby/config/blocks/heading/heading.php
Executable file
@@ -0,0 +1 @@
|
||||
<<?= $level = $block->level()->or('h2') ?>><?= $block->text() ?></<?= $level ?>>
|
24
kirby/config/blocks/heading/heading.yml
Executable file
24
kirby/config/blocks/heading/heading.yml
Executable file
@@ -0,0 +1,24 @@
|
||||
name: field.blocks.heading.name
|
||||
icon: title
|
||||
wysiwyg: true
|
||||
preview: heading
|
||||
fields:
|
||||
level:
|
||||
label: field.blocks.heading.level
|
||||
type: select
|
||||
empty: false
|
||||
default: "h2"
|
||||
width: 1/6
|
||||
options:
|
||||
- h1
|
||||
- h2
|
||||
- h3
|
||||
- h4
|
||||
- h5
|
||||
- h6
|
||||
text:
|
||||
label: field.blocks.heading.text
|
||||
type: writer
|
||||
inline: true
|
||||
width: 5/6
|
||||
placeholder: field.blocks.heading.placeholder
|
34
kirby/config/blocks/image/image.php
Executable file
34
kirby/config/blocks/image/image.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
$alt = $block->alt();
|
||||
$caption = $block->caption();
|
||||
$crop = $block->crop()->isTrue();
|
||||
$link = $block->link();
|
||||
$ratio = $block->ratio()->or('auto');
|
||||
$src = null;
|
||||
|
||||
if ($block->location() == 'web') {
|
||||
$src = $block->src();
|
||||
} elseif ($image = $block->image()->toFile()) {
|
||||
$alt = $alt ?? $image->alt();
|
||||
$src = $image->url();
|
||||
}
|
||||
|
||||
?>
|
||||
<?php if ($src): ?>
|
||||
<figure<?= attr(['data-ratio' => $ratio, 'data-crop' => $crop], ' ') ?>>
|
||||
<?php if ($link->isNotEmpty()): ?>
|
||||
<a href="<?= $link->toUrl() ?>">
|
||||
<img src="<?= $src ?>" alt="<?= $alt ?>">
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<img src="<?= $src ?>" alt="<?= $alt ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($caption->isNotEmpty()): ?>
|
||||
<figcaption>
|
||||
<?= $caption ?>
|
||||
</figcaption>
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
<?php endif ?>
|
59
kirby/config/blocks/image/image.yml
Executable file
59
kirby/config/blocks/image/image.yml
Executable file
@@ -0,0 +1,59 @@
|
||||
name: field.blocks.image.name
|
||||
icon: image
|
||||
preview: image
|
||||
fields:
|
||||
location:
|
||||
label: field.blocks.image.location
|
||||
type: radio
|
||||
columns: 2
|
||||
default: "kirby"
|
||||
options:
|
||||
kirby: Kirby
|
||||
web: Web
|
||||
image:
|
||||
label: field.blocks.image.name
|
||||
type: files
|
||||
multiple: false
|
||||
image:
|
||||
back: black
|
||||
uploads:
|
||||
template: blocks/image
|
||||
when:
|
||||
location: kirby
|
||||
src:
|
||||
label: Image URL
|
||||
type: url
|
||||
when:
|
||||
location: web
|
||||
alt:
|
||||
label: field.blocks.image.alt
|
||||
type: text
|
||||
icon: title
|
||||
caption:
|
||||
label: field.blocks.image.caption
|
||||
type: writer
|
||||
icon: text
|
||||
inline: true
|
||||
link:
|
||||
label: field.blocks.image.link
|
||||
type: text
|
||||
icon: url
|
||||
ratio:
|
||||
label: field.blocks.image.ratio
|
||||
type: select
|
||||
placeholder: Auto
|
||||
width: 1/2
|
||||
options:
|
||||
1/1: "1:1"
|
||||
16/9: "16:9"
|
||||
10/8: "10:8"
|
||||
21/9: "21:9"
|
||||
7/5: "7:5"
|
||||
4/3: "4:3"
|
||||
5/3: "5:3"
|
||||
3/2: "3:2"
|
||||
3/1: "3:1"
|
||||
crop:
|
||||
label: field.blocks.image.crop
|
||||
type: toggle
|
||||
width: 1/2
|
1
kirby/config/blocks/list/list.php
Executable file
1
kirby/config/blocks/list/list.php
Executable file
@@ -0,0 +1 @@
|
||||
<?= $block->text();
|
8
kirby/config/blocks/list/list.yml
Executable file
8
kirby/config/blocks/list/list.yml
Executable file
@@ -0,0 +1,8 @@
|
||||
name: field.blocks.list.name
|
||||
icon: list-bullet
|
||||
wysiwyg: true
|
||||
preview: list
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.list.name
|
||||
type: list
|
1
kirby/config/blocks/markdown/markdown.php
Executable file
1
kirby/config/blocks/markdown/markdown.php
Executable file
@@ -0,0 +1 @@
|
||||
<?= $block->text()->kt();
|
11
kirby/config/blocks/markdown/markdown.yml
Executable file
11
kirby/config/blocks/markdown/markdown.yml
Executable file
@@ -0,0 +1,11 @@
|
||||
name: field.blocks.markdown.name
|
||||
icon: markdown
|
||||
preview: markdown
|
||||
wysiwyg: true
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.markdown.label
|
||||
placeholder: field.blocks.markdown.placeholder
|
||||
type: textarea
|
||||
buttons: false
|
||||
font: monospace
|
8
kirby/config/blocks/quote/quote.php
Executable file
8
kirby/config/blocks/quote/quote.php
Executable file
@@ -0,0 +1,8 @@
|
||||
<blockquote>
|
||||
<?= $block->text() ?>
|
||||
<?php if ($block->citation()->isNotEmpty()): ?>
|
||||
<footer>
|
||||
<?= $block->citation() ?>
|
||||
</footer>
|
||||
<?php endif ?>
|
||||
</blockquote>
|
17
kirby/config/blocks/quote/quote.yml
Executable file
17
kirby/config/blocks/quote/quote.yml
Executable file
@@ -0,0 +1,17 @@
|
||||
name: field.blocks.quote.name
|
||||
icon: quote
|
||||
wysiwyg: true
|
||||
preview: quote
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.quote.text.label
|
||||
placeholder: field.blocks.quote.text.placeholder
|
||||
type: writer
|
||||
inline: true
|
||||
icon: quote
|
||||
citation:
|
||||
label: field.blocks.quote.citation.label
|
||||
placeholder: field.blocks.quote.citation.placeholder
|
||||
type: writer
|
||||
inline: true
|
||||
icon: user
|
3
kirby/config/blocks/table/table.yml
Executable file
3
kirby/config/blocks/table/table.yml
Executable file
@@ -0,0 +1,3 @@
|
||||
name: Table
|
||||
icon: menu
|
||||
preview: table
|
1
kirby/config/blocks/text/text.php
Executable file
1
kirby/config/blocks/text/text.php
Executable file
@@ -0,0 +1 @@
|
||||
<?= $block->text();
|
9
kirby/config/blocks/text/text.yml
Executable file
9
kirby/config/blocks/text/text.yml
Executable file
@@ -0,0 +1,9 @@
|
||||
name: field.blocks.text.name
|
||||
icon: text
|
||||
wysiwyg: true
|
||||
preview: text
|
||||
fields:
|
||||
text:
|
||||
type: writer
|
||||
nodes: false
|
||||
placeholder: field.blocks.text.placeholder
|
8
kirby/config/blocks/video/video.php
Executable file
8
kirby/config/blocks/video/video.php
Executable file
@@ -0,0 +1,8 @@
|
||||
<?php if ($block->url()->isNotEmpty()): ?>
|
||||
<figure>
|
||||
<?= video($block->url()) ?>
|
||||
<?php if ($block->caption()->isNotEmpty()): ?>
|
||||
<figcaption><?= $block->caption() ?></figcaption>
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
<?php endif ?>
|
12
kirby/config/blocks/video/video.yml
Executable file
12
kirby/config/blocks/video/video.yml
Executable file
@@ -0,0 +1,12 @@
|
||||
name: field.blocks.video.name
|
||||
icon: video
|
||||
preview: video
|
||||
fields:
|
||||
url:
|
||||
label: field.blocks.video.url.label
|
||||
type: url
|
||||
placeholder: field.blocks.video.url.placeholder
|
||||
caption:
|
||||
label: field.blocks.video.caption
|
||||
type: writer
|
||||
inline: true
|
@@ -1,7 +1,26 @@
|
||||
<?php
|
||||
|
||||
$blocksRoot = __DIR__ . '/blocks';
|
||||
|
||||
return [
|
||||
'files/default' => __DIR__ . '/blueprints/file.yml',
|
||||
'pages/default' => __DIR__ . '/blueprints/page.yml',
|
||||
'site' => __DIR__ . '/blueprints/site.yml'
|
||||
// blocks
|
||||
'blocks/code' => $blocksRoot . '/code/code.yml',
|
||||
'blocks/gallery' => $blocksRoot . '/gallery/gallery.yml',
|
||||
'blocks/heading' => $blocksRoot . '/heading/heading.yml',
|
||||
'blocks/image' => $blocksRoot . '/image/image.yml',
|
||||
'blocks/list' => $blocksRoot . '/list/list.yml',
|
||||
'blocks/markdown' => $blocksRoot . '/markdown/markdown.yml',
|
||||
'blocks/quote' => $blocksRoot . '/quote/quote.yml',
|
||||
'blocks/table' => $blocksRoot . '/table/table.yml',
|
||||
'blocks/text' => $blocksRoot . '/text/text.yml',
|
||||
'blocks/video' => $blocksRoot . '/video/video.yml',
|
||||
|
||||
// file blueprints
|
||||
'files/default' => __DIR__ . '/blueprints/files/default.yml',
|
||||
|
||||
// page blueprints
|
||||
'pages/default' => __DIR__ . '/blueprints/pages/default.yml',
|
||||
|
||||
// site blueprints
|
||||
'site' => __DIR__ . '/blueprints/site.yml'
|
||||
];
|
||||
|
56
kirby/config/blueprints/blocks/code.yml
Executable file
56
kirby/config/blueprints/blocks/code.yml
Executable file
@@ -0,0 +1,56 @@
|
||||
name: Code
|
||||
icon: code
|
||||
fields:
|
||||
code:
|
||||
label: Code
|
||||
type: textarea
|
||||
buttons: false
|
||||
font: monospace
|
||||
language:
|
||||
label: Language
|
||||
type: select
|
||||
default: text
|
||||
options:
|
||||
bash: Bash
|
||||
basic: BASIC
|
||||
c: C
|
||||
clojure: Clojure
|
||||
cpp: C++
|
||||
csharp: C#
|
||||
css: CSS
|
||||
diff: Diff
|
||||
elixir: Elixir
|
||||
elm: Elm
|
||||
erlang: Erlang
|
||||
go: Go
|
||||
graphql: GraphQL
|
||||
haskell: Haskell
|
||||
html: HTML
|
||||
java: Java
|
||||
js: JavaScript
|
||||
json: JSON
|
||||
latext: LaTeX
|
||||
less: Less
|
||||
lisp: Lisp
|
||||
lua: Lua
|
||||
makefile: Makefile
|
||||
markdown: Markdown
|
||||
markup: Markup
|
||||
objectivec: Objective-C
|
||||
pascal: Pascal
|
||||
perl: Perl
|
||||
php: PHP
|
||||
text: Plain Text
|
||||
python: Python
|
||||
r: R
|
||||
ruby: Ruby
|
||||
rust: Rust
|
||||
sass: Sass
|
||||
scss: SCSS
|
||||
shell: Shell
|
||||
sql: SQL
|
||||
swift: Swift
|
||||
typescript: TypeScript
|
||||
vbnet: VB.net
|
||||
xml: XML
|
||||
yaml: YAML
|
21
kirby/config/blueprints/blocks/heading.yml
Executable file
21
kirby/config/blueprints/blocks/heading.yml
Executable file
@@ -0,0 +1,21 @@
|
||||
icon: title
|
||||
fields:
|
||||
text:
|
||||
type: text
|
||||
level:
|
||||
type: select
|
||||
width: 1/2
|
||||
default: 1
|
||||
empty: false
|
||||
default: "2"
|
||||
options:
|
||||
- value: "1"
|
||||
text: Heading 1
|
||||
- value: "2"
|
||||
text: Heading 2
|
||||
- value: "3"
|
||||
text: Heading 3
|
||||
id:
|
||||
type: text
|
||||
label: ID
|
||||
width: 1/2
|
16
kirby/config/blueprints/blocks/image.yml
Executable file
16
kirby/config/blueprints/blocks/image.yml
Executable file
@@ -0,0 +1,16 @@
|
||||
name: Image
|
||||
icon: image
|
||||
fields:
|
||||
image:
|
||||
type: files
|
||||
multiple: false
|
||||
alt:
|
||||
type: text
|
||||
icon: title
|
||||
caption:
|
||||
type: writer
|
||||
inline: true
|
||||
icon: text
|
||||
link:
|
||||
type: text
|
||||
icon: url
|
12
kirby/config/blueprints/blocks/quote.yml
Executable file
12
kirby/config/blueprints/blocks/quote.yml
Executable file
@@ -0,0 +1,12 @@
|
||||
name: Quote
|
||||
icon: quote
|
||||
fields:
|
||||
text:
|
||||
label: Quote Text
|
||||
type: writer
|
||||
inline: true
|
||||
citation:
|
||||
label: Citation
|
||||
type: writer
|
||||
inline: true
|
||||
placeholder: by …
|
25
kirby/config/blueprints/blocks/table.yml
Executable file
25
kirby/config/blueprints/blocks/table.yml
Executable file
@@ -0,0 +1,25 @@
|
||||
name: Table
|
||||
icon: menu
|
||||
fields:
|
||||
rows:
|
||||
label: Menu
|
||||
type: structure
|
||||
columns:
|
||||
dish: true
|
||||
description: true
|
||||
price:
|
||||
before: €
|
||||
width: 1/4
|
||||
align: right
|
||||
fields:
|
||||
dish:
|
||||
label: Dish
|
||||
type: text
|
||||
description:
|
||||
label: Description
|
||||
type: text
|
||||
price:
|
||||
label: Price
|
||||
type: number
|
||||
before: €
|
||||
step: 0.01
|
5
kirby/config/blueprints/blocks/text.yml
Executable file
5
kirby/config/blueprints/blocks/text.yml
Executable file
@@ -0,0 +1,5 @@
|
||||
name: Text
|
||||
icon: text
|
||||
fields:
|
||||
text:
|
||||
type: writer
|
8
kirby/config/blueprints/blocks/video.yml
Executable file
8
kirby/config/blueprints/blocks/video.yml
Executable file
@@ -0,0 +1,8 @@
|
||||
name: Video
|
||||
icon: video
|
||||
label: "{{ url }}"
|
||||
fields:
|
||||
url:
|
||||
type: url
|
||||
caption:
|
||||
type: writer
|
@@ -236,7 +236,7 @@ return [
|
||||
return $item->searchHits > 0 ? true : false;
|
||||
});
|
||||
|
||||
return $results->sortBy('searchScore', 'desc');
|
||||
return $results->sort('searchScore', 'desc');
|
||||
},
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'blocks' => 'Kirby\Form\Field\BlocksField',
|
||||
'checkboxes' => __DIR__ . '/fields/checkboxes.php',
|
||||
'date' => __DIR__ . '/fields/date.php',
|
||||
'email' => __DIR__ . '/fields/email.php',
|
||||
@@ -9,7 +10,9 @@ return [
|
||||
'headline' => __DIR__ . '/fields/headline.php',
|
||||
'hidden' => __DIR__ . '/fields/hidden.php',
|
||||
'info' => __DIR__ . '/fields/info.php',
|
||||
'layout' => 'Kirby\Form\Field\LayoutField',
|
||||
'line' => __DIR__ . '/fields/line.php',
|
||||
'list' => __DIR__ . '/fields/list.php',
|
||||
'multiselect' => __DIR__ . '/fields/multiselect.php',
|
||||
'number' => __DIR__ . '/fields/number.php',
|
||||
'pages' => __DIR__ . '/fields/pages.php',
|
||||
@@ -24,5 +27,6 @@ return [
|
||||
'time' => __DIR__ . '/fields/time.php',
|
||||
'toggle' => __DIR__ . '/fields/toggle.php',
|
||||
'url' => __DIR__ . '/fields/url.php',
|
||||
'users' => __DIR__ . '/fields/users.php'
|
||||
'users' => __DIR__ . '/fields/users.php',
|
||||
'writer' => __DIR__ . '/fields/writer.php'
|
||||
];
|
||||
|
@@ -1,21 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Toolkit\I18n;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
return [
|
||||
'mixins' => ['datetime'],
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'placeholder' => null,
|
||||
|
||||
/**
|
||||
* Activate/deactivate the dropdown calendar
|
||||
*/
|
||||
'calendar' => function (bool $calendar = true) {
|
||||
return $calendar;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Default date when a new page/file/user gets created
|
||||
*/
|
||||
'default' => function ($default = null) {
|
||||
'default' => function (string $default = null) {
|
||||
return $default;
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines a custom format that is used when the field is saved
|
||||
* Custom format (dayjs tokens: `DD`, `MM`, `YYYY`) that is
|
||||
* used to display the field in the Panel
|
||||
*/
|
||||
'format' => function (string $format = null) {
|
||||
return $format;
|
||||
'display' => function ($display = 'YYYY-MM-DD') {
|
||||
return I18n::translate($display, $display);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -24,22 +41,52 @@ return [
|
||||
'icon' => function (string $icon = 'calendar') {
|
||||
return $icon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Youngest date, which can be selected/saved
|
||||
* Latest date, which can be selected/saved (Y-m-d)
|
||||
*/
|
||||
'max' => function (string $max = null) {
|
||||
return $this->toDate($max);
|
||||
return $this->toDatetime($max);
|
||||
},
|
||||
/**
|
||||
* Oldest date, which can be selected/saved
|
||||
* Earliest date, which can be selected/saved (Y-m-d)
|
||||
*/
|
||||
'min' => function (string $min = null) {
|
||||
return $this->toDate($min);
|
||||
return $this->toDatetime($min);
|
||||
},
|
||||
|
||||
/**
|
||||
* The placeholder is not available
|
||||
* Round to the nearest: sub-options for `unit` (day) and `size` (1)
|
||||
*/
|
||||
'placeholder' => null,
|
||||
'step' => function ($step = null) {
|
||||
if ($step === null) {
|
||||
return [
|
||||
'size' => 1,
|
||||
'unit' => 'day'
|
||||
];
|
||||
}
|
||||
|
||||
if (is_array($step) === true) {
|
||||
return $step;
|
||||
}
|
||||
|
||||
if (is_int($step) === true) {
|
||||
return [
|
||||
'size' => $step,
|
||||
'unit' => 'day'
|
||||
];
|
||||
}
|
||||
|
||||
if (is_string($step) === true) {
|
||||
return [
|
||||
'size' => 1,
|
||||
'unit' => $step
|
||||
];
|
||||
}
|
||||
|
||||
throw new Exception('step option has to be defined as array');
|
||||
},
|
||||
|
||||
/**
|
||||
* Pass `true` or an array of time field options to show the time selector.
|
||||
*/
|
||||
@@ -55,27 +102,29 @@ return [
|
||||
],
|
||||
'computed' => [
|
||||
'default' => function () {
|
||||
return $this->toDate($this->default);
|
||||
return $this->toDatetime($this->default);
|
||||
},
|
||||
'format' => function () {
|
||||
return $this->props['format'] ?? ($this->time() === false ? 'Y-m-d' : 'Y-m-d H:i');
|
||||
'display' => function () {
|
||||
if ($this->display) {
|
||||
return Str::upper($this->display);
|
||||
}
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->toDate($this->value);
|
||||
},
|
||||
],
|
||||
'methods' => [
|
||||
'toDate' => function ($value) {
|
||||
if ($timestamp = timestamp($value, $this->time['step'] ?? 5)) {
|
||||
return date('Y-m-d H:i:s', $timestamp);
|
||||
'step' => function () {
|
||||
if ($this->time !== false) {
|
||||
$timeField = require __DIR__ . '/time.php';
|
||||
return $timeField['props']['step']($this->time['step'] ?? null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return $this->step;
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->toDatetime($this->value);
|
||||
},
|
||||
],
|
||||
'save' => function ($value) {
|
||||
if ($value !== null && $date = strtotime($value)) {
|
||||
return date($this->format(), $date);
|
||||
if ($value !== null && $timestamp = timestamp($value)) {
|
||||
$format = $this->time === false ? 'Y-m-d' : 'Y-m-d H:i:s';
|
||||
return $this->toISO($timestamp, $format);
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -86,7 +135,7 @@ return [
|
||||
$min = $this->min ? strtotime($this->min) : null;
|
||||
$max = $this->max ? strtotime($this->max) : null;
|
||||
$value = strtotime($this->value());
|
||||
$format = 'd.m.Y';
|
||||
$format = $this->time === false ? 'd.m.Y' : 'd.m.Y H:i';
|
||||
$errors = [];
|
||||
|
||||
if ($value && $min && $value < $min) {
|
||||
|
@@ -11,7 +11,6 @@ return [
|
||||
'before' => null,
|
||||
'default' => null,
|
||||
'disabled' => null,
|
||||
'help' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
'required' => null,
|
||||
|
@@ -4,6 +4,19 @@ use Kirby\Toolkit\I18n;
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'after' => null,
|
||||
'autofocus' => null,
|
||||
'before' => null,
|
||||
'default' => null,
|
||||
'disabled' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
'required' => null,
|
||||
'translate' => null,
|
||||
|
||||
/**
|
||||
* Text to be displayed
|
||||
*/
|
||||
|
12
kirby/config/fields/list.php
Executable file
12
kirby/config/fields/list.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`. Activate them all by passing `true`. Deactivate them all by passing `false`
|
||||
*/
|
||||
'marks' => function ($marks = true) {
|
||||
return $marks;
|
||||
}
|
||||
]
|
||||
];
|
16
kirby/config/fields/mixins/datetime.php
Executable file
16
kirby/config/fields/mixins/datetime.php
Executable file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'methods' => [
|
||||
'toDatetime' => function ($value, string $format = 'Y-m-d H:i:s') {
|
||||
if ($timestamp = timestamp($value, $this->step)) {
|
||||
return $this->toISO($timestamp, $format);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
'toISO' => function (int $time, string $format = 'Y-m-d H:i:s') {
|
||||
return date($format, $time);
|
||||
}
|
||||
]
|
||||
];
|
@@ -30,7 +30,7 @@ return [
|
||||
'template' => $template
|
||||
]);
|
||||
|
||||
$uploads['accept'] = $file->blueprint()->accept()['mime'] ?? '*';
|
||||
$uploads['accept'] = $file->blueprint()->acceptMime();
|
||||
} else {
|
||||
$uploads['accept'] = '*';
|
||||
}
|
||||
|
@@ -99,6 +99,7 @@ return [
|
||||
],
|
||||
[
|
||||
'pattern' => 'upload',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
$field = $this->field();
|
||||
$uploads = $field->uploads();
|
||||
|
@@ -1,24 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Toolkit\I18n;
|
||||
|
||||
return [
|
||||
'mixins' => ['datetime'],
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'placeholder' => null,
|
||||
|
||||
|
||||
/**
|
||||
* Sets the default time when a new page/file/user is created
|
||||
*/
|
||||
'default' => function ($default = null) {
|
||||
return $default;
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom format (dayjs tokens: `HH`, `hh`, `mm`, `ss`, `a`) that is
|
||||
* used to display the field in the Panel
|
||||
*/
|
||||
'display' => function ($display = null) {
|
||||
return I18n::translate($display, $display);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the clock icon
|
||||
*/
|
||||
'icon' => function (string $icon = 'clock') {
|
||||
return $icon;
|
||||
},
|
||||
/**
|
||||
* Latest time, which can be selected/saved (H:i or H:i:s)
|
||||
*/
|
||||
'max' => function (string $max = null) {
|
||||
return $max ? $this->toDatetime(date('Y-m-d ') . $max) : null;
|
||||
},
|
||||
/**
|
||||
* Earliest time, which can be selected/saved (H:i or H:i:s)
|
||||
*/
|
||||
'min' => function (string $min = null) {
|
||||
return $min ? $this->toDatetime(date('Y-m-d ') . $min) : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* `12` or `24` hour notation. If `12`, an AM/PM selector will be shown.
|
||||
*/
|
||||
@@ -26,10 +53,35 @@ return [
|
||||
return $value === 24 ? 24 : 12;
|
||||
},
|
||||
/**
|
||||
* The interval between minutes in the minutes select dropdown.
|
||||
* Round to the nearest: sub-options for `unit` (minute) and `size` (5)
|
||||
*/
|
||||
'step' => function (int $step = 5) {
|
||||
return $step;
|
||||
'step' => function ($step = null) {
|
||||
if ($step === null) {
|
||||
return [
|
||||
'size' => 5,
|
||||
'unit' => 'minute'
|
||||
];
|
||||
}
|
||||
|
||||
if (is_array($step) === true) {
|
||||
return $step;
|
||||
}
|
||||
|
||||
if (is_int($step) === true) {
|
||||
return [
|
||||
'size' => $step,
|
||||
'unit' => 'minute'
|
||||
];
|
||||
}
|
||||
|
||||
if (is_string($step) === true) {
|
||||
return [
|
||||
'size' => 1,
|
||||
'unit' => $step
|
||||
];
|
||||
}
|
||||
|
||||
throw new Exception('step option has to be defined as array');
|
||||
},
|
||||
'value' => function ($value = null) {
|
||||
return $value;
|
||||
@@ -37,32 +89,70 @@ return [
|
||||
],
|
||||
'computed' => [
|
||||
'default' => function () {
|
||||
return $this->toTime($this->default);
|
||||
return $this->toDatetime($this->default, 'H:i:s');
|
||||
},
|
||||
'format' => function () {
|
||||
return $this->notation === 24 ? 'H:i' : 'h:i a';
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->toTime($this->value);
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'toTime' => function ($value) {
|
||||
if ($timestamp = timestamp($value, $this->step)) {
|
||||
return date('H:i', $timestamp);
|
||||
'display' => function () {
|
||||
if ($this->display) {
|
||||
return $this->display;
|
||||
}
|
||||
|
||||
return null;
|
||||
return $this->notation === 24 ? 'HH:mm' : 'hh:mm a';
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->toDatetime($this->value, 'H:i:s');
|
||||
}
|
||||
],
|
||||
'save' => function ($value): string {
|
||||
if ($timestamp = strtotime($value)) {
|
||||
return date($this->format, $timestamp);
|
||||
if ($value != null && $timestamp = strtotime($value)) {
|
||||
return date('H:i:s', $timestamp);
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
'validations' => [
|
||||
'time',
|
||||
'minMax' => function ($value) {
|
||||
$min = $this->min ? strtotime($this->min) : null;
|
||||
$max = $this->max ? strtotime($this->max) : null;
|
||||
$value = strtotime($this->value());
|
||||
$format = 'H:i:s';
|
||||
$errors = [];
|
||||
|
||||
if ($value && $min && $value < $min) {
|
||||
$errors['min'] = $min;
|
||||
}
|
||||
|
||||
if ($value && $max && $value > $max) {
|
||||
$errors['max'] = $max;
|
||||
}
|
||||
|
||||
if (empty($errors) === false) {
|
||||
if ($min && $max) {
|
||||
throw new Exception([
|
||||
'key' => 'validation.time.between',
|
||||
'data' => [
|
||||
'min' => date($format, $min),
|
||||
'max' => date($format, $max)
|
||||
]
|
||||
]);
|
||||
} elseif ($min) {
|
||||
throw new Exception([
|
||||
'key' => 'validation.time.after',
|
||||
'data' => [
|
||||
'time' => date($format, $min),
|
||||
]
|
||||
]);
|
||||
} else {
|
||||
throw new Exception([
|
||||
'key' => 'validation.time.before',
|
||||
'data' => [
|
||||
'time' => date($format, $max),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
]
|
||||
];
|
||||
|
@@ -59,9 +59,7 @@ return [
|
||||
'boolean',
|
||||
'required' => function ($value) {
|
||||
if ($this->isRequired() && ($value === false || $this->isEmpty($value))) {
|
||||
throw new InvalidArgumentException([
|
||||
'key' => 'form.field.required'
|
||||
]);
|
||||
throw new InvalidArgumentException(I18n::translate('field.required'));
|
||||
}
|
||||
},
|
||||
]
|
||||
|
20
kirby/config/fields/writer.php
Executable file
20
kirby/config/fields/writer.php
Executable file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* Enables inline mode, which will not wrap new lines in paragraphs and creates hard breaks instead.
|
||||
*
|
||||
* @param bool $inline
|
||||
*/
|
||||
'inline' => function (bool $inline = false) {
|
||||
return $inline;
|
||||
},
|
||||
/**
|
||||
* Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`. Activate them all by passing `true`. Deactivate them all by passing `false`
|
||||
*/
|
||||
'marks' => function ($marks = true) {
|
||||
return $marks;
|
||||
}
|
||||
]
|
||||
];
|
@@ -66,16 +66,16 @@ function csrf(string $check = null)
|
||||
if (func_num_args() === 0) {
|
||||
// no arguments, generate/return a token
|
||||
|
||||
$token = $session->get('csrf');
|
||||
$token = $session->get('kirby.csrf');
|
||||
if (is_string($token) !== true) {
|
||||
$token = bin2hex(random_bytes(32));
|
||||
$session->set('csrf', $token);
|
||||
$session->set('kirby.csrf', $token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
} elseif (is_string($check) === true && is_string($session->get('csrf')) === true) {
|
||||
} elseif (is_string($check) === true && is_string($session->get('kirby.csrf')) === true) {
|
||||
// argument has been passed, check the token
|
||||
return hash_equals($session->get('csrf'), $check) === true;
|
||||
return hash_equals($session->get('kirby.csrf'), $check) === true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -747,10 +747,10 @@ function tc($key, int $count)
|
||||
* by the defined step
|
||||
*
|
||||
* @param string $date
|
||||
* @param int $step
|
||||
* @param int $step array of `unit` and `size` to round to nearest
|
||||
* @return string|null
|
||||
*/
|
||||
function timestamp(string $date = null, int $step = null): ?string
|
||||
function timestamp(string $date = null, $step = null): ?string
|
||||
{
|
||||
if (V::date($date) === false) {
|
||||
return null;
|
||||
@@ -762,13 +762,46 @@ function timestamp(string $date = null, int $step = null): ?string
|
||||
return $date;
|
||||
}
|
||||
|
||||
$hours = date('H', $date);
|
||||
$minutes = date('i', $date);
|
||||
$minutes = floor($minutes / $step) * $step;
|
||||
$minutes = str_pad($minutes, 2, 0, STR_PAD_LEFT);
|
||||
$date = date('Y-m-d', $date) . ' ' . $hours . ':' . $minutes;
|
||||
if (is_int($step) === true) {
|
||||
$step = [
|
||||
'unit' => 'minute',
|
||||
'size' => 1
|
||||
];
|
||||
}
|
||||
|
||||
return strtotime($date);
|
||||
if (is_array($step) === false) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
$parts = [
|
||||
'second' => date('s', $date),
|
||||
'minute' => date('i', $date),
|
||||
'hour' => date('H', $date),
|
||||
'day' => date('d', $date),
|
||||
'month' => date('m', $date),
|
||||
'year' => date('Y', $date),
|
||||
];
|
||||
|
||||
$current = $parts[$step['unit']];
|
||||
$nearest = round($current / $step['size']) * $step['size'];
|
||||
$parts[$step['unit']] = $nearest;
|
||||
|
||||
foreach ($parts as $part => $value) {
|
||||
if ($part === $step['unit']) {
|
||||
break;
|
||||
}
|
||||
|
||||
$parts[$part] = 0;
|
||||
}
|
||||
|
||||
return strtotime(
|
||||
$parts['year'] . '-' .
|
||||
str_pad($parts['month'], 2, 0, STR_PAD_LEFT) . '-' .
|
||||
str_pad($parts['day'], 2, 0, STR_PAD_LEFT) . ' ' .
|
||||
str_pad($parts['hour'], 2, 0, STR_PAD_LEFT) . ':' .
|
||||
str_pad($parts['minute'], 2, 0, STR_PAD_LEFT) . ':' .
|
||||
str_pad($parts['second'], 2, 0, STR_PAD_LEFT)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -829,6 +862,36 @@ function url(string $path = null, $options = null): string
|
||||
return Url::to($path, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a compliant v4 UUID
|
||||
* Taken from: https://github.com/symfony/polyfill
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function uuid(): string
|
||||
{
|
||||
$uuid = bin2hex(random_bytes(16));
|
||||
|
||||
return sprintf(
|
||||
'%08s-%04s-4%03s-%04x-%012s',
|
||||
// 32 bits for "time_low"
|
||||
substr($uuid, 0, 8),
|
||||
// 16 bits for "time_mid"
|
||||
substr($uuid, 8, 4),
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
substr($uuid, 13, 3),
|
||||
// 16 bits:
|
||||
// * 8 bits for "clk_seq_hi_res",
|
||||
// * 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
hexdec(substr($uuid, 16, 4)) & 0x3fff | 0x8000,
|
||||
// 48 bits for "node"
|
||||
substr($uuid, 20, 12)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a video embed via iframe for Youtube or Vimeo
|
||||
* videos. The embed Urls are automatically detected from
|
||||
|
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Kirby\Cms\App;
|
||||
use Kirby\Cms\Blocks;
|
||||
use Kirby\Cms\Field;
|
||||
use Kirby\Cms\Files;
|
||||
use Kirby\Cms\Html;
|
||||
use Kirby\Cms\Layouts;
|
||||
use Kirby\Cms\Structure;
|
||||
use Kirby\Cms\Url;
|
||||
use Kirby\Data\Data;
|
||||
@@ -53,6 +55,41 @@ return function (App $app) {
|
||||
},
|
||||
|
||||
// converters
|
||||
/**
|
||||
* Converts a yaml or json field to a Blocks object
|
||||
*
|
||||
* @param \Kirby\Cms\Field $field
|
||||
* @return \Kirby\Cms\Blocks
|
||||
*/
|
||||
'toBlocks' => function (Field $field) {
|
||||
try {
|
||||
$blocks = Blocks::factory(Blocks::parse($field->value()), [
|
||||
'parent' => $field->parent(),
|
||||
]);
|
||||
|
||||
return $blocks->filter('isHidden', false);
|
||||
} catch (Throwable $e) {
|
||||
if ($field->parent() === null) {
|
||||
$message = 'Invalid blocks data for "' . $field->key() . '" field';
|
||||
} else {
|
||||
$message = 'Invalid blocks data for "' . $field->key() . '" field on parent "' . $field->parent()->title() . '"';
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($message);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the field value into a proper boolean
|
||||
*
|
||||
* @param \Kirby\Cms\Field $field
|
||||
* @param bool $default Default value if the field is empty
|
||||
* @return bool
|
||||
*/
|
||||
'toBool' => function (Field $field, $default = false): bool {
|
||||
$value = $field->isEmpty() ? $default : $field->value;
|
||||
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses the field value with the given method
|
||||
@@ -71,18 +108,6 @@ return function (App $app) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the field value into a proper boolean
|
||||
*
|
||||
* @param \Kirby\Cms\Field $field
|
||||
* @param bool $default Default value if the field is empty
|
||||
* @return bool
|
||||
*/
|
||||
'toBool' => function (Field $field, $default = false): bool {
|
||||
$value = $field->isEmpty() ? $default : $field->value;
|
||||
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the field value to a timestamp or a formatted date
|
||||
*
|
||||
@@ -159,6 +184,19 @@ return function (App $app) {
|
||||
return (int)$value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse layouts and turn them into
|
||||
* Layout objects
|
||||
*
|
||||
* @param \Kirby\Cms\Field $field
|
||||
* @return \Kirby\Cms\Layouts
|
||||
*/
|
||||
'toLayouts' => function (Field $field) {
|
||||
return Layouts::factory(Data::decode($field->value, 'json'), [
|
||||
'parent' => $field->parent()
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Wraps a link tag around the field value. The field value is used as the link text
|
||||
*
|
||||
|
@@ -67,6 +67,9 @@ return [
|
||||
'languages' => function (array $roots) {
|
||||
return $roots['site'] . '/languages';
|
||||
},
|
||||
'logs' => function (array $roots) {
|
||||
return $roots['site'] . '/logs';
|
||||
},
|
||||
'models' => function (array $roots) {
|
||||
return $roots['site'] . '/models';
|
||||
},
|
||||
|
@@ -41,25 +41,15 @@ return [
|
||||
}
|
||||
|
||||
return $fields;
|
||||
},
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'errors' => function () {
|
||||
return $this->form->errors();
|
||||
},
|
||||
'data' => function () {
|
||||
$values = $this->form->values();
|
||||
|
||||
if (is_a($this->model, 'Kirby\Cms\Page') === true || is_a($this->model, 'Kirby\Cms\Site') === true) {
|
||||
// the title should never be updated directly via
|
||||
// fields section to avoid conflicts with the rename dialog
|
||||
unset($values['title']);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
],
|
||||
'toArray' => function () {
|
||||
return [
|
||||
'errors' => $this->errors,
|
||||
'fields' => $this->fields,
|
||||
];
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@ return [
|
||||
'template' => $this->template
|
||||
]);
|
||||
|
||||
return $file->blueprint()->accept()['mime'] ?? '*';
|
||||
return $file->blueprint()->acceptMime();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -84,12 +84,12 @@ return [
|
||||
$files = $this->parent->files()->template($this->template);
|
||||
|
||||
// filter out all protected files
|
||||
$files = $files->filterBy('isReadable', true);
|
||||
$files = $files->filter('isReadable', true);
|
||||
|
||||
if ($this->sortBy) {
|
||||
$files = $files->sortBy(...$files::sortArgs($this->sortBy));
|
||||
} elseif ($this->sortable === true) {
|
||||
$files = $files->sortBy('sort', 'asc', 'filename', 'asc');
|
||||
$files = $files->sort(...$files::sortArgs($this->sortBy));
|
||||
} else {
|
||||
$files = $files->sort('sort', 'asc', 'filename', 'asc');
|
||||
}
|
||||
|
||||
// flip
|
||||
@@ -206,13 +206,15 @@ return [
|
||||
$multiple = true;
|
||||
}
|
||||
|
||||
$template = $this->template === 'default' ? null : $this->template;
|
||||
|
||||
return [
|
||||
'accept' => $this->accept,
|
||||
'multiple' => $multiple,
|
||||
'max' => $max,
|
||||
'api' => $this->parent->apiUrl(true) . '/files',
|
||||
'attributes' => array_filter([
|
||||
'template' => $this->template
|
||||
'template' => $template
|
||||
])
|
||||
];
|
||||
}
|
||||
|
@@ -126,7 +126,7 @@ return [
|
||||
|
||||
// sort
|
||||
if ($this->sortBy) {
|
||||
$pages = $pages->sortBy(...$pages::sortArgs($this->sortBy));
|
||||
$pages = $pages->sort(...$pages::sortArgs($this->sortBy));
|
||||
}
|
||||
|
||||
// flip
|
||||
@@ -165,7 +165,9 @@ return [
|
||||
'status' => $item->status(),
|
||||
'permissions' => [
|
||||
'sort' => $permissions->can('sort'),
|
||||
'changeStatus' => $permissions->can('changeStatus')
|
||||
'changeSlug' => $permissions->can('changeSlug'),
|
||||
'changeStatus' => $permissions->can('changeStatus'),
|
||||
'changeTitle' => $permissions->can('changeTitle')
|
||||
]
|
||||
];
|
||||
}
|
||||
|
17
kirby/config/snippets.php
Executable file
17
kirby/config/snippets.php
Executable file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
$blocksRoot = __DIR__ . '/blocks';
|
||||
|
||||
return [
|
||||
// blocks
|
||||
'blocks/code' => $blocksRoot . '/code/code.php',
|
||||
'blocks/gallery' => $blocksRoot . '/gallery/gallery.php',
|
||||
'blocks/heading' => $blocksRoot . '/heading/heading.php',
|
||||
'blocks/image' => $blocksRoot . '/image/image.php',
|
||||
'blocks/list' => $blocksRoot . '/list/list.php',
|
||||
'blocks/markdown' => $blocksRoot . '/markdown/markdown.php',
|
||||
'blocks/quote' => $blocksRoot . '/quote/quote.php',
|
||||
'blocks/table' => $blocksRoot . '/table/table.php',
|
||||
'blocks/text' => $blocksRoot . '/text/text.php',
|
||||
'blocks/video' => $blocksRoot . '/video/video.php',
|
||||
];
|
8
kirby/config/templates.php
Executable file
8
kirby/config/templates.php
Executable file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
return [
|
||||
'emails/auth/login' => __DIR__ . '/templates/emails/auth/login.php',
|
||||
'emails/auth/password-reset' => __DIR__ . '/templates/emails/auth/password-reset.php'
|
||||
];
|
||||
// @codeCoverageIgnoreEnd
|
3
kirby/config/templates/emails/auth/login.php
Executable file
3
kirby/config/templates/emails/auth/login.php
Executable file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo I18n::template('login.email.login.body', null, compact('user', 'code', 'timeout'));
|
3
kirby/config/templates/emails/auth/password-reset.php
Executable file
3
kirby/config/templates/emails/auth/password-reset.php
Executable file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo I18n::template('login.email.password-reset.body', null, compact('user', 'code', 'timeout'));
|
Reference in New Issue
Block a user