Overview
Comment:Change of strategy: will do rich text editing later, first let's just migrate the wiki to web
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA1: 246bb415009482e2c37ce6bc81b28c5b2cca2d6c
User & Date: bohwaz on 2020-12-14 23:42:34
Other Links: branch diff | manifest | tags
Context
2020-12-15
00:42
Editor is working, now onto preview check-in: 273b468d7d user: bohwaz tags: dev
2020-12-14
23:42
Change of strategy: will do rich text editing later, first let's just migrate the wiki to web check-in: 246bb41500 user: bohwaz tags: dev
02:21
More work on the rich text editor, but Trix sucks a lot :( check-in: e1d70bedb9 user: bohwaz tags: dev
Changes

Modified src/VERSION from [4c3ec47899] to [528cf42af9].

1
1.0.0-rc12
|
1
1.1.0

Modified src/include/lib/Garradin/Entities/Files/File.php from [0da72de85a] to [ca4754f46f].

1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
<?php

namespace Garradin\Entities\Files;

use KD2\Image;

use Garradin\DB;
use Garradin\Entity;
use Garradin\UserException;
use Garradin\Membres\Session;
use Garradin\Membres;
use Garradin\Utils;


use Garradin\Files\Files;

use const Garradin\{WWW_URL, ENABLE_XSENDFILE};

class File extends Entity
{












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace Garradin\Entities\Files;

use KD2\Image;

use Garradin\DB;
use Garradin\Entity;
use Garradin\UserException;
use Garradin\Membres\Session;
use Garradin\Membres;
use Garradin\Utils;
use Garradin\Entities\Web\Page;

use Garradin\Files\Files;

use const Garradin\{WWW_URL, ENABLE_XSENDFILE};

class File extends Entity
{
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
	{
		$return = parent::save();

		// Store content in search table
		if ($return && substr($this->type, 0, 5) == 'text/') {
			$content = Files::callStorage('fetch', $this);

			if ($this->type == 'text/html') {
				$content = strip_tags($content);
			}

			if ($this->type == 'text/vnd.skriv.encrypted') {
				$content = 'Contenu chiffré';
			}

			$db->preparedQuery('INSERT OR REPLACE INTO files_search (id, content) VALUES (?, ?);', $this->id(), $content);
		}

		return $return;
	}

	public function store(string $source_path = null, $source_content = null): self
	{







|



|



|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
	{
		$return = parent::save();

		// Store content in search table
		if ($return && substr($this->type, 0, 5) == 'text/') {
			$content = Files::callStorage('fetch', $this);

			if ($this->type == Page::FILE_TYPE_HTML) {
				$content = strip_tags($content);
			}

			if ($this->type == Page::FILE_TYPE_ENCRYPTED) {
				$content = 'Contenu chiffré';
			}

			DB::getInstance()->preparedQuery('INSERT OR REPLACE INTO files_search (id, content) VALUES (?, ?);', $this->id(), $content);
		}

		return $return;
	}

	public function store(string $source_path = null, $source_content = null): self
	{
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
					throw new \RuntimeException('Le serveur n\'a aucune bibliothèque de gestion d\'image installée, et ne peut donc pas accepter les images. Installez Imagick ou GD.');
				}

				throw new UserException('Fichier image invalide');
			}
		}

		if (!Files::callStorage('store', $file, $source_path, $source_content)) {
			throw new UserException('Le fichier n\'a pas pu être enregistré.');
		}

		return $this;
	}

	static protected function create(string $name, string $source_path = null, $source_content = null): self







|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
					throw new \RuntimeException('Le serveur n\'a aucune bibliothèque de gestion d\'image installée, et ne peut donc pas accepter les images. Installez Imagick ou GD.');
				}

				throw new UserException('Fichier image invalide');
			}
		}

		if (!Files::callStorage('store', $this, $source_path, $source_content)) {
			throw new UserException('Le fichier n\'a pas pu être enregistré.');
		}

		return $this;
	}

	static protected function create(string $name, string $source_path = null, $source_content = null): self
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
	}

	public function fetch()
	{
		return Files::callStorage('fetch', $this);
	}

	public function render(): string
	{
		static $render_types = ['text/html', 'text/vnd.skriv', 'text/vnd.skriv.encrypted'];

		if (!in_array($this->type, $render_types)) {
			throw new \LogicException('Render can not be called on files of type: ' . $this->type);
		}

		$content = $this->fetch();

		if ($this->type == 'text/html') {
			return \Garradin\Files\Render\HTML::render($this, $content);
		}
		elseif ($this->type == 'text/vnd.skriv') {
			return \Garradin\Files\Render\Skriv::render($this, $content);
		}
		elseif ($this->type == 'text/vnd.skriv.encrypted') {
			return \Garradin\Files\Render\EncryptedSkriv::render($this, $content);
		}

		throw new \LogicException('Unknown render type');
	}

	public function checkReadAccess(Session $session): bool
	{
		// Web and config files should be marked as public when not in draft
		if ($this->public) {
			return true;
		}








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







471
472
473
474
475
476
477























478
479
480
481
482
483
484
	}

	public function fetch()
	{
		return Files::callStorage('fetch', $this);
	}
























	public function checkReadAccess(Session $session): bool
	{
		// Web and config files should be marked as public when not in draft
		if ($this->public) {
			return true;
		}

Modified src/include/lib/Garradin/Entities/Web/Page.php from [a9d6f2dd6b] to [a395c53d59].

36
37
38
39
40
41
42




43
44
45
46
47
48
49

	const STATUS_ONLINE = 1;
	const STATUS_DRAFT = 0;

	const TYPE_CATEGORY = 1;
	const TYPE_PAGE = 2;





	public function url(): string
	{
		$url = WWW_URL . $this->uri;

		if ($this->type == self::TYPE_CATEGORY) {
			$url .= '/';
		}







>
>
>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

	const STATUS_ONLINE = 1;
	const STATUS_DRAFT = 0;

	const TYPE_CATEGORY = 1;
	const TYPE_PAGE = 2;

	const FILE_TYPE_HTML = 'text/html';
	const FILE_TYPE_ENCRYPTED = 'text/vnd.skriv.encrypted';
	const FILE_TYPE_SKRIV = 'text/vnd.skriv';

	public function url(): string
	{
		$url = WWW_URL . $this->uri;

		if ($this->type == self::TYPE_CATEGORY) {
			$url .= '/';
		}
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98




99
100
101
102
103











104
105
106
107
108
109
110

	public function selfCheck(): void
	{
		$this->assert($this->type === self::TYPE_CATEGORY || $this->type === self::TYPE_PAGE, 'Unknown page type');
		$this->assert($this->status === self::STATUS_DRAFT || $this->status === self::STATUS_ONLINE, 'Unknown page status');
		$this->assert(trim($this->title) !== '', 'Le titre ne peut rester vide');
		$this->assert(trim($this->uri) !== '', 'L\'URI ne peut rester vide');
		$this->assert(!$this->_file, 'Fichier manquant');
	}

	public function importForm(array $source = null)
	{
		if (null === $source) {
			$source = $_POST;
		}





		$file = $this->file();

		if (isset($source['content']) && sha1($source['content']) != $file->hash) {
			$file->store(null, $content);











		}

		return $this->import($source);
	}

	static public function create(int $type, string $title, string $content, int $status = self::STATUS_ONLINE): Page
	{







|







>
>
>
>




|
>
>
>
>
>
>
>
>
>
>
>







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

	public function selfCheck(): void
	{
		$this->assert($this->type === self::TYPE_CATEGORY || $this->type === self::TYPE_PAGE, 'Unknown page type');
		$this->assert($this->status === self::STATUS_DRAFT || $this->status === self::STATUS_ONLINE, 'Unknown page status');
		$this->assert(trim($this->title) !== '', 'Le titre ne peut rester vide');
		$this->assert(trim($this->uri) !== '', 'L\'URI ne peut rester vide');
		$this->assert((bool) $this->_file, 'Fichier manquant');
	}

	public function importForm(array $source = null)
	{
		if (null === $source) {
			$source = $_POST;
		}

		if (isset($source['parent_id']) && is_array($source['parent_id'])) {
			$source['parent_id'] = key($source['parent_id']);
		}

		$file = $this->file();

		if (isset($source['content']) && sha1($source['content']) != $file->hash) {
			$file->store(null, $source['content']);
		}

		if (isset($source['date']) && isset($source['date_time'])) {
			$file->importForm(['created' => sprintf('%s %s', $source['date'], $source['date_time'])]);
		}

		if (!empty($source['encrypted']) ) {
			$file->set('type', self::FILE_TYPE_ENCRYPTED);
		}
		else {
			$file->set('type', self::FILE_TYPE_SKRIV);
		}

		return $this->import($source);
	}

	static public function create(int $type, string $title, string $content, int $status = self::STATUS_ONLINE): Page
	{
132
133
134
135
136
137
138
139























		}

		$file->store(null, $content);
		$page->save();

		return $page;
	}
}






























|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
		}

		$file->store(null, $content);
		$page->save();

		return $page;
	}

	public function render(): string
	{
		static $render_types = [self::FILE_TYPE_SKRIV, self::FILE_TYPE_ENCRYPTED, self::FILE_TYPE_HTML];

		if (!in_array($this->type, $render_types)) {
			throw new \LogicException('Render can not be called on files of type: ' . $this->type);
		}

		$content = $this->fetch();

		if ($this->type == self::FILE_TYPE_HTML) {
			return \Garradin\Files\Render\HTML::render($this, $content);
		}
		elseif ($this->type == self::FILE_TYPE_SKRIV) {
			return \Garradin\Files\Render\Skriv::render($this, $content);
		}
		elseif ($this->type == self::FILE_TYPE_ENCRYPTED) {
			return \Garradin\Files\Render\EncryptedSkriv::render($this, $content);
		}

		throw new \LogicException('Unknown render type');
	}
}

Modified src/include/lib/Garradin/Entity.php from [de03b9076a] to [7ef148b9bf].

44
45
46
47
48
49
50
51

52
53



54
55
56
57
58
59
60
			elseif (preg_match('!^\d{2}/\d{2}/\d{4}$!', $value)) {
				return \DateTime::createFromFormat('d/m/Y', $value);
			}
			elseif (null !== $value) {
				throw new ValidationException('Format de date invalide (merci d\'utiliser le format JJ/MM/AAAA) : ' . $value);
			}
		}
		else {

			return parent::filterUserValue($type, $value, $key);
		}



	}

	protected function assert(bool $test, string $message = null): void
	{
		if ($test) {
			return;
		}







|
>
|
|
>
>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
			elseif (preg_match('!^\d{2}/\d{2}/\d{4}$!', $value)) {
				return \DateTime::createFromFormat('d/m/Y', $value);
			}
			elseif (null !== $value) {
				throw new ValidationException('Format de date invalide (merci d\'utiliser le format JJ/MM/AAAA) : ' . $value);
			}
		}
		elseif ($type == 'DateTime') {
			if (preg_match('!^\d{2}/\d{2}/\d{4}\s\d{2}:\d{2}$!', $value)) {
				return \DateTime::createFromFormat('d/m/Y H:i', $value);
			}
		}

		return parent::filterUserValue($type, $value, $key);
	}

	protected function assert(bool $test, string $message = null): void
	{
		if ($test) {
			return;
		}

Modified src/include/lib/Garradin/Files/Files.php from [f113720eda] to [216db749fc].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace Garradin\Files;

use Garradin\Static_Cache;
use Garradin\DB;
use Garradin\Membres\Session;
use Garradin\Entities\Files\File;
use KD2\DB\EntityManager as EM;

use const Garradin\FILE_STORAGE_BACKEND;

class Files
{
	static public function callStorage(string $function, ...$args)
	{
		// Check that we can store this data
		if ($function == 'store') {
			$quota = FILE_STORAGE_QUOTA ?: self::callStorage('getQuota');
			$used = self::callStorage('getTotalSize');

			$size = $args[0] ? filesize($args[0]) : strlen($args[1]);

			if (($used + $size) >= $quota) {
				throw new \OutOfBoundsException('File quota has been exhausted');
			}
		}

		$storage = FILE_STORAGE_BACKEND ?? 'SQLite';










|










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace Garradin\Files;

use Garradin\Static_Cache;
use Garradin\DB;
use Garradin\Membres\Session;
use Garradin\Entities\Files\File;
use KD2\DB\EntityManager as EM;

use const Garradin\{FILE_STORAGE_BACKEND, FILE_STORAGE_QUOTA};

class Files
{
	static public function callStorage(string $function, ...$args)
	{
		// Check that we can store this data
		if ($function == 'store') {
			$quota = FILE_STORAGE_QUOTA ?: self::callStorage('getQuota');
			$used = self::callStorage('getTotalSize');

			$size = $args[0] ? filesize($args[1]) : strlen($args[2]);

			if (($used + $size) >= $quota) {
				throw new \OutOfBoundsException('File quota has been exhausted');
			}
		}

		$storage = FILE_STORAGE_BACKEND ?? 'SQLite';

Modified src/include/lib/Garradin/Files/Storage/SQLite.php from [bb87054c4e] to [bd5dafc63d].

1
2
3
4
5
6
7
8


9
10
11
12
13
14
15
<?php

namespace Garradin\Files\Storage;

use Garradin\Entities\Files\File;

use Garradin\Static_Cache;
use Garradin\DB;



class SQLite implements StorageInterface
{
	/**
	 * Renvoie le chemin vers le fichier local en cache, et le crée s'il n'existe pas
	 * @return string Chemin local
	 */








>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

namespace Garradin\Files\Storage;

use Garradin\Entities\Files\File;

use Garradin\Static_Cache;
use Garradin\DB;

use const Garradin\DB_FILE;

class SQLite implements StorageInterface
{
	/**
	 * Renvoie le chemin vers le fichier local en cache, et le crée s'il n'existe pas
	 * @return string Chemin local
	 */
26
27
28
29
30
31
32
33











34
35
36
37
38
39
40

		return Static_Cache::getPath($cache_id);
	}

	static public function store(File $file, ?string $path, ?string $content): bool
	{
		$db = DB::getInstance();
		$db->exec(sprintf('UPDATE files_contents SET blob = zeroblob(%d) WHERE id = %d;', $file->size, $file->content_id));












		$blob = $db->openBlob('files_contents', 'content', $file->content_id, 'main', SQLITE3_OPEN_READWRITE);

		if (null !== $content) {
			fwrite($blob, $content);
		}
		else {







|
>
>
>
>
>
>
>
>
>
>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

		return Static_Cache::getPath($cache_id);
	}

	static public function store(File $file, ?string $path, ?string $content): bool
	{
		$db = DB::getInstance();

		if (!$file->content_id) {
			$db->preparedQuery('INSERT INTO files_contents (hash, content) VALUES (?, ?, zeroblob(?));', $file->hash, $file->size);
			$file->content_id = $db->lastInsertId();
		}
		else {
			$cache_id = 'files.' . $file->content_id;

			Static_Cache::remove($cache_id);

			$db->preparedQuery('UPDATE files_contents SET hash = ?, content = zeroblob(?) WHERE id = ?;', $file->hash, $file->size, $file->content_id);
		}

		$blob = $db->openBlob('files_contents', 'content', $file->content_id, 'main', SQLITE3_OPEN_READWRITE);

		if (null !== $content) {
			fwrite($blob, $content);
		}
		else {
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
	static public function move(File $old_file, File $new_file): bool
	{
		return true;
	}

	static public function getTotalSize(): int
	{
		return (int) DB::getInstance()->firstColumn('SELECT SUM(size) FROM files_contents;');
	}

	static public function getQuota(): int
	{
		return disk_total_space(dirname(DB_FILE));
	}
}







|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	static public function move(File $old_file, File $new_file): bool
	{
		return true;
	}

	static public function getTotalSize(): int
	{
		return (int) DB::getInstance()->firstColumn('SELECT SUM(LENGTH(content)) FROM files_contents;');
	}

	static public function getQuota(): int
	{
		return disk_total_space(dirname(DB_FILE));
	}
}

Modified src/include/lib/Garradin/Template.php from [b8eafe3cb8] to [3a8e6cf21e].

218
219
220
221
222
223
224











225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244



245
246
247
248
249
250
251
		$attributes = array_diff_key($params, array_flip($params_list));
		$params = array_intersect_key($params, array_flip($params_list));
		extract($params, \EXTR_SKIP);

		if (!isset($name, $type)) {
			throw new \InvalidArgumentException('Missing name or type');
		}












		$current_value = null;
		$current_value_from_user = false;

		if (isset($_POST[$name])) {
			$current_value = $_POST[$name];
			$current_value_from_user = true;
		}
		elseif (isset($source) && is_object($source) && isset($source->$name)) {
			$current_value = $source->$name;
		}
		elseif (isset($source) && is_array($source) && isset($source[$name])) {
			$current_value = $source[$name];
		}
		elseif (isset($default)) {
			$current_value = $default;
		}

		if ($type == 'date' && is_object($current_value) && $current_value instanceof \DateTimeInterface) {
			$current_value = $current_value->format('d/m/Y');



		}
		elseif ($type == 'date' && is_string($current_value)) {
			if ($v = \DateTime::createFromFormat('!Y-m-d', $current_value)) {
				$current_value = $v->format('d/m/Y');
			}
		}








>
>
>
>
>
>
>
>
>
>
>




















>
>
>







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
		$attributes = array_diff_key($params, array_flip($params_list));
		$params = array_intersect_key($params, array_flip($params_list));
		extract($params, \EXTR_SKIP);

		if (!isset($name, $type)) {
			throw new \InvalidArgumentException('Missing name or type');
		}

		$suffix = null;

		if ($type == 'datetime') {
			$type = 'date';
			$tparams = func_get_arg(0);
			$tparams['type'] = 'time';
			$tparams['name'] = sprintf('%s_time', $name);
			unset($tparams['label']);
			$suffix = self::formInput($tparams);
		}

		$current_value = null;
		$current_value_from_user = false;

		if (isset($_POST[$name])) {
			$current_value = $_POST[$name];
			$current_value_from_user = true;
		}
		elseif (isset($source) && is_object($source) && isset($source->$name)) {
			$current_value = $source->$name;
		}
		elseif (isset($source) && is_array($source) && isset($source[$name])) {
			$current_value = $source[$name];
		}
		elseif (isset($default)) {
			$current_value = $default;
		}

		if ($type == 'date' && is_object($current_value) && $current_value instanceof \DateTimeInterface) {
			$current_value = $current_value->format('d/m/Y');
		}
		elseif ($type == 'time' && is_object($current_value) && $current_value instanceof \DateTimeInterface) {
			$current_value = $current_value->format('H:i');
		}
		elseif ($type == 'date' && is_string($current_value)) {
			if ($v = \DateTime::createFromFormat('!Y-m-d', $current_value)) {
				$current_value = $v->format('d/m/Y');
			}
		}

269
270
271
272
273
274
275








276
277
278
279
280
281
282
			$type = 'text';
			$attributes['placeholder'] = 'JJ/MM/AAAA';
			$attributes['data-input'] = 'date';
			$attributes['size'] = 12;
			$attributes['maxlength'] = 10;
			$attributes['pattern'] = '\d\d?/\d\d?/\d{4}';
		}









		// Create attributes string
		if (array_key_exists('required', $attributes)) {
			$attributes['required'] = 'required';
		}

		if (!empty($attributes['disabled'])) {







>
>
>
>
>
>
>
>







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
			$type = 'text';
			$attributes['placeholder'] = 'JJ/MM/AAAA';
			$attributes['data-input'] = 'date';
			$attributes['size'] = 12;
			$attributes['maxlength'] = 10;
			$attributes['pattern'] = '\d\d?/\d\d?/\d{4}';
		}
		elseif ($type == 'time') {
			$type = 'text';
			$attributes['placeholder'] = 'HH:MM';
			$attributes['data-input'] = 'time';
			$attributes['size'] = 8;
			$attributes['maxlength'] = 5;
			$attributes['pattern'] = '\d\d?:\d\d?';
		}

		// Create attributes string
		if (array_key_exists('required', $attributes)) {
			$attributes['required'] = 'required';
		}

		if (!empty($attributes['disabled'])) {
375
376
377
378
379
380
381


382
383
384
385
386
387
388

			return $input;
		}

		if ($type == 'file') {
			$input .= sprintf('<input type="hidden" name="MAX_FILE_SIZE" value="%d" id="f_maxsize" />', Utils::return_bytes(Utils::getMaxUploadSize()));
		}



		$label = sprintf('<label for="%s">%s</label>', $attributes['id'], $this->escape($label));

		if ($type == 'radio' || $type == 'checkbox') {
			$out = sprintf('<dd>%s %s', $input, $label);

			if (isset($help)) {







>
>







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

			return $input;
		}

		if ($type == 'file') {
			$input .= sprintf('<input type="hidden" name="MAX_FILE_SIZE" value="%d" id="f_maxsize" />', Utils::return_bytes(Utils::getMaxUploadSize()));
		}

		$input .= $suffix;

		$label = sprintf('<label for="%s">%s</label>', $attributes['id'], $this->escape($label));

		if ($type == 'radio' || $type == 'checkbox') {
			$out = sprintf('<dd>%s %s', $input, $label);

			if (isset($help)) {
402
403
404
405
406
407
408



409
410
411
412
413
414
415
				$out .= sprintf('<dd class="help">%s</dd>', $this->escape($help));
			}
		}

		return $out;
	}




	protected function formField(array $params, $escape = true)
	{
		if (!isset($params['name']))
		{
			throw new \BadFunctionCallException('name argument is mandatory');
		}








>
>
>







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
				$out .= sprintf('<dd class="help">%s</dd>', $this->escape($help));
			}
		}

		return $out;
	}

	/**
	 * @deprecated
	 */
	protected function formField(array $params, $escape = true)
	{
		if (!isset($params['name']))
		{
			throw new \BadFunctionCallException('name argument is mandatory');
		}

Deleted src/templates/admin/wiki/creer.tpl version [e927f05760].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{include file="admin/_head.tpl" title="Créer une page" current="wiki"}

{form_errors}

<form method="post" action="{$self_url}">

    <fieldset>
        <legend>Informations</legend>
        <dl>
            <dt><label for="f_titre">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="text" name="titre" id="f_titre" value="{form_field name=titre}" /></dd>
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="wiki_create"}
        {button type="submit" name="create" label="Créer cette page" shape="right" class="main"}
    </p>

</form>


{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































Deleted src/templates/admin/wiki/editer.tpl version [fa476c25ad].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
{include file="admin/_head.tpl" title="Éditer une page" current="wiki"}

{form_errors}

<form method="post" action="{$self_url}" id="f_form">

    <fieldset class="wikiMain">
        <legend>Informations générales</legend>
        <dl>
            <dt><label for="f_titre">Titre</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd><input type="text" name="titre" id="f_titre" value="{form_field data=$page name=titre}" required="required" /></dd>
            <dt><label for="f_uri">Adresse unique</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd class="help">
                Ne peut comporter que des lettres, des chiffres, des tirets et des tirets bas.
            </dd>
            <dd><input type="text" name="uri" id="f_uri" value="{form_field data=$page name=uri}" required="required" /></dd>
            <dt><label for="f_browse_parent">Cette page est une sous-rubrique de...</label></dt>
            <dd>
                <input type="hidden" name="parent" id="f_parent" value="{form_field data=$page name=parent}" />
                {if $page.parent == 0}
                    <samp id="current_parent_name">la racine du site</samp>
                {else}
                    <samp id="current_parent_name">{$parent}</samp>
                {/if}
                <input type="button" id="f_browse_parent" onclick="browseWikiForParent();" value="Changer" />
            </dd>
            <dt><label for="f_date">Date</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
            <dd>
                <input type="date" size="10" name="date" id="f_date" value="{$date|date_fr:'Y-m-d'}" pattern="{literal}^\d{4}-\d{2}-\d{2}${/literal}" required="required" />
                <input type="text" class="time" size="2" name="date_h" value="{$date|date_fr:'H'}" pattern="^{literal}\d{1,2}${/literal}" required="required" /> h
                <input type="text" class="time" size="2" name="date_min" value="{$date|date_fr:'i'}" pattern="{literal}^\d{1,2}${/literal}" required="required" />
            </dd>
        </dl>
    </fieldset>

    <fieldset class="wikiRights">
        <legend>Droits d'accès</legend>
        <dl>
            <dt><label for="f_droit_lecture_public">Cette page est visible :</label></dt>
            <dd>
                <input type="radio" name="droit_lecture" id="f_droit_lecture_public" value="{$wiki::LECTURE_PUBLIC}" {form_field data=$page name="droit_lecture" checked=$wiki::LECTURE_PUBLIC} />
                <label for="f_droit_lecture_public"><strong>Sur le site de l'association</strong></label>
                &mdash; cette page apparaîtra sur le site public de l'association, accessible à tous les visiteurs
            </dd>
            <dd>
                <input type="radio" name="droit_lecture" id="f_droit_lecture_normal" value="{$wiki::LECTURE_NORMAL}"  {form_field data=$page name="droit_lecture" checked=$wiki::LECTURE_NORMAL} />
                <label for="f_droit_lecture_normal"><strong>Sur le wiki uniquement</strong></label>
                &mdash; seuls les membres ayant accès au wiki pourront la voir
            </dd>
            <dd>
                <input type="radio" name="droit_lecture" id="f_droit_lecture_categorie" value="{$user.id_categorie}"  {if $page.droit_lecture >= $wiki::LECTURE_CATEGORIE}checked="checked"{/if} />
                <label for="f_droit_lecture_categorie"><strong>Aux membres de ma catégorie</strong></label>
                &mdash; seuls les membres de la même catégorie que moi pourront voir cette page
            </dd>
            <dt><label for="f_droit_ecriture_normal">Cette page peut être modifiée par :</label></dt>
            <dd>
                <input type="radio" name="droit_ecriture" id="f_droit_ecriture_normal" value="{$wiki::ECRITURE_NORMAL}" {form_field data=$page name="droit_ecriture" checked=$wiki::ECRITURE_NORMAL} {if $page.droit_lecture >= $wiki::LECTURE_CATEGORIE}disabled="disabled"{/if} />
                <label for="f_droit_ecriture_normal">Les membres qui ont accès au wiki en écriture</label>
            </dd>
            <dd>
                <input type="radio" name="droit_ecriture" id="f_droit_ecriture_categorie" value="{$user.id_categorie}" {if $page.droit_ecriture >= $wiki::ECRITURE_CATEGORIE || $page.droit_lecture >= $wiki::LECTURE_CATEGORIE}checked="checked"{/if} {if $page.droit_lecture >= $wiki::LECTURE_CATEGORIE}disabled="disabled"{/if} />
                <label for="f_droit_ecriture_categorie">Les membres de ma catégorie</label>
            </dd>
        </dl>
    </fieldset>

    <fieldset class="wikiEncrypt">
        <dl>
            <dt>
                <input type="checkbox" name="chiffrement" id="f_chiffrement" {form_field name=chiffrement data=$page default=0 checked=1} value="1" onchange="checkEncryption(this);" />
                <label for="f_chiffrement">Chiffrer le contenu</label> <i>(facultatif)</i>
            </dt>
            <noscript>
            <dd>Nécessite JavaScript activé pour fonctionner !</dd>
            </noscript>
            <dd>Mot de passe : <i id="encryptPasswordDisplay" title="Chiffrement désactivé">désactivé</i></dd>
            <dd class="help">Le mot de passe n'est ni transmis ni enregistré, vous seul le connaissez,
                il n'est pas possible de retrouver le contenu si vous l'oubliez.</dd>
        </dl>
    </fieldset>


    <fieldset class="wikiText">
        <div class="textEditor">
            <textarea name="contenu" id="f_contenu" cols="70" rows="35">{form_field data=$page name=contenu}</textarea>
        </div>
    </fieldset>

    <fieldset class="wikiRevision">
        <dl>
            <dt><label for="f_modification">Résumé des modifications</label>  <i>(facultatif)</i></dt>
            <dd><input type="text" name="modification" id="f_modification" value="{form_field data=$page name=modification}" /></dd>
            {* FIXME
            <dt>
                <input type="checkbox" name="suivi" value="1" id="f_suivi" />
                <label for="f_suivi">Suivre les modifications de cette page</label>
            </dt>
            *}
        </dl>
    </fieldset>

    <p class="submit">
        {csrf_field key="wiki_edit_%d"|args:$page.id}
        <input type="hidden" name="revision_edition" value="{form_field name=revision_edition default=$page.revision}" />
        <input type="hidden" name="debut_edition" value="{form_field name=debut_edition default=$time}" />
        <input id="f_id" value="{$page.id}" type="hidden" />
        {button type="submit" name="save" label="Enregistrer" shape="right" class="main"}
    </p>

</form>

<script type="text/javascript">
var page_id = '{$page.id}';
{literal}
(function() {
    $('#f_droit_lecture_categorie').onchange = function()
    {
        $('#f_droit_ecriture_normal').checked = false;
        $('#f_droit_ecriture_normal').disabled = true;

        $('#f_droit_ecriture_categorie').checked = true;
        $('#f_droit_ecriture_categorie').disabled = true;
    };

    $('#f_droit_lecture_normal').onchange = function() {
        $('#f_droit_ecriture_normal').disabled = false;
        $('#f_droit_ecriture_categorie').disabled = false;
    };

    $('#f_droit_lecture_public').onchange = function() {
        $('#f_droit_ecriture_normal').disabled = false;
        $('#f_droit_ecriture_categorie').disabled = false;
    };

    window.changeParent = function(parent, title)
    {
        if (parent == page_id)
        {
            return false;
        }

        $('#f_parent').value = parent;
        $('#current_parent_name').innerHTML = title;
        return true;
    };

    window.browseWikiForParent = function()
    {
        window.open('_chercher_parent.php?parent=' + $('#f_parent').value, 'browseParent',
            'width=500,height=600,top=150,left=150,scrollbars=1,location=false');
    };

    if ($('#f_chiffrement').checked)
    {
        wikiDecrypt(true);
    }
}());
</script>
{/literal}

{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































Deleted src/templates/admin/wiki/historique.tpl version [ad74fa04e5].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{include file="admin/_head.tpl" title="Historique : %s"|args:$page.titre current="wiki"}

<nav class="tabs">
    <ul>
        <li><a href="{$admin_url}wiki/?{$page.uri}">Retour à la page</a></li>
    </ul>
</nav>

{if !empty($revisions)}
    <table class="list wikiRevisions">
    {foreach from=$revisions item="rev"}
        <tr>
            <td>
                {if $rev.chiffrement}
                    <del title="Contenu chiffré">chiffré</del>
                {else}
                    {if $rev.revision == $page.revision}
                        actu
                    {else}
                        <a href="?id={$page.id}&amp;diff={$rev.revision}.{$page.revision}">actu</a>
                    {/if}
                    |
                    {if $rev.revision == 1}
                        diff
                    {else}
                        <a href="?id={$page.id}&amp;diff={$rev.revision-1}.{$rev.revision}">diff</a>
                    {/if}
                {/if}
            </td>
            <th>{$rev.date|date_long}</th>
            <td>
                {if $session->canAccess('membres', Membres::DROIT_ACCES)}
                <a href="{$admin_url}membres/fiche.php?id={$rev.id_auteur}">{$rev.nom_auteur}</a>
                {/if}
            </td>
            <td class="length">
                {$rev.taille} octets
                {if $rev.revision > 1 && !$rev.chiffrement}
                    {if $rev.diff_taille > 0}
                        <ins>(+{$rev.diff_taille})</ins>
                    {elseif $rev.diff_taille < 0}
                        <del>({$rev.diff_taille})</del>
                    {else}
                        <i>({$rev.diff_taille})</i>
                    {/if}
                {/if}
            </td>
            <td>
            {if $rev.modification}
                <em>{$rev.modification}</em>
            {/if}
            </td>
        </tr>
    {/foreach}
    </table>
{elseif !empty($diff)}
    <div class="wikiRevision revisionLeft">
        <h3>Version du {$rev1.date|date_long}</h3>
        {if $session->canAccess('membres', Membres::DROIT_ACCES)}
            <h4>De <a href="{$admin_url}membres/fiche.php?id={$rev1.id_auteur}">{$rev1.nom_auteur}</a></h4>
        {/if}
        {if $rev1.modification}
            <p><em>{$rev1.modification}</em></p>
        {/if}
    </div>
    <div class="wikiRevision revisionRight">
        <h3>Version {if $rev2.revision == $page.revision}actuelle en date{/if} du {$rev2.date|date_long}</h3>
        {if $session->canAccess('membres', Membres::DROIT_ACCES)}
            <h4>De <a href="{$admin_url}membres/fiche.php?id={$rev2.id_auteur}">{$rev2.nom_auteur}</a></h4>
        {/if}
        {if $rev2.modification}
            <p><em>{$rev2.modification}</em></p>
        {/if}
    </div>
    {diff old=$rev1.contenu new=$rev2.contenu}
{else}
    <p class="block alert">
        Cette page n'a pas d'historique.
    </p>
{/if}


{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































Deleted src/templates/admin/wiki/recent.tpl version [b616432b4b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{include file="admin/_head.tpl" title="Pages modifiées récemment" current="wiki/recent"}

{if !empty($list)}
    <table class="list">
        <tbody>
        {foreach from=$list item="page"}
        <tr>
            <th><a href="{$admin_url}wiki/?{$page.uri}">{$page.titre}</a></th>
            <td>{$page.date_modification|date_long}</td>
        </tr>
        {/foreach}
        </tbody>
    </table>

    {pagination url="?p=[ID]" page=$current_page bypage=$bypage total=$total}
{else}
    <p class="block alert">Pas de modification récente.</p>
{/if}

{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































Deleted src/templates/admin/wiki/supprimer.tpl version [0d139503af].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{include file="admin/_head.tpl" title="Supprimer : %s"|args:$page.titre current="wiki"}

<nav class="tabs">
    <ul>
        <li><a href="{$admin_url}wiki/"><strong>Wiki</strong></a></li>
        <li><a href="{$admin_url}wiki/chercher.php">Rechercher</a></li>
        <li><a href="{$admin_url}wiki/?{$page.uri}">Voir la page</a></li>
        <li><a href="{$admin_url}wiki/editer.php?id={$page.id}">Éditer</a></li>
    </ul>
</nav>

{form_errors}

<form method="post" action="{$self_url}">

    <fieldset>
        <legend>Supprimer cette page du wiki ?</legend>
        <h3 class="warning">
            Êtes-vous sûr de vouloir supprimer la page «&nbsp;{$page.titre}&nbsp;» ?
        </h3>
        <p class="help">
            La page ne pourra pas être supprimée si d'autres pages l'utilisent comme rubrique
            parente.
        </p>
    </fieldset>

    <p class="submit">
        {csrf_field key="delete_wiki_"|cat:$page.id}
        {button type="submit" name="delete" label="Supprimer" shape="right" class="main"}
    </p>

</form>

{include file="admin/_foot.tpl"}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































Name change from src/templates/admin/wiki/_fichiers.tpl to src/templates/web/_attach.php.

Name change from src/templates/admin/wiki/_preview.tpl to src/templates/web/_preview.tpl.

Name change from src/templates/admin/wiki/_chercher_parent.tpl to src/templates/web/_selector.tpl.

Modified src/templates/web/edit.tpl from [5664c13bce] to [3ef23491dd].

1
2
3
4
5

6
7
8
9


10





11












12
13















14





15

16











































17
{include file="admin/_head.tpl" title="Édition : %s"|args:$page.title current="web"}

{form_errors}

<form method="post" action="{$self_url}" class="web-edit">

	<fieldset>
		<legend>Édition</legend>
		<dl>
			{input type="text" label="Titre" required=true name="title" source=$page}


			{input type="text" label="Adresse unique" required=true name="uri" source=$page}





			{input type="checkbox" label="Brouillon" name="status" value=$page::STATUS_DRAFT source=$page help="Si coché, ne sera pas visible sur le site public"}












		</dl>
	</fieldset>















</form>



















































{include file="admin/_foot.tpl"}





>
|
|

|
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
{include file="admin/_head.tpl" title="Édition : %s"|args:$page.title current="web"}

{form_errors}

<form method="post" action="{$self_url}" class="web-edit">

	<fieldset class="wikiMain">
		<legend>Informations générales</legend>
		<dl>
			{input type="text" name="title" source=$page required=true label="Titre"}
			{input type="text" name="uri" source=$page required=true label="Adresse unique URI" help="Utilisée pour désigner l'adresse de la page sur le site. Ne peut comporter que des lettres, des chiffres, des tirets et des tirets bas." pattern="[A-Za-z0-9_-]+"}
			{input type="list" name="parent_id" label="Catégorie" default=$parent target="web/_selector.php?current=%d"|args:$page.parent_id required=true}
			{input type="datetime" name="date" label="Date" required=true default=$page->file()->created}
			<dt>Statut</dt>
			{input type="radio" name="status" value=$page::STATUS_ONLINE label="En ligne" source=$page}
			{input type="radio" name="status" value=$page::STATUS_DRAFT label="Brouillon" source=$page}
		</dl>
	</fieldset>

	<fieldset class="wikiEncrypt">
		<dl>
			<dt>
				<input type="checkbox" name="encryption" id="f_encryption" {if $encrypted} checked="checked"{/if} value="1" onchange="checkEncryption(this);" />
				<label for="f_encryption">Chiffrer le contenu</label> <i>(facultatif)</i>
			</dt>
			<noscript>
			<dd>Nécessite JavaScript activé pour fonctionner !</dd>
			</noscript>
			<dd>Mot de passe : <i id="encryptPasswordDisplay" title="Chiffrement désactivé">désactivé</i></dd>
			<dd class="help">Le mot de passe n'est ni transmis ni enregistré, vous seul le connaissez,
				il n'est pas possible de retrouver le contenu si vous l'oubliez.</dd>
		</dl>
	</fieldset>


	<fieldset class="wikiText">
		<div class="textEditor">
			{input type="textarea" name="content" cols="70" rows="35" default=$page->file()->fetch() required=true}
		</div>
	</fieldset>

	<p class="submit">
		{csrf_field key=$csrf_key}
		<input type="hidden" name="editing_started" value="{$editing_started}" />
		{button type="submit" name="save" label="Enregistrer" shape="upload" class="main"}
		{button type="submit" name="cancel" label="Retourner à la liste" shape="reset"}
	</p>

</form>
<script type="text/javascript">
var page_id = '{$page.id}';
{literal}
(function() {
	window.changeParent = function(parent, title)
	{
		if (parent == page_id)
		{
			return false;
		}

		$('#f_parent').value = parent;
		$('#current_parent_name').innerHTML = title;
		return true;
	};

	window.browseWikiForParent = function()
	{
		window.open('_chercher_parent.php?parent=' + $('#f_parent').value, 'browseParent',
			'width=500,height=600,top=150,left=150,scrollbars=1,location=false');
	};

	if ($('#f_encryption').checked)
	{
		wikiDecrypt(true);
	}

	if (location.hash == '#saved') {
		location.hash = '';

		let c = document.createElement('p');
		c.className = 'block confirm';
		c.id = 'confirm_saved';
		c.innerText = 'Enregistré';
		c.style.right = '-10em';

		document.querySelector('#f_content').parentNode.appendChild(c);

		window.setTimeout(() => {
			c.style.right = '';
		}, 200);

		window.setTimeout(() => {
			c.style.opacity = 0;
		}, 3000);
	}
}());
</script>
{/literal}


{include file="admin/_foot.tpl"}

Name change from src/templates/admin/wiki/page.tpl to src/templates/web/page.tpl.

Name change from src/templates/admin/wiki/chercher.tpl to src/templates/web/search.tpl.

Modified src/www/admin/static/scripts/wiki-encryption.js from [2f0eae2745] to [78239d4188].

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

		encryptPassword = window.prompt('Mot de passe ?');

		if (!encryptPassword)
		{
			encryptPassword = null;

			if (document.getElementById('f_contenu'))
			{
				if (window.confirm("Aucun mot de passe entré.\nDésactiver le chiffrement et effacer le contenu ?"))
				{
					document.getElementById('f_contenu').value = '';
					document.getElementById('f_chiffrement').checked = false;
					checkEncryption(document.getElementById('f_chiffrement'));
				}
				else
				{
					wikiDecrypt();
				}
			}








|



|
|
|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

		encryptPassword = window.prompt('Mot de passe ?');

		if (!encryptPassword)
		{
			encryptPassword = null;

			if (document.getElementById('f_content'))
			{
				if (window.confirm("Aucun mot de passe entré.\nDésactiver le chiffrement et effacer le contenu ?"))
				{
					document.getElementById('f_content').value = '';
					document.getElementById('f_encrypted').checked = false;
					checkEncryption(document.getElementById('f_encrypted'));
				}
				else
				{
					wikiDecrypt();
				}
			}

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
			}

			iteration++;
			window.setTimeout(decrypt, 500);
			return;
		}

		var content = document.getElementById('f_contenu');
		var edit = true;

		if (!content) {
		 	content = document.getElementById('wikiEncryptedContent');
		 	edit = false;
		}








|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
			}

			iteration++;
			window.setTimeout(decrypt, 500);
			return;
		}

		var content = document.getElementById('f_content');
		var edit = true;

		if (!content) {
		 	content = document.getElementById('wikiEncryptedContent');
		 	edit = false;
		}

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
			content.style.display = 'block';
			document.getElementById('wikiEncryptedMessage').style.display = 'none';
			content.innerHTML = formatContent(wikiContent);
		}
		else
		{
			content.value = wikiContent;
			checkEncryption(document.getElementById('f_chiffrement'));
		}
	};

	window.checkEncryption = function(elm)
	{
		String.prototype.repeat = function(num)
		{







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
			content.style.display = 'block';
			document.getElementById('wikiEncryptedMessage').style.display = 'none';
			content.innerHTML = formatContent(wikiContent);
		}
		else
		{
			content.value = wikiContent;
			checkEncryption(document.getElementById('f_encrypted'));
		}
	};

	window.checkEncryption = function(elm)
	{
		String.prototype.repeat = function(num)
		{
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
			{
				if (typeof GibberishAES == 'undefined')
				{
					alert("Le chargement de la bibliothèque AES n'est pas terminé.\nLe chiffrement est impossible pour le moment, recommencez dans quelques instants ou désactivez le chiffrement.");
					return false;
				}

				var content = document.getElementById('f_contenu');
				content.value = GibberishAES.enc(content.value, encryptPassword);
				content.readOnly = true;
				return true;
			};
		}
		else
		{







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
			{
				if (typeof GibberishAES == 'undefined')
				{
					alert("Le chargement de la bibliothèque AES n'est pas terminé.\nLe chiffrement est impossible pour le moment, recommencez dans quelques instants ou désactivez le chiffrement.");
					return false;
				}

				var content = document.getElementById('f_content');
				content.value = GibberishAES.enc(content.value, encryptPassword);
				content.readOnly = true;
				return true;
			};
		}
		else
		{

Added src/www/admin/static/scripts/wiki_editor.css version [30c3c98262].

































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
.textEditor {
    border-radius: .5em;
    background: #ccc;
    padding: 1%;
    overflow: hidden;
    position: relative;
}

.textEditor textarea {
    border: none;
    margin: 0;
    background: #eee;
    border-radius: .5em;
    height: 96%;
    width: 98%;
}

nav.te {
    margin-bottom: .5em;
    height: 30px;
}

nav.te button {
    text-decoration: none;
    cursor: pointer;
    background: #eee no-repeat center center;
    display: inline-block;
    vertical-align: bottom;
    transition: all .2s;
    border: 1px solid #999;
    box-shadow: 2px 2px 5px #999;
}

nav.te .bold, nav.te .italic, nav.te .title, nav.te .link {
    font-family: Georgia, "Times New Roman", serif;
}

nav.te .bold { font-weight: bold; }
nav.te .italic { font-style: italic; }
nav.te .link { text-decoration: underline; color: blue; }

nav.te .fullscreen {
    text-indent: -70em;
    width: 32px;
    overflow: hidden;
}

nav.te .icnl {
    font-size: 18px;
}

nav.te .ext.icnl {
    width: 24px;
    line-height: 5px;
    overflow: hidden;
}

nav.te .file {
    margin-left: 2em;
}

nav.te .fullscreen {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABMTFFOTlBOTlCQ1uMHAAAAA3RSTlMAOcKBmOr4AAAAQUlEQVQI12P4/4D7P8N/B0Yo8XsC23+GZw+4pzM4TmBzYsAGgBKODNcecM9m+D+B7T3DPwfG/Qz/G5iABlzg+g8ANzMax/3kkQoAAAAASUVORK5CYII=");
    float: right;
}

nav.te .preview {
    margin-left: 2em;
}

.textEditor.fullscreen nav.te .fullscreen {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABNTVFOTlBOTlBLB/faAAAAA3RSTlMAOsPdsomtAAAAQElEQVQI12NIEWCRZNi5gTePIe8D/08G6Q/8Txj0P/B/YVj/gf8fAzawHyQhD1ICJvI/8O9k2FnAl8eQosAiCQCgixb13aKGIwAAAABJRU5ErkJggg==");
}

.textEditor nav button.close {
    display: none;
    float: right;
}

.textEditor nav button.reload {
    display: none;
    float: left;
}

.textEditor.fullscreen {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 98%;
    height: 98%;
    padding: 1%;
    border-radius: 0;
    z-index: 100000;
}

.textEditor.fullscreen textarea {
    height: 90%;
}

.textEditor.iframe textarea {
    display: none;
}

.textEditor.iframe nav button {
    display: none;
}

.textEditor.iframe nav button.close, .textEditor.iframe nav button.reload {
    display: inline-block;
}

.textEditor iframe {
    border: none;
    background: #eee;
    border-radius: .5em;
    padding: 1%;
    width: 98%;
}

.textEditor iframe.hidden {
    visibility: hidden;
    width: 0px;
    height: 0px;
    position: absolute;
    top: -1000px;
}

Added src/www/admin/static/scripts/wiki_editor.js version [888ea259ae].

































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
(function () {
	var wiki_id = window.location.search.match(/id=(\d+)/)[1];

	g.onload(function () {
		g.style('scripts/wiki_editor.css');

		g.script('scripts/text_editor.min.js', function () {
			var t = new textEditor('f_content');
			t.parent = t.textarea.parentNode;

			var toolbar = document.createElement('nav');
			toolbar.className = 'te';

			var toggleFullscreen = function (e)
			{
				var classes = t.parent.className.split(' ');

				for (var i = 0; i < classes.length; i++)
				{
					if (classes[i] == 'fullscreen')
					{
						classes.splice(i, 1);
						t.parent.className = classes.join(' ');
						t.fullscreen = false;
						return true;
					}
				}

				classes.push('fullscreen');
				t.parent.className = classes.join(' ');
				t.fullscreen = true;
				return true;
			};

			var openPreview = function ()
			{
				openIFrame('');
				var form = document.createElement('form');
				form.appendChild(t.textarea.cloneNode(true));
				form.firstChild.value = t.textarea.value;
				form.target = 'editorFrame';
				form.action = g.admin_url + 'wiki/_preview.php?id=' + wiki_id;
				form.style.display = 'none';
				form.method = 'post';
				document.body.appendChild(form);
				form.submit();
				//document.body.removeChild(form);
			};

			var openSyntaxHelp = function ()
			{
				openIFrame(g.admin_url + 'wiki/_syntaxe.html');
			};

			var openFileInsert = function ()
			{
				openIFrame(g.admin_url + 'wiki/_fichiers.php?page=' + wiki_id);
			};

			window.te_insertFile = function (file)
			{
				var tag = '<<fichier|'+file+'>>';
				
				t.insertAtPosition(t.getSelection().start, tag);
				
				closeIFrame();
			};

			window.te_insertImage = function (file, position, caption)
			{
				var tag = '<<image|' + file;

				if (position)
					tag += '|' + position;

				if (caption)
					tag += '|' + caption;
				
				tag += '>>';
				
				t.insertAtPosition(t.getSelection().start, tag);
				
				closeIFrame();
			};

			var openIFrame = function(url)
			{
				if (t.iframe && t.iframe.src == t.base_url + url)
				{
					t.iframe.className = '';
					t.parent.className += ' iframe';
					return true;
				}
				else if (t.iframe)
				{
					t.parent.removeChild(t.iframe);
					t.iframe = null;
				}

				var w = t.textarea.offsetWidth,
					h = t.textarea.offsetHeight;

				var iframe = document.createElement('iframe');
				iframe.width = w;
				iframe.height = h;
				iframe.src = url;
				iframe.name = 'editorFrame';
				iframe.frameborder = '0';
				iframe.scrolling = 'yes';

				t.parent.appendChild(iframe);
				t.parent.className += ' iframe';
				t.iframe = iframe;
			};

			var closeIFrame = function ()
			{
				t.parent.className = t.parent.className.replace(/ iframe$/, '');
				t.iframe.className = 'hidden';
			};


			var appendButton = function (name, title, action, altTitle)
			{
				var btn = document.createElement('button');
				btn.type = 'button';
				btn.title = altTitle ? altTitle : title;
				if (title.length == 1) {
					btn.dataset.icon = title;
				}
				else {
					btn.innerText = title;
				}
				btn.className = 'icn-btn ' +name;
				btn.onclick = function () { action.call(); return false; };

				toolbar.appendChild(btn);
				return btn;
			};

			var wrapTags = function (left, right)
			{
				t.wrapSelection(t.getSelection(), left, right);
				return true;
			};

			appendButton('title', "== Titre", function () { wrapTags("== ", ""); } );
			appendButton('bold', '**gras**', function () { wrapTags('**', '**'); } );
			appendButton('italic', "''italique''", function () { wrapTags("''", "''"); } );
			appendButton('link', "[[lien|http://]]", function () { 
				if (url = window.prompt('Adresse URL ?')) 
					wrapTags("[[", "|" + url + ']]'); 
			} );
			appendButton('file', "📎", openFileInsert, 'Insérer fichier / image');

			appendButton('ext preview', '👁', openPreview, 'Prévisualiser');

			appendButton('ext help', '❓', openSyntaxHelp, 'Aide sur la syntaxe');
			appendButton('ext fullscreen', 'Plein écran', toggleFullscreen, 'Plein écran');
			appendButton('ext close', 'Fermer', closeIFrame);

			t.parent.insertBefore(toolbar, t.parent.firstChild);

			t.shortcuts.push({key: 'F11', callback: toggleFullscreen});
			t.shortcuts.push({ctrl: true, key: 'b', callback: function () { return wrapTags('**', '**'); } });
			t.shortcuts.push({ctrl: true, key: 'g', callback: function () { return wrapTags('**', '**'); } });
			t.shortcuts.push({ctrl: true, key: 'i', callback: function () { return wrapTags("''", "''"); } });

			if (window.location.hash.match(/fullscreen/))
			{
				t.toggleFullscreen();
				window.location.hash = '';
			}
		});
	});
}());

Modified src/www/admin/static/wiki.css from [c1552b949b] to [2c20ca7f50].

109
110
111
112
113
114
115
116







117


118
119
120
121
122
123
124
125
126
127
128
129
130


131

132
133
134
135
136
137
138




139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    background: #fff;
    padding: 1em;
    max-height: 90%;
    max-width: 90%;
    border-radius: .5em;
    cursor: e-resize;
}








fieldset.wikiText {


    border: none;
    padding: 0;
}

fieldset.wikiMain, fieldset.wikiRights, fieldset.wikiEncrypt {
    float: right;
    width: 35%;
    margin-left: 3%;
    clear: right;
}

fieldset.wikiMain input[type=text] {
    min-width: 0;


}


#encryptPasswordDisplay {
    cursor: help;
    background: #ddd;
}

fieldset.wikiEncrypt .help {




    font-size: .9em;
}

fieldset.wikiMain #f_titre {
    width: 90%;
    font-size: 14pt;
}

fieldset.wikiMain #f_uri {
    width: 90%;
}

fieldset.wikiRights dl {
    font-size: 10pt;
}

fieldset.wikiRevision  {
    clear: both;
}

fieldset.wikiRevision #f_modification {
    width: 90%;
}

.wikiFiles {
    text-align: center;
}

.wikiFooter, .wikiFiles {
    font-size: 0.8em;








>
>
>
>
>
>
>

>
>




|
<
|
<
<


<
|
>
>
|
>






|
>
>
>
>



|








<
<
<
<
<
<
<
<
<
<
<







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

132


133
134

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162











163
164
165
166
167
168
169
    background: #fff;
    padding: 1em;
    max-height: 90%;
    max-width: 90%;
    border-radius: .5em;
    cursor: e-resize;
}

.web-edit {
    display: grid;
    grid-template-columns: 1fr 30%;
    grid-template-rows: .3fr .3fr .3fr;
    grid-gap: 2em;
}

fieldset.wikiText {
    grid-column: 1;
    grid-row: 1/3;
    border: none;
    padding: 0;
}

.web-edit input[type=text] {

    min-width: 0;


}


@media screen and (max-width: 980px) {
    .web-edit {
        display: block;
    }
}

#encryptPasswordDisplay {
    cursor: help;
    background: #ddd;
}

fieldset.wikiEncrypt, fieldset.wikiMain, .web-edit p.submit {
    grid-column: 2;
}

.web-edit dd.help {
    font-size: .9em;
}

fieldset.wikiMain #f_title {
    width: 90%;
    font-size: 14pt;
}

fieldset.wikiMain #f_uri {
    width: 90%;
}













.wikiFiles {
    text-align: center;
}

.wikiFooter, .wikiFiles {
    font-size: 0.8em;
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
}

.wikiResults p {
    margin-bottom: .8em;
    font-size: .9em;
}

.wikiRevisions .length ins {
    text-decoration: none;
    color: green;
}

.wikiRevisions .length del {
    text-decoration: none;
    color: red;
}

.wikiRevisions .length i {
    font-style: normal;
    color: gray;
}

div.wikiRevision {
    width: 48%;
    margin: 1em 1%;
    text-align: center;
    float: left;
}

div.wikiRevision h3 {
    font-size: 1em;
}

div.wikiRevision h4 {
    font-weight: normal;
    font-size: .9em;
}

.diff .ins {
    background: #cfc;
    width: 45%;
}

.diff .del {
    background: #fcc;
    width: 45%;
}

.diff .line {
    width: 2%;
    padding: 0.2em;
    text-align: right;
    font-family: Mono;
    font-size: 90%;
    color: #666;
}

.diff .leftChange, .diff .rightChange {
    text-align: center;
    vertical-align: middle;
}

.diff ins { background: #9f9; }
.diff del { background: #f99; }

.diff hr {
    background: none;
    border: none;
    border-top: 5px dotted #fff;
    color: #fff;
    margin: .2em .4em;
}

.diff .separator {
    background: #ccc;
}

.diff {
    border-collapse: collapse;
    width: 100%;
    font-size: 0.9em;
}

.diff tr {
    border: 1px solid #ccc;
    vertical-align: top;
}

.diff .leftChange b, .diff .rightChange b {
    text-shadow: 1px 1px 1px #ccc;
    color: #666;
}

form#f_upload fieldset {
    position: relative;
}

form .fileUpload .uploadHelper_progress {
    position: absolute;
    bottom: 1em;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







268
269
270
271
272
273
274






















































































275
276
277
278
279
280
281
}

.wikiResults p {
    margin-bottom: .8em;
    font-size: .9em;
}























































































form#f_upload fieldset {
    position: relative;
}

form .fileUpload .uploadHelper_progress {
    position: absolute;
    bottom: 1em;
442
443
444
445
446
447
448








}

form#insertImage .align input:hover, form#insertImage .cancel input:hover  {
    cursor: pointer;
    background-color: #eee;
    color: darkred;
}















>
>
>
>
>
>
>
>
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
}

form#insertImage .align input:hover, form#insertImage .cancel input:hover  {
    cursor: pointer;
    background-color: #eee;
    color: darkred;
}

#confirm_saved {
    position: absolute;
    top: .5em;
    right: 4em;
    text-align: center;
    transition: all .5s, opacity 3s;
}

Name change from src/www/admin/wiki/_fichiers.php to src/www/admin/web/_attach.php.

Name change from src/www/admin/wiki/_preview.php to src/www/admin/web/_preview.php.

Name change from src/www/admin/wiki/_chercher_parent.php to src/www/admin/web/_selector.php.

Name change from src/www/admin/wiki/_syntaxe.html to src/www/admin/web/_syntaxe.html.

Name change from src/www/admin/wiki/supprimer.php to src/www/admin/web/delete.php.

Modified src/www/admin/web/edit.php from [4a4a219729] to [53c2dc299d].

11
12
13
14
15
16
17

18




19
20
21
22
23



24
25
26
27
28
29
$page = Web::get($id);

if (!$page) {
    throw new UserException('Page inconnue');
}

$csrf_key = 'edit_' . $page->id();






$form->runIf('save', function ($page) {
    $page->importForm();
    $page->save();
}, $csrf_key, Utils::getSelfURI());




$tpl->assign(compact('page', 'csrf_key'));

$tpl->assign('custom_css', ['styles/web-content.css', 'styles/web.css']);
//$tpl->assign('custom_js', ['trix.min.js']);

$tpl->display('web/edit.tpl');







>

>
>
>
>
|


|

>
>
>
|

<
|


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34
35
36
$page = Web::get($id);

if (!$page) {
    throw new UserException('Page inconnue');
}

$csrf_key = 'edit_' . $page->id();
$editing_started = f('editing_started') ?: date('Y-m-d H:i:s');

if (f('cancel')) {
	Utils::redirect(ADMIN_URL . 'web/?parent=' . $page->parent_id);
}

$form->runIf('save', function () use ($page) {
    $page->importForm();
    $page->save();
}, $csrf_key, Utils::getSelfURI() . '#saved');

$parent = $page->parent_id ? [$page->parent_id => Web::get($page->parent_id)->title] : null;
$encrypted = f('encrypted') || $page->file()->type == Page::FILE_TYPE_ENCRYPTED;

$tpl->assign(compact('page', 'parent', 'editing_started', 'encrypted', 'csrf_key'));


$tpl->assign('custom_js', ['wiki_editor.js', 'wiki-encryption.js']);

$tpl->display('web/edit.tpl');

Name change from src/www/admin/wiki/index.php to src/www/admin/web/page.php.

Name change from src/www/admin/wiki/chercher.php to src/www/admin/web/search.php.

Deleted src/www/admin/wiki/_inc.php version [7e46f0d30d].

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('wiki', Membres::DROIT_ACCES);

$wiki = new Wiki;
$wiki->setRestrictionCategorie($user->id_categorie, $user->droit_wiki);

$tpl->assign('custom_css', ['wiki.css']);
<
<
<
<
<
<
<
<
<
<
<
<
























Deleted src/www/admin/wiki/creer.php version [fcf6294705].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$parent = (int) qg('parent');

if (f('create'))
{
    $form->check('wiki_create', [
        'titre' => 'required',
        'parent'=> 'required|integer'
    ]);

    try {
        $id = $wiki->create([
            'titre'  => f('titre'),
            'parent' => $parent,
            'droit_lecture' => qg('public') !== null ? Wiki::LECTURE_PUBLIC : Wiki::LECTURE_NORMAL,
        ]);

        Utils::redirect(ADMIN_URL . 'wiki/editer.php?id='.$id);
    }
    catch (UserException $e)
    {
        $form->addError($e->getMessage());
    }
}

$tpl->display('admin/wiki/creer.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Deleted src/www/admin/wiki/editer.php version [85c2033cca].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$session->requireAccess('wiki', Membres::DROIT_ECRITURE);

qv(['id' => 'required|numeric']);

$page = $wiki->getById(qg('id'));
$date = false;

if (!$page)
{
    throw new UserException('Page introuvable.');
}

if (!empty($page->contenu))
{
    $page->chiffrement = $page->contenu->chiffrement;
    $page->contenu = $page->contenu->contenu;
}

if (f('date'))
{
    $date = f('date') . ' ' . sprintf('%02d:%02d', f('date_h'), f('date_min'));
}

if (f('save'))
{
    $form->check('wiki_edit_' . $page->id, [
        'titre'          => 'required',
        'uri'            => 'required',
        'parent'         => 'numeric',
        'droit_lecture'  => 'numeric',
        'droit_ecriture' => 'numeric',
    ]);
    
    if ($page->date_modification > (int) f('debut_edition'))
    {
        $form->addError('La page a été modifiée par quelqu\'un d\'autre depuis que vous avez commencé l\'édition.');
    }

    if (!$form->hasErrors())
    {
        try {
            $wiki->edit($page->id, [
                'titre'         =>  f('titre'),
                'uri'           =>  f('uri'),
                'parent'        =>  f('parent'),
                'droit_lecture' =>  f('droit_lecture'),
                'droit_ecriture'=>  f('droit_ecriture'),
                'date_creation' =>  $date,
            ]);

            $wiki->editRevision($page->id, (int) f('revision_edition'), [
                'contenu'      =>  f('contenu'),
                'modification' =>  f('modification'),
                'id_auteur'    =>  $user->id,
                'chiffrement'  =>  f('chiffrement'),
            ]);

            $page = $wiki->getById($page->id);

            Utils::redirect(ADMIN_URL . 'wiki/?'.$page->uri);
        }
        catch (UserException $e)
        {
            $form->addError($e->getMessage());
        }
    }
}

$parent = (int) f('parent') ?: (int) $page->parent;
$tpl->assign('parent', $parent ? $wiki->getTitle($parent) : 0);

$tpl->assign('page', $page);

$tpl->assign('wiki', $wiki);

$tpl->assign('time', time());
$tpl->assign('date', $date ? strtotime($date) : $page->date_creation);

$tpl->assign('custom_js', ['wiki_editor.js', 'wiki-encryption.js']);

$tpl->display('admin/wiki/editer.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































Deleted src/www/admin/wiki/historique.php version [0c8cd47a0e].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

qv(['id' => 'required|numeric']);

$page = $wiki->getByID(qg('id'));

if (!$page)
{
    throw new UserException("Cette page n'existe pas.");
}

if (!$wiki->canReadPage($page->droit_lecture))
{
    throw new UserException("Vous n'avez pas le droit de voir cette page.");
}

if (qg('diff'))
{
    $revs = explode('.', qg('diff'));

    if (count($revs) != 2)
    {
        throw new UserException("Erreur de paramètre.");
    }

    $rev1 = $wiki->getRevision($page->id, (int)$revs[0]);
    $rev2 = $wiki->getRevision($page->id, (int)$revs[1]);

    if ($rev1->chiffrement)
    {
        $rev1->contenu = 'Contenu chiffré';
    }

    if ($rev2->chiffrement)
    {
        $rev2->contenu = 'Contenu chiffré';
    }

    $tpl->assign('rev1', $rev1);
    $tpl->assign('rev2', $rev2);
    $tpl->assign('diff', true);
}
else
{
    $tpl->assign('revisions', $wiki->listRevisions($page->id));
}

$tpl->assign('can_edit', $wiki->canWritePage($page->droit_ecriture));
$tpl->assign('page', $page);

$tpl->display('admin/wiki/historique.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































Deleted src/www/admin/wiki/recent.php version [8a00987ce2].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

namespace Garradin;

require_once __DIR__ . '/_inc.php';

$page = (int) qg('p') ?: 1;

$tpl->assign('current_page', $page);
$tpl->assign('bypage', Wiki::ITEMS_PER_PAGE);
$tpl->assign('total', $wiki->countRecentModifications());
$tpl->assign('list', $wiki->listRecentModifications($page));

$tpl->display('admin/wiki/recent.tpl');
<
<
<
<
<
<
<
<
<
<
<
<
<
<