[mod] alles mögliche verbessert
This commit is contained in:
parent
36814b5a7a
commit
ae2e6a2142
16 changed files with 703 additions and 537 deletions
19
notizen.md
19
notizen.md
|
@ -1,19 +1,10 @@
|
||||||
# Notizen
|
# Notizen
|
||||||
|
|
||||||
## Ziele
|
|
||||||
|
|
||||||
- soll eine kleine Web-Anwendung werden
|
|
||||||
- einzige Domäne im Modell ist die der Dokumente
|
|
||||||
- Eigenschaften von Dokumenten:
|
|
||||||
- Autor : Zeichenkette
|
|
||||||
- Titel : Zeichenkette
|
|
||||||
- Formulierung : Zeichenkette
|
|
||||||
- Begründung (optional) : Zeichenkette
|
|
||||||
- dafür soll es ein schlichtes [CRUD](https://de.wikipedia.org/wiki/CRUD) geben
|
|
||||||
- für jedes bestehende Dokument soll es Funktionen zum Aufbereiten und Herunderladen geben in den Formaten pdf und ogg
|
|
||||||
- für die Erstellung der Audio-Variante soll nach Möglichkeit [Piper](https://github.com/rhasspy/piper) verwendet werden
|
|
||||||
|
|
||||||
|
|
||||||
## Zu erledigen
|
## Zu erledigen
|
||||||
|
|
||||||
- asynchrones Erstellen der Audio-Dateien (solange nicht fertig, eine Markierung in der Liste anzeigen)
|
- asynchrones Erstellen der Audio-Dateien (solange nicht fertig, eine Markierung in der Liste anzeigen)
|
||||||
|
- Persistenz mit SQLite
|
||||||
|
- Datum für Dokumente ergänzen
|
||||||
|
- eingebetter Media-Spieler?
|
||||||
|
- für jedes bestehende Dokument soll es Funktionen zum Aufbereiten und Herunderladen geben in den Formaten pdf/odt (pandoc nutzen) und ogg
|
||||||
|
- bei Löschung eines Dokuments auch die zugehörigen Dateien löschen
|
||||||
|
|
|
@ -9,7 +9,7 @@ proof-of-concept für Partei-Arbeits-Dokumenten-Verwaltung, welche hörbare Vers
|
||||||
|
|
||||||
### Voraussetzungen
|
### Voraussetzungen
|
||||||
|
|
||||||
- curl
|
- curl (Debian-Paket-Name: `curl`)
|
||||||
|
|
||||||
|
|
||||||
### Anweisungen
|
### Anweisungen
|
||||||
|
|
|
@ -1,268 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace rosavox\helpers;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
class cache_state
|
|
||||||
{
|
|
||||||
public static array $pool = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function cache_get(string $key, \Closure $retrieve)
|
|
||||||
{
|
|
||||||
if (\array_key_exists($key, cache_state::$pool))
|
|
||||||
{
|
|
||||||
$value = cache_state::$pool[$key];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$value = ($retrieve)();
|
|
||||||
cache_state::$pool[$key] = $value;
|
|
||||||
}
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function database_map_type(string $type)
|
|
||||||
{
|
|
||||||
switch ($type)
|
|
||||||
{
|
|
||||||
case 'integer': return \SQLITE3_INTEGER;
|
|
||||||
case 'string': return \SQLITE3_TEXT;
|
|
||||||
default: throw (new \Exception(\sprintf('unhandled type: %s', $type)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function database_get(string $query_template, array $arguments) : array
|
|
||||||
{
|
|
||||||
$connection = new \SQLite3('data.sqlite');
|
|
||||||
$rows = $connection->query($query_template);
|
|
||||||
/*
|
|
||||||
$query = "SELECT * FROM books";
|
|
||||||
$result = $db->query($query);
|
|
||||||
|
|
||||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function database_put(string $query_template, array $arguments) : int
|
|
||||||
{
|
|
||||||
$connection = new \SQLite3('data.sqlite');
|
|
||||||
$statement = $connection->prepare($query);
|
|
||||||
foreach ($arguments as $key => $value)
|
|
||||||
{
|
|
||||||
$statement->bindValue(
|
|
||||||
\sprintf(':%s', $key),
|
|
||||||
$value['value'],
|
|
||||||
database_map_type($value['type'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ($statement->execute()) {
|
|
||||||
// SELECT last_insert_rowid()
|
|
||||||
echo "Buch erfolgreich hinzugefügt!";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
echo "Fehler beim Hinzufügen des Buches: " . $db->lastErrorMsg();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function string_coin(string $template, array $arguments) : string
|
|
||||||
{
|
|
||||||
$result = $template;
|
|
||||||
foreach ($arguments as $key => $value)
|
|
||||||
{
|
|
||||||
$result = \str_replace(\sprintf('{{%s}}', $key), $value, $result);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
class class_crud_jsonfile
|
|
||||||
{
|
|
||||||
private string $path;
|
|
||||||
|
|
||||||
private \Closure $id_encode;
|
|
||||||
|
|
||||||
private \Closure $id_decode;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
string $path,
|
|
||||||
\Closure $id_encode,
|
|
||||||
\Closure $id_decode
|
|
||||||
)
|
|
||||||
{
|
|
||||||
$this->path = $path;
|
|
||||||
$this->id_encode = $id_encode;
|
|
||||||
$this->id_decode = $id_decode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get() : array
|
|
||||||
{
|
|
||||||
$content = (\file_exists($this->path) ? \file_get_contents($this->path) : null);
|
|
||||||
return (
|
|
||||||
($content === null)
|
|
||||||
?
|
|
||||||
['last_id' => 0, 'entries' => []]
|
|
||||||
:
|
|
||||||
\json_decode($content, true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function put(array $data) : void
|
|
||||||
{
|
|
||||||
$content = \json_encode($data, \JSON_PRETTY_PRINT);
|
|
||||||
\file_put_contents($this->path, $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function list_() : array
|
|
||||||
{
|
|
||||||
$data = $this->get();
|
|
||||||
return \array_map(
|
|
||||||
fn ($id_encoded) => [
|
|
||||||
'id' => ($this->id_decode)($id_encoded),
|
|
||||||
'value' => $data['entries'][$id_encoded],
|
|
||||||
],
|
|
||||||
\array_keys($data['entries'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read(int $id)
|
|
||||||
{
|
|
||||||
$data = $this->get();
|
|
||||||
$id_encoded = ($this->id_encode)($id);
|
|
||||||
if (! \array_key_exists($id_encoded, $data['entries']))
|
|
||||||
{
|
|
||||||
throw (new \Exception('not found'));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $data['entries'][$id_encoded];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create($value) : int
|
|
||||||
{
|
|
||||||
$data = $this->get();
|
|
||||||
$id = ($data['last_id'] + 1);
|
|
||||||
$id_encoded = ($this->id_encode)($id);
|
|
||||||
$data['last_id'] = $id;
|
|
||||||
$data['entries'][$id_encoded] = $value;
|
|
||||||
$this->put($data);
|
|
||||||
return $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(int $id, $value) : void
|
|
||||||
{
|
|
||||||
$data = $this->get();
|
|
||||||
$id_encoded = ($this->id_encode)($id);
|
|
||||||
if (! \array_key_exists($id_encoded, $data['entries']))
|
|
||||||
{
|
|
||||||
throw (new \Exception('not found'));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$data['entries'][$id_encoded] = $value;
|
|
||||||
$this->put($data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(int $id) : void
|
|
||||||
{
|
|
||||||
$data = $this->get();
|
|
||||||
$id_encoded = ($this->id_encode)($id);
|
|
||||||
if (! \array_key_exists($id_encoded, $data['entries']))
|
|
||||||
{
|
|
||||||
throw (new \Exception('not found'));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unset($data['entries'][$id_encoded]);
|
|
||||||
$this->put($data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function render(string $template_name, array $arguments) : string
|
|
||||||
{
|
|
||||||
return string_coin(
|
|
||||||
cache_get(
|
|
||||||
string_coin(
|
|
||||||
'template.{{name}}',
|
|
||||||
[
|
|
||||||
'name' => $template_name,
|
|
||||||
]
|
|
||||||
),
|
|
||||||
fn() => \file_get_contents(
|
|
||||||
string_coin(
|
|
||||||
'{{directory}}/templates/{{name}}.html.tpl',
|
|
||||||
[
|
|
||||||
'directory' => __DIR__,
|
|
||||||
'name' => $template_name,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
$arguments
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function navigate(string $target) : void
|
|
||||||
{
|
|
||||||
\header('Location: ' . $target);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function generate_audio(string $name, string $input) : string
|
|
||||||
{
|
|
||||||
$path_wav = string_coin(
|
|
||||||
'/tmp/{{name}}.wav',
|
|
||||||
[
|
|
||||||
'name' => $name,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$path_ogg = string_coin(
|
|
||||||
'{{name}}.ogg',
|
|
||||||
[
|
|
||||||
'name' => $name,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$command = string_coin(
|
|
||||||
'echo "{{input}}" | piper/piper --model piper/voice.onnx --output_file {{path_wav}} ; ffmpeg -y -i {{path_wav}} {{path_ogg}}',
|
|
||||||
[
|
|
||||||
'input' => $input,
|
|
||||||
'path_wav' => $path_wav,
|
|
||||||
'path_ogg' => $path_ogg,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
exec($command);
|
|
||||||
return $path_ogg;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
30
source/helpers/cache.php
Normal file
30
source/helpers/cache.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace rosavox\helpers\cache;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class state
|
||||||
|
{
|
||||||
|
public static array $pool = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get(string $key, \Closure $retrieve)
|
||||||
|
{
|
||||||
|
if (\array_key_exists($key, state::$pool))
|
||||||
|
{
|
||||||
|
$value = state::$pool[$key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$value = ($retrieve)();
|
||||||
|
state::$pool[$key] = $value;
|
||||||
|
}
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
85
source/helpers/misc.php
Normal file
85
source/helpers/misc.php
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace rosavox\helpers\misc;
|
||||||
|
|
||||||
|
require_once('string.php');
|
||||||
|
require_once('cache.php');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function render(string $template_name, array $arguments) : string
|
||||||
|
{
|
||||||
|
return \rosavox\helpers\string_\coin(
|
||||||
|
\rosavox\helpers\cache\get(
|
||||||
|
\rosavox\helpers\string_\coin(
|
||||||
|
'template.{{name}}',
|
||||||
|
[
|
||||||
|
'name' => $template_name,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
fn() => \file_get_contents(
|
||||||
|
\rosavox\helpers\string_\coin(
|
||||||
|
'{{directory}}/templates/{{name}}.html.tpl',
|
||||||
|
[
|
||||||
|
'directory' => /*__DIR__*/'.',
|
||||||
|
'name' => $template_name,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
$arguments
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function navigate(string $target) : void
|
||||||
|
{
|
||||||
|
\header('Location: ' . $target);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function generate_audio(string $input, string $output_path) : void
|
||||||
|
{
|
||||||
|
$key = \hash('sha256', $input);
|
||||||
|
$path_wav = \rosavox\helpers\string_\coin(
|
||||||
|
'/tmp/{{key}}.wav',
|
||||||
|
[
|
||||||
|
'key' => $key,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$path_ogg = $output_path;
|
||||||
|
$command = \rosavox\helpers\string_\coin(
|
||||||
|
'echo "{{input}}" | piper/piper --model piper/voice.onnx --output_file {{path_wav}} && ffmpeg -y -i {{path_wav}} {{path_ogg}} ; rm -f {{path_wav}}',
|
||||||
|
[
|
||||||
|
'input' => $input,
|
||||||
|
'path_wav' => $path_wav,
|
||||||
|
'path_ogg' => $path_ogg,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
\exec($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function translate(string $key, ?array $options = null) : string
|
||||||
|
{
|
||||||
|
$strings = \rosavox\helpers\cache\get(
|
||||||
|
'strings',
|
||||||
|
fn () => \json_decode(\file_get_contents('strings.json'), true)
|
||||||
|
);
|
||||||
|
$options = \array_merge(
|
||||||
|
[
|
||||||
|
'language' => 'de',
|
||||||
|
],
|
||||||
|
($options ?? [])
|
||||||
|
);
|
||||||
|
return ($strings[$options['language']][$key] ?? \sprintf('{%s}', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
128
source/helpers/storage.php
Normal file
128
source/helpers/storage.php
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace rosavox\helpers\storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
interface interface_
|
||||||
|
{
|
||||||
|
public function list_() : array;
|
||||||
|
|
||||||
|
public function read(int $id);
|
||||||
|
|
||||||
|
public function create($value) : int;
|
||||||
|
|
||||||
|
public function update(int $id, $value) : void;
|
||||||
|
|
||||||
|
public function delete(int $id) : void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class class_jsonfile implements interface_
|
||||||
|
{
|
||||||
|
private string $path;
|
||||||
|
|
||||||
|
private \Closure $id_encode;
|
||||||
|
|
||||||
|
private \Closure $id_decode;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $path,
|
||||||
|
\Closure $id_encode,
|
||||||
|
\Closure $id_decode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->path = $path;
|
||||||
|
$this->id_encode = $id_encode;
|
||||||
|
$this->id_decode = $id_decode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function get() : array
|
||||||
|
{
|
||||||
|
$content = (\file_exists($this->path) ? \file_get_contents($this->path) : null);
|
||||||
|
return (
|
||||||
|
($content === null)
|
||||||
|
?
|
||||||
|
['last_id' => 0, 'entries' => []]
|
||||||
|
:
|
||||||
|
\json_decode($content, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function put(array $data) : void
|
||||||
|
{
|
||||||
|
$content = \json_encode($data, \JSON_PRETTY_PRINT);
|
||||||
|
\file_put_contents($this->path, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list_() : array
|
||||||
|
{
|
||||||
|
$data = $this->get();
|
||||||
|
return \array_map(
|
||||||
|
fn ($id_encoded) => [
|
||||||
|
'id' => ($this->id_decode)($id_encoded),
|
||||||
|
'value' => $data['entries'][$id_encoded],
|
||||||
|
],
|
||||||
|
\array_keys($data['entries'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(int $id)
|
||||||
|
{
|
||||||
|
$data = $this->get();
|
||||||
|
$id_encoded = ($this->id_encode)($id);
|
||||||
|
if (! \array_key_exists($id_encoded, $data['entries']))
|
||||||
|
{
|
||||||
|
throw (new \Exception('not found'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $data['entries'][$id_encoded];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($value) : int
|
||||||
|
{
|
||||||
|
$data = $this->get();
|
||||||
|
$id = ($data['last_id'] + 1);
|
||||||
|
$id_encoded = ($this->id_encode)($id);
|
||||||
|
$data['last_id'] = $id;
|
||||||
|
$data['entries'][$id_encoded] = $value;
|
||||||
|
$this->put($data);
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(int $id, $value) : void
|
||||||
|
{
|
||||||
|
$data = $this->get();
|
||||||
|
$id_encoded = ($this->id_encode)($id);
|
||||||
|
if (! \array_key_exists($id_encoded, $data['entries']))
|
||||||
|
{
|
||||||
|
throw (new \Exception('not found'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$data['entries'][$id_encoded] = $value;
|
||||||
|
$this->put($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(int $id) : void
|
||||||
|
{
|
||||||
|
$data = $this->get();
|
||||||
|
$id_encoded = ($this->id_encode)($id);
|
||||||
|
if (! \array_key_exists($id_encoded, $data['entries']))
|
||||||
|
{
|
||||||
|
throw (new \Exception('not found'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unset($data['entries'][$id_encoded]);
|
||||||
|
$this->put($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
18
source/helpers/string.php
Normal file
18
source/helpers/string.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace rosavox\helpers\string_;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function coin(string $template, array $arguments) : string
|
||||||
|
{
|
||||||
|
$result = $template;
|
||||||
|
foreach ($arguments as $key => $value)
|
||||||
|
{
|
||||||
|
$result = \str_replace(\sprintf('{{%s}}', $key), $value, $result);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -1,22 +1,29 @@
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . '/helpers.php');
|
|
||||||
require_once(__DIR__ . '/logic.php');
|
require_once('helpers/string.php');
|
||||||
|
require_once('helpers/misc.php');
|
||||||
|
require_once('services/doc.php');
|
||||||
|
|
||||||
|
|
||||||
\rosavox\logic\docs_init();
|
\rosavox\services\doc\init();
|
||||||
|
|
||||||
$mode = ($_GET['mode'] ?? 'list');
|
$mode = ($_GET['mode'] ?? 'list');
|
||||||
$id_encoded = (! empty($_GET['id']) ? $_GET['id'] : null);
|
$id_encoded = (! empty($_GET['id']) ? $_GET['id'] : null);
|
||||||
$id = (($id_encoded === null) ? null : \intval($id_encoded));
|
$id = (($id_encoded === null) ? null : \intval($id_encoded));
|
||||||
|
|
||||||
|
|
||||||
function nav(string $mode, array $args) : void
|
/**
|
||||||
|
*/
|
||||||
|
function make_link(string $mode, array $args) : string
|
||||||
{
|
{
|
||||||
$a = \array_merge($args, ['mode' => $mode]);
|
$a = \array_merge($args, ['mode' => $mode]);
|
||||||
$target = \implode(
|
return (
|
||||||
|
'?'
|
||||||
|
.
|
||||||
|
\implode(
|
||||||
'&',
|
'&',
|
||||||
\array_map(
|
\array_map(
|
||||||
fn ($key) => \rosavox\helpers\string_coin(
|
fn ($key) => \rosavox\helpers\string_\coin(
|
||||||
'{{key}}={{value}}',
|
'{{key}}={{value}}',
|
||||||
[
|
[
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
|
@ -25,109 +32,150 @@ function nav(string $mode, array $args) : void
|
||||||
),
|
),
|
||||||
\array_keys($a)
|
\array_keys($a)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
\rosavox\helpers\navigate('?' . $target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function nav(string $mode, array $args) : void
|
||||||
|
{
|
||||||
|
\rosavox\helpers\misc\navigate(make_link($mode, $args));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function render_list() : string
|
||||||
|
{
|
||||||
|
return \rosavox\helpers\misc\render(
|
||||||
|
'docs-list',
|
||||||
|
[
|
||||||
|
'label_make' => \rosavox\helpers\misc\translate('action.make'),
|
||||||
|
'link_make' => make_link('make', []),
|
||||||
|
'entries' => \implode(
|
||||||
|
"\n",
|
||||||
|
\array_map(
|
||||||
|
fn ($entry) => \rosavox\helpers\misc\render(
|
||||||
|
'docs-list-entry',
|
||||||
|
[
|
||||||
|
'label_read' => \rosavox\helpers\misc\translate('action.read'),
|
||||||
|
'label_hear' => \rosavox\helpers\misc\translate('action.hear'),
|
||||||
|
'value_link_open' => make_link('edit', ['id' => \sprintf('%u', $entry['id'])]),
|
||||||
|
'value_link_read' => \rosavox\services\doc\readable_path($entry['id']),
|
||||||
|
'value_link_hear' => \rosavox\services\doc\audio_path($entry['id']),
|
||||||
|
'value_name' => \rosavox\helpers\string_\coin(
|
||||||
|
'{{name}}.oga',
|
||||||
|
[
|
||||||
|
'name' => \rosavox\services\doc\name($entry['id']),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'value_text' => $entry['value']['title'],
|
||||||
|
]
|
||||||
|
),
|
||||||
|
\rosavox\services\doc\list_()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function render_edit(?int $id) : string
|
||||||
|
{
|
||||||
|
$doc = (
|
||||||
|
($id === null)
|
||||||
|
?
|
||||||
|
\rosavox\services\doc\empty_()
|
||||||
|
:
|
||||||
|
\rosavox\services\doc\read($id)
|
||||||
|
);
|
||||||
|
return \rosavox\helpers\misc\render(
|
||||||
|
'docs-edit',
|
||||||
|
[
|
||||||
|
'label_action_back' => \rosavox\helpers\misc\translate('action.back'),
|
||||||
|
'label_action_save' => \rosavox\helpers\misc\translate('action.save'),
|
||||||
|
'label_action_delete' => \rosavox\helpers\misc\translate('action.delete'),
|
||||||
|
'label_doc_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||||
|
'label_doc_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||||
|
'label_doc_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||||
|
'label_doc_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||||
|
'value_action_back' => make_link('list', []),
|
||||||
|
'value_action_save' => make_link('save', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||||
|
'value_action_delete' => make_link('delete', (($id === null) ? [] : ['id' => \strval($id)])),
|
||||||
|
'value_doc_title' => $doc['title'],
|
||||||
|
'value_doc_authors' => \implode(', ', $doc['authors']),
|
||||||
|
'value_doc_content' => $doc['content'],
|
||||||
|
'value_doc_reasoning' => ($doc['reasoning'] ?? ''),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/style.css"/>
|
<link rel="stylesheet" type="text/css" href="/style.css"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>rosavox</h1>
|
<h1>rosavox</h1>
|
||||||
<?php
|
<?php
|
||||||
switch ($mode)
|
switch ($mode)
|
||||||
{
|
{
|
||||||
case 'list':
|
case 'delete':
|
||||||
{
|
{
|
||||||
echo(
|
if ($id === null)
|
||||||
\rosavox\helpers\render(
|
{
|
||||||
'docs-list',
|
// do nothing
|
||||||
[
|
|
||||||
'entries' => \implode(
|
|
||||||
"\n",
|
|
||||||
\array_map(
|
|
||||||
fn ($entry) => \rosavox\helpers\render(
|
|
||||||
'docs-list-entry',
|
|
||||||
[
|
|
||||||
'link_open' => \rosavox\helpers\string_coin(
|
|
||||||
'?mode=edit&id={{id}}',
|
|
||||||
[
|
|
||||||
'id' => $entry['id'],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
'link_read' => '#not_implemented',
|
|
||||||
'link_hear' => \rosavox\logic\docs_audio_path($entry['id']),
|
|
||||||
'text' => $entry['value']['title'],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
\rosavox\logic\docs_list()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
'link_new' => '?mode=make',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'make':
|
else
|
||||||
{
|
{
|
||||||
echo(
|
\rosavox\services\doc\delete($id);
|
||||||
\rosavox\helpers\render(
|
|
||||||
'docs-edit',
|
|
||||||
[
|
|
||||||
'id' => '',
|
|
||||||
'title' => '',
|
|
||||||
'authors' => '',
|
|
||||||
'content' => '',
|
|
||||||
'reasoning' => '',
|
|
||||||
'link_back' => '?mode=list',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'edit':
|
nav('list', []);
|
||||||
{
|
|
||||||
$doc = \rosavox\logic\docs_read($id);
|
|
||||||
echo(
|
|
||||||
\rosavox\helpers\render(
|
|
||||||
'docs-edit',
|
|
||||||
[
|
|
||||||
'id' => $id_encoded,
|
|
||||||
'title' => $doc['title'],
|
|
||||||
'authors' => \implode(', ', $doc['authors']),
|
|
||||||
'content' => $doc['content'],
|
|
||||||
'reasoning' => $doc['reasoning'],
|
|
||||||
'link_back' => '?mode=list',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'save':
|
case 'save':
|
||||||
{
|
{
|
||||||
$doc = [
|
$doc = [
|
||||||
'title' => $_GET['title'],
|
'title' => $_POST['title'],
|
||||||
'authors' => \explode(',', $_GET['authors']),
|
'authors' => \explode(',', $_POST['authors']),
|
||||||
'content' => $_GET['content'],
|
'content' => $_POST['content'],
|
||||||
'reasoning' => (empty($_GET['reasoning']) ? null : $_GET['reasoning']),
|
'reasoning' => (empty($_POST['reasoning']) ? null : $_GET['reasoning']),
|
||||||
];
|
];
|
||||||
if ($id === null)
|
if ($id === null)
|
||||||
{
|
{
|
||||||
$id = \rosavox\logic\docs_create($doc);
|
$id = \rosavox\services\doc\create($doc);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
\rosavox\logic\docs_update($id, $doc);
|
\rosavox\services\doc\update($id, $doc);
|
||||||
}
|
}
|
||||||
// nav('edit', ['id' => \rosavox\logic\docs_id_encode($id)]);
|
// nav('edit', ['id' => \rosavox\services\doc\id_encode($id)]);
|
||||||
nav('list', []);
|
nav('list', []);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'list':
|
||||||
|
{
|
||||||
|
echo(render_list());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'make':
|
||||||
|
{
|
||||||
|
echo(render_edit(null));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'edit':
|
||||||
|
{
|
||||||
|
echo(render_edit($id));
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw (new \Exception(\sprintf('invalid mode: %s', $mode)));
|
throw (new \Exception(\sprintf('invalid mode: %s', $mode)));
|
||||||
|
|
146
source/logic.php
146
source/logic.php
|
@ -1,146 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace rosavox\logic;
|
|
||||||
|
|
||||||
require_once(__DIR__ . '/helpers.php');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
class docs_state
|
|
||||||
{
|
|
||||||
public static ?\rosavox\helpers\class_crud_jsonfile $crud = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_audio_name(int $id) : string
|
|
||||||
{
|
|
||||||
return \sprintf('%04u', $id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_audio_path(int $id) : string
|
|
||||||
{
|
|
||||||
return \sprintf('%s.ogg', docs_audio_name($id));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_generate_audio(int $id, $doc) : void
|
|
||||||
{
|
|
||||||
$pause = ' . ';
|
|
||||||
\rosavox\helpers\generate_audio(
|
|
||||||
docs_audio_name($id),
|
|
||||||
\rosavox\helpers\string_coin(
|
|
||||||
"{{title}}{{pause}}Autoren: {{authors}}{{pause}}Formulierung: {{content}}{{macro_reasoning}}",
|
|
||||||
[
|
|
||||||
'pause' => $pause,
|
|
||||||
'title' => $doc['title'],
|
|
||||||
'authors' => implode(', ', $doc['authors']),
|
|
||||||
'content' => $doc['content'],
|
|
||||||
'macro_reasoning' => (
|
|
||||||
($doc['reasoning'] === null)
|
|
||||||
?
|
|
||||||
''
|
|
||||||
:
|
|
||||||
\rosavox\helpers\string_coin(
|
|
||||||
"{{pause}}Begründung: {{reasoning}}",
|
|
||||||
[
|
|
||||||
'pause' => $pause,
|
|
||||||
'reasoning' => $doc['reasoning'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_list() : array
|
|
||||||
{
|
|
||||||
return docs_state::$crud->list_();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_read(int $id) : array
|
|
||||||
{
|
|
||||||
return docs_state::$crud->read($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo async generating
|
|
||||||
*/
|
|
||||||
function docs_create(array $doc) : int
|
|
||||||
{
|
|
||||||
$id = docs_state::$crud->create($doc);
|
|
||||||
docs_generate_audio($id, $doc);
|
|
||||||
return $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_update(int $id, array $doc) : void
|
|
||||||
{
|
|
||||||
docs_state::$crud->update($id, $doc);
|
|
||||||
docs_generate_audio($id, $doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_delete(int $id) : void
|
|
||||||
{
|
|
||||||
docs_state::$crud->delete($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_add_examples() : void
|
|
||||||
{
|
|
||||||
docs_create(
|
|
||||||
[
|
|
||||||
'title' => 'Freibier bei Parteitagen',
|
|
||||||
'authors' => [
|
|
||||||
'Björn Biernot',
|
|
||||||
'Doreen Dauerdurst',
|
|
||||||
],
|
|
||||||
'content' => 'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.',
|
|
||||||
'reasoning' => 'Wir haben Durst!',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
function docs_init() : void
|
|
||||||
{
|
|
||||||
docs_state::$crud = new \rosavox\helpers\class_crud_jsonfile(
|
|
||||||
'docs.json',
|
|
||||||
fn ($id) => \sprintf('%u', $id),
|
|
||||||
fn ($id_encoded) => \intval($id_encoded)
|
|
||||||
);
|
|
||||||
if (empty(docs_state::$crud->list_()))
|
|
||||||
{
|
|
||||||
docs_add_examples();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
246
source/services/doc.php
Normal file
246
source/services/doc.php
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace rosavox\services\doc;
|
||||||
|
|
||||||
|
require_once('helpers/string.php');
|
||||||
|
require_once('helpers/storage.php');
|
||||||
|
require_once('helpers/misc.php');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class state
|
||||||
|
{
|
||||||
|
public static ?\rosavox\helpers\storage\interface_ $storage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function name(int $id) : string
|
||||||
|
{
|
||||||
|
return \sprintf('doc-%04u', $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function audio_path(int $id) : string
|
||||||
|
{
|
||||||
|
return \sprintf('docs/%s.oga', name($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function readable_path(int $id) : string
|
||||||
|
{
|
||||||
|
return \sprintf('docs/%s.md', name($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function generate_readable(int $id, $doc) : void
|
||||||
|
{
|
||||||
|
$markdown = \rosavox\helpers\string_\coin(
|
||||||
|
"# {{value_title}}
|
||||||
|
|
||||||
|
## {{label_authors}}
|
||||||
|
|
||||||
|
{{value_authors}}
|
||||||
|
|
||||||
|
|
||||||
|
## {{label_content}}
|
||||||
|
|
||||||
|
{{value_content}}
|
||||||
|
|
||||||
|
{{macro_reasoning}}",
|
||||||
|
[
|
||||||
|
'label_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||||
|
'value_title' => $doc['title'],
|
||||||
|
'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||||
|
'value_authors' => \implode(
|
||||||
|
"\n",
|
||||||
|
\array_map(
|
||||||
|
fn ($author) => \rosavox\helpers\string_\coin(
|
||||||
|
'- {{author}}',
|
||||||
|
[
|
||||||
|
'author' => $author,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
$doc['authors']
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||||
|
'value_content' => $doc['content'],
|
||||||
|
'macro_reasoning' => (
|
||||||
|
($doc['reasoning'] === null)
|
||||||
|
?
|
||||||
|
''
|
||||||
|
:
|
||||||
|
\rosavox\helpers\string_\coin(
|
||||||
|
"
|
||||||
|
## {{label_reasoning}}
|
||||||
|
|
||||||
|
{{value_reasoning}}",
|
||||||
|
[
|
||||||
|
'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||||
|
'value_reasoning' => $doc['reasoning'],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
\file_put_contents(
|
||||||
|
readable_path($id),
|
||||||
|
$markdown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function generate_audio(int $id, $doc) : void
|
||||||
|
{
|
||||||
|
$pause = " .\n";
|
||||||
|
$text = \rosavox\helpers\string_\coin(
|
||||||
|
"{{value_title}}{{pause}}{{label_authors}}: {{value_authors}}{{pause}}{{label_content}}: {{value_content}}{{macro_reasoning}}",
|
||||||
|
[
|
||||||
|
'pause' => $pause,
|
||||||
|
'label_title' => \rosavox\helpers\misc\translate('domain.doc.title'),
|
||||||
|
'value_title' => $doc['title'],
|
||||||
|
'label_authors' => \rosavox\helpers\misc\translate('domain.doc.authors'),
|
||||||
|
'value_authors' => \implode($pause, $doc['authors']),
|
||||||
|
'label_content' => \rosavox\helpers\misc\translate('domain.doc.content'),
|
||||||
|
'value_content' => $doc['content'],
|
||||||
|
'macro_reasoning' => (
|
||||||
|
($doc['reasoning'] === null)
|
||||||
|
?
|
||||||
|
''
|
||||||
|
:
|
||||||
|
\rosavox\helpers\string_\coin(
|
||||||
|
"{{pause}}{{label_reasoning}}: {{value_reasoning}}",
|
||||||
|
[
|
||||||
|
'pause' => $pause,
|
||||||
|
'label_reasoning' => \rosavox\helpers\misc\translate('domain.doc.reasoning'),
|
||||||
|
'value_reasoning' => $doc['reasoning'],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
\rosavox\helpers\misc\generate_audio(
|
||||||
|
$text,
|
||||||
|
audio_path($id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function empty_() : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => '',
|
||||||
|
'authors' => [],
|
||||||
|
'content' => '',
|
||||||
|
'reasoning' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function list_() : array
|
||||||
|
{
|
||||||
|
return state::$storage->list_();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function read(int $id) : array
|
||||||
|
{
|
||||||
|
return state::$storage->read($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo async generating
|
||||||
|
*/
|
||||||
|
function create(array $doc) : int
|
||||||
|
{
|
||||||
|
$id = state::$storage->create($doc);
|
||||||
|
generate_readable($id, $doc);
|
||||||
|
generate_audio($id, $doc);
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function update(int $id, array $doc) : void
|
||||||
|
{
|
||||||
|
state::$storage->update($id, $doc);
|
||||||
|
generate_readable($id, $doc);
|
||||||
|
generate_audio($id, $doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function delete(int $id) : void
|
||||||
|
{
|
||||||
|
state::$storage->delete($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function add_examples() : void
|
||||||
|
{
|
||||||
|
create(
|
||||||
|
[
|
||||||
|
'title' => 'Freibier bei Parteitagen',
|
||||||
|
'authors' => [
|
||||||
|
'Björn Biernot',
|
||||||
|
'Doreen Dauerdurst',
|
||||||
|
],
|
||||||
|
'content' => 'Der Landesverband möge beschließen, dass zu Beginn eines jeden Parteitags für jeden Deligierten mindestens zwei Flaschen Bier auf den zugehörigen Platz zu stellen sind.',
|
||||||
|
'reasoning' => 'Wir haben Durst!',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
create(
|
||||||
|
[
|
||||||
|
'title' => 'Götterdämmerung',
|
||||||
|
'authors' => [
|
||||||
|
'Fenriswolf',
|
||||||
|
],
|
||||||
|
'content' => 'Der Allvater hat mich betrogen. Ich werde ihn und seine elende Asenbrut verschlingen.',
|
||||||
|
'reasoning' => null,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function init() : void
|
||||||
|
{
|
||||||
|
state::$storage = new \rosavox\helpers\storage\class_jsonfile(
|
||||||
|
'docs.json',
|
||||||
|
fn ($id) => \sprintf('%u', $id),
|
||||||
|
fn ($id_encoded) => \intval($id_encoded)
|
||||||
|
);
|
||||||
|
if (empty(state::$storage->list_()))
|
||||||
|
{
|
||||||
|
add_examples();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
14
source/strings.json
Normal file
14
source/strings.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"de": {
|
||||||
|
"action.make": "neu",
|
||||||
|
"action.save": "speichern",
|
||||||
|
"action.back": "zurück",
|
||||||
|
"action.delete": "löschen",
|
||||||
|
"action.hear": "hören",
|
||||||
|
"action.read": "lesen",
|
||||||
|
"domain.doc.title": "Titel",
|
||||||
|
"domain.doc.authors": "Autoren",
|
||||||
|
"domain.doc.content": "Formulierung",
|
||||||
|
"domain.doc.reasoning": "Begründung"
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ html
|
||||||
color: hsl(var(--hue), 0%, 100%);
|
color: hsl(var(--hue), 0%, 100%);
|
||||||
|
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
body
|
body
|
||||||
|
@ -48,7 +49,7 @@ label > span
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"]
|
input
|
||||||
{
|
{
|
||||||
min-width: 480px;
|
min-width: 480px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
@ -56,6 +57,8 @@ input[type="text"]
|
||||||
background-color: hsl(var(--hue), 0%, 25%);
|
background-color: hsl(var(--hue), 0%, 25%);
|
||||||
color: hsl(var(--hue), 0%, 100%);
|
color: hsl(var(--hue), 0%, 100%);
|
||||||
|
|
||||||
|
font-size: 1.0em;
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,5 +71,18 @@ textarea
|
||||||
background-color: hsl(var(--hue), 0%, 25%);
|
background-color: hsl(var(--hue), 0%, 25%);
|
||||||
color: hsl(var(--hue), 0%, 100%);
|
color: hsl(var(--hue), 0%, 100%);
|
||||||
|
|
||||||
|
font-size: 1.0em;
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button
|
||||||
|
{
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 1.0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-list-entry > *
|
||||||
|
{
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
<div id="docs-edit">
|
<div id="docs-edit">
|
||||||
<form method="GET">
|
<form method="POST">
|
||||||
<input type="hidden" name="mode" value="save"/>
|
|
||||||
<input type="hidden" name="id" value="{{id}}"/>
|
|
||||||
<label>
|
<label>
|
||||||
<span>Titel</span>
|
<span>{{label_doc_title}}</span>
|
||||||
<input type="text" name="title" value="{{title}}"/>
|
<input type="text" name="title" value="{{value_doc_title}}"/>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span>Autoren</span>
|
<span>{{label_doc_authors}}</span>
|
||||||
<input type="text" name="authors" value="{{authors}}"/>
|
<input type="text" name="authors" value="{{value_doc_authors}}"/>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span>Formulierung</span>
|
<span>{{label_doc_content}}</span>
|
||||||
<textarea name="content">{{content}}</textarea>
|
<textarea name="content">{{value_doc_content}}</textarea>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span>Begründung</span>
|
<span>{{label_doc_reasoning}}</span>
|
||||||
<textarea name="reasoning">{{reasoning}}</textarea>
|
<textarea name="reasoning">{{value_doc_reasoning}}</textarea>
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="submit" value="Speichern"/>
|
|
||||||
</label>
|
</label>
|
||||||
|
<button formaction="{{value_action_back}}">{{label_action_back}}</button>
|
||||||
|
<button formaction="{{value_action_save}}">{{label_action_save}}</button>
|
||||||
|
<button formaction="{{value_action_delete}}">{{label_action_delete}}</button>
|
||||||
</form>
|
</form>
|
||||||
<a href="{{link_back}}">zurück</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<li class="docs-list-entry">
|
<li class="docs-list-entry">
|
||||||
<a href="{{link_open}}">{{text}}</a>
|
<a href="{{value_link_open}}">{{value_text}}</a>
|
||||||
| <a href="{{link_read}}">[lesen]</a>
|
|
|
||||||
| <a href="{{link_hear}}">[hören]</a>
|
<a href="{{value_link_read}}">[{{label_read}}]</a>
|
||||||
|
|
|
||||||
|
<a href="{{value_link_hear}}" download="{{value_name}}" type="audio/ogg">[{{label_hear}}]</a>
|
||||||
|
|
|
||||||
|
<audio controls="controls" src="{{value_link_hear}}"></audio>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<div id="docs-list">
|
<div id="docs-list">
|
||||||
<ul>
|
<ul>
|
||||||
{{entries}}
|
{{entries}}
|
||||||
</ul>
|
</ul>
|
||||||
<a href="{{link_new}}">Neu</a>
|
<form method="POST">
|
||||||
|
<button formaction="{{link_make}}">{{label_make}}</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,3 +12,4 @@ mkdir -p ${dir_build}
|
||||||
cp -r -u lib/* ${dir_build}/
|
cp -r -u lib/* ${dir_build}/
|
||||||
cp -r -u -v ${dir_source}/* ${dir_build}/
|
cp -r -u -v ${dir_source}/* ${dir_build}/
|
||||||
cd ${dir_build} && ln -f -s index.html.php index.php ; cd -
|
cd ${dir_build} && ln -f -s index.html.php index.php ; cd -
|
||||||
|
mkdir -p ${dir_build}/docs
|
||||||
|
|
Loading…
Add table
Reference in a new issue