Overview
Comment:Editor is working, now onto preview
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA1: 273b468d7d0f465fa263dc5f3ddfd3e49ffbbd60
User & Date: bohwaz on 2020-12-15 00:42:05
Other Links: branch diff | manifest | tags
Context
2020-12-15
01:56
Attachments working \o/ check-in: 8b6cb2def1 user: bohwaz tags: dev
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
Changes

Modified src/include/data/1.1.0_schema.sql from [1510ba50b8] to [0feccf33cb].

295
296
297
298
299
300
301
302

303
304
305
306
307
308
309
CREATE UNIQUE INDEX IF NOT EXISTS files_contents_hash ON files_contents (hash);

CREATE TABLE IF NOT EXISTS files_folders
(
    id INTEGER NOT NULL PRIMARY KEY,
    parent_id INTEGER NULL REFERENCES files_folders(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    system INTEGER NOT NULL DEFAULT 0

);

CREATE VIRTUAL TABLE IF NOT EXISTS files_search USING fts4
-- Search inside files content
(
    tokenize=unicode61, -- Available from SQLITE 3.7.13 (2012)
    id INT PRIMARY KEY NOT NULL REFERENCES files(id),







|
>







295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
CREATE UNIQUE INDEX IF NOT EXISTS files_contents_hash ON files_contents (hash);

CREATE TABLE IF NOT EXISTS files_folders
(
    id INTEGER NOT NULL PRIMARY KEY,
    parent_id INTEGER NULL REFERENCES files_folders(id) ON DELETE CASCADE,
    name TEXT NOT NULL,
    system INTEGER NOT NULL DEFAULT 0,
    CHECK (parent_id IS NULL OR parent_id != id)
);

CREATE VIRTUAL TABLE IF NOT EXISTS files_search USING fts4
-- Search inside files content
(
    tokenize=unicode61, -- Available from SQLITE 3.7.13 (2012)
    id INT PRIMARY KEY NOT NULL REFERENCES files(id),

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

1
2
3
4
5

6
7
8
9
10
11
12
<?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;





>







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

namespace Garradin\Entities\Files;

use KD2\Image;
use KD2\DB\EntityManager as EM;

use Garradin\DB;
use Garradin\Entity;
use Garradin\UserException;
use Garradin\Membres\Session;
use Garradin\Membres;
use Garradin\Utils;
336
337
338
339
340
341
342





343
344
345
346
347
348
349

		if (!in_array($type, $types)) {
			throw new \InvalidArgumentException('Unknown file link type.');
		}

		return DB::getInstance()->firstColumn(sprintf('SELECT %s FROM files_links WHERE id = %d;', $type, $this->id()));
	}






	/**
	 * Envoie le fichier au client HTTP
	 */
	public function serve(?Session $session = null): void
	{
		if (!$this->checkReadAccess($session)) {







>
>
>
>
>







337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

		if (!in_array($type, $types)) {
			throw new \InvalidArgumentException('Unknown file link type.');
		}

		return DB::getInstance()->firstColumn(sprintf('SELECT %s FROM files_links WHERE id = %d;', $type, $this->id()));
	}

	public function listLinked(): array
	{
		return EM::getInstance(File::class)->all('SELECT f.* FROM files f INNER JOIN files_links l ON l.id = f.id WHERE l.file_id = ?;', $this->id());
	}

	/**
	 * Envoie le fichier au client HTTP
	 */
	public function serve(?Session $session = null): void
	{
		if (!$this->checkReadAccess($session)) {

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

1
2
3
4

5
6
7
8
9
10
11
<?php

namespace Garradin\Entities\Web;


use Garradin\Entity;
use Garradin\UserException;
use Garradin\Entities\Files\File;

use KD2\DB\EntityManager as EM;

use const Garradin\WWW_URL;




>







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

namespace Garradin\Entities\Web;

use Garradin\DB;
use Garradin\Entity;
use Garradin\UserException;
use Garradin\Entities\Files\File;

use KD2\DB\EntityManager as EM;

use const Garradin\WWW_URL;
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

	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 .= '/';
		}

		return $url;
	}

	public function raw(): string
	{




		return $this->file()->fetch();
	}

	public function file(): File
	{
		if (null === $this->_file) {
			$this->_file = EM::findOneById(File::class, $this->id);
		}







>
>
>














>
>
>
>
|







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

	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';

	protected $_attachments;
	protected $_content;

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

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

		return $url;
	}

	public function raw(): string
	{
		if (null === $this->_content) {
			$this->_content = $this->file()->fetch();
		}

		return $this->_content;
	}

	public function file(): File
	{
		if (null === $this->_file) {
			$this->_file = EM::findOneById(File::class, $this->id);
		}
104
105
106
107
108
109
110

111
112
113
114
115
116
117
		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'])]);
		}








>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
		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) {
			$this->_content = $source['content'];
			$file->store(null, $source['content']);
		}

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

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');

	}
}







|

>
>
|
>
>

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

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

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

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

>
>
|
>


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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

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

		return $page;
	}

	public function render(array $options = []): string
	{
		$file = $this->file();
		$type = $file->type;

		// Load content
		$this->raw();

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

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

	public function getBreadcrumbs()
	{
		$sql = '
			WITH RECURSIVE parents(id, name, parent_id, level) AS (
				SELECT id, title, parent_id, 1 FROM web_pages WHERE id = ?
				UNION ALL
				SELECT p.id, p.title, p.parent_id, level + 1
				FROM web_pages p
					JOIN parents ON p.id = parents.parent_id
			)
			SELECT id, name FROM parents ORDER BY level DESC;';
		return DB::getInstance()->getAssoc($sql, $this->id());
	}

	public function listAttachments(): array
	{
		if (null === $this->_attachments) {
			$this->_attachments = $this->file()->listLinked();
		}

		return $this->_attachments;
	}

	public function findTaggedAttachments(): array
	{
		$this->raw();

		preg_match_all('/<<?(?:fichier|image)\s*(?:\|\s*)?(\d+)/', $this->_content, $match, PREG_PATTERN_ORDER);
		preg_match_all('/(?:fichier|image):\/\/(\d+)/', $this->_content, $match2, PREG_PATTERN_ORDER);

		return array_merge($match[1], $match2[1]);
	}

	/**
	 * Return list of images
	 * If $all is FALSE then this will only return images that are not present in the content
	 */
	public function getImageGallery(bool $all = true): array
	{
		return $this->getAttachmentsGallery($all, true);
	}

	/**
	 * Return list of files
	 * If $all is FALSE then this will only return files that are not present in the content
	 */
	public function getAttachmentsGallery(bool $all = true, bool $images = false): array
	{
		$out = [];

		if (!$all) {
			$tagged = $this->findTaggedAttachments();
		}

		foreach ($this->listAttachments() as $a) {
			if ($images && !$a->image) {
				continue;
			}
			elseif (!$images && $a->image) {
				continue;
			}

			// Skip
			if (!$all && in_array($a->id, $tagged)) {
				continue;
			}

			$out[] = $a;
		}

		return $out;
	}
}

Modified src/include/lib/Garradin/Fichiers.php from [a47061b5a4] to [cc9a859ad2].

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
		$used = self::listFilesUsedInText($text);

		return array_filter($files, function ($row) use ($used) {
			return !in_array($row->id, $used);
		});
	}

	/**
	 * Renvoie une liste d'ID de fichiers mentionnées dans un texte wiki
	 * @param  string $text Texte wiki
	 * @return array       Liste des IDs de fichiers mentionnés
	 */
	static public function listFilesUsedInText($text)
	{
		preg_match_all('/<<?(?:fichier|image)\s*(?:\|\s*)?(\d+)/', $text, $match, PREG_PATTERN_ORDER);
		preg_match_all('/(?:fichier|image):\/\/(\d+)/', $text, $match2, PREG_PATTERN_ORDER);

		return array_merge($match[1], $match2[1]);
	}

}







<
<
<
<
<
<
<
<
<
|
<
<
<
<
84
85
86
87
88
89
90









91




		$used = self::listFilesUsedInText($text);

		return array_filter($files, function ($row) use ($used) {
			return !in_array($row->id, $used);
		});
	}










}




Modified src/include/lib/Garradin/Web/Render/EncryptedSkriv.php from [085541e42b] to [252cf26860].

1
2
3



4
5
6
7
8
9
10
11
12
13
<?php

namespace Garradin\Files\Render;




class EncryptedSkriv
{
	static public function render(File $file, string $content): string
	{
		$tpl = Template::getInstance();
		$tpl->assign(compact('file', 'content'));
		return $tpl->fetch('common/_file_render_encrypted.tpl');
	}
}


|
>
>
>










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

namespace Garradin\Web\Render;

use Garradin\Entities\Files\File;
use Garradin\Template;

class EncryptedSkriv
{
	static public function render(File $file, string $content): string
	{
		$tpl = Template::getInstance();
		$tpl->assign(compact('file', 'content'));
		return $tpl->fetch('common/_file_render_encrypted.tpl');
	}
}

Modified src/include/lib/Garradin/Web/Render/HTML.php from [38e9516154] to [ca31cd740c].

1
2
3


4
5
6
7
8
9
10
<?php

namespace Garradin\Files\Render;



use KD2\Garbage2xhtml;

class HTML
{
	static protected $g2x;




>
>







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

namespace Garradin\Files\Render;

use Garradin\Entities\Files\File;

use KD2\Garbage2xhtml;

class HTML
{
	static protected $g2x;

Modified src/include/lib/Garradin/Web/Render/Skriv.php from [0dba465910] to [2301b08c1b].

1
2
3
4



5

6
7
8
9
10
11
12
13
14




15
16
17
18
19
20
21
<?php

namespace Garradin\Files\Render;




use Garradin\Web\Squelette_Filtres;


use KD2\SkrivLite;

class Skriv
{
	static protected $skriv;

	static public function render(File $file, string $str): string
	{




		if (!self::$skriv)
		{
			self::$skriv = new \KD2\SkrivLite;
			self::$skriv->registerExtension('fichier', [self::class, 'SkrivFichier']);
			self::$skriv->registerExtension('image', [self::class, 'SkrivImage']);

			// Enregistrer d'autres extensions éventuellement


|

>
>
>
|
>







|

>
>
>
>







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\Web\Render;

use Garradin\Entities\Files\File;

use Garradin\Squelette_Filtres;
use Garradin\Plugin;
use Garradin\Files\Files;

use KD2\SkrivLite;

class Skriv
{
	static protected $skriv;

	static public function render(?File $file, string $str, array $options = []): string
	{
		if (!isset($options['prefix'])) {
			throw new \InvalidArgumentException('Missing "prefix" option');
		}

		if (!self::$skriv)
		{
			self::$skriv = new \KD2\SkrivLite;
			self::$skriv->registerExtension('fichier', [self::class, 'SkrivFichier']);
			self::$skriv->registerExtension('image', [self::class, 'SkrivImage']);

			// Enregistrer d'autres extensions éventuellement
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
			return $file->url();
		}, $str);

		$str = self::$skriv->render($str);

		$str = Squelette_Filtres::typo_fr($str);

		$str = preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($prefix) {
			return '<a href="' . $prefix . self::transformTitleToURI($matches[1]) . '">';
		}, $str);

		return $str;
	}

	/**
	 * Callback utilisé pour l'extension <<fichier>> dans le wiki-texte
	 * @param array $args    Arguments passés à l'extension
	 * @param string $content Contenu éventuel (en mode bloc)
	 * @param object $skriv   Objet SkrivLite
	 */
	static public function SkrivFichier($args, $content, $skriv)
	{
		$id = $caption = null;

		foreach ($args as $value)
		{
			if (preg_match('/^\d+$/', $value) && !$id)
			{







|
|











|







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
			return $file->url();
		}, $str);

		$str = self::$skriv->render($str);

		$str = Squelette_Filtres::typo_fr($str);

		$str = preg_replace_callback('!<a href="([^/.:@]+)">!i', function ($matches) use ($options) {
			return sprintf('<a href="%s%s">', $options['prefix'], self::transformTitleToURI($matches[1]));
		}, $str);

		return $str;
	}

	/**
	 * Callback utilisé pour l'extension <<fichier>> dans le wiki-texte
	 * @param array $args    Arguments passés à l'extension
	 * @param string $content Contenu éventuel (en mode bloc)
	 * @param object $skriv   Objet SkrivLite
	 */
	static public function SkrivFichier(array $args, ?string $content, SkrivLite $skriv): string
	{
		$id = $caption = null;

		foreach ($args as $value)
		{
			if (preg_match('/^\d+$/', $value) && !$id)
			{
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
		}

		if (empty($id))
		{
			return $skriv->parseError('/!\ Tag fichier : aucun numéro de fichier indiqué.');
		}

		$file = Files::get((int)$match[2]);

		if (!$file) {
			return $skriv->parseError('/!\ Tag fichier invalide');
		}

		if (empty($caption))
		{







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
		}

		if (empty($id))
		{
			return $skriv->parseError('/!\ Tag fichier : aucun numéro de fichier indiqué.');
		}

		$file = Files::get((int)$id);

		if (!$file) {
			return $skriv->parseError('/!\ Tag fichier invalide');
		}

		if (empty($caption))
		{
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

	/**
	 * Callback utilisé pour l'extension <<image>> dans le wiki-texte
	 * @param array $args    Arguments passés à l'extension
	 * @param string $content Contenu éventuel (en mode bloc)
	 * @param object $skriv   Objet SkrivLite
	 */
	static public function SkrivImage($args, $content, $skriv)
	{
		static $align_values = ['droite', 'gauche', 'centre'];

		$align = '';
		$id = $caption = null;

		foreach ($args as $value)







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

	/**
	 * Callback utilisé pour l'extension <<image>> dans le wiki-texte
	 * @param array $args    Arguments passés à l'extension
	 * @param string $content Contenu éventuel (en mode bloc)
	 * @param object $skriv   Objet SkrivLite
	 */
	static public function SkrivImage(array $args, ?string $content, SkrivLite $skriv): string
	{
		static $align_values = ['droite', 'gauche', 'centre'];

		$align = '';
		$id = $caption = null;

		foreach ($args as $value)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
		}

		if (!$id)
		{
			return $skriv->parseError('/!\ Tag image : aucun numéro de fichier indiqué.');
		}

		$file = Files::get((int)$match[2]);

		if (!$file) {
			return $skriv->parseError('/!\ Tag image invalide');
		}

		if (!$file->image)
		{







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
		}

		if (!$id)
		{
			return $skriv->parseError('/!\ Tag image : aucun numéro de fichier indiqué.');
		}

		$file = Files::get((int)$id);

		if (!$file) {
			return $skriv->parseError('/!\ Tag image invalide');
		}

		if (!$file->image)
		{

Modified src/include/lib/Garradin/Wiki.php from [a3cb964340] to [9fc9e84930].

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
367
368
369
370
371
372
373

    public function countRecentModifications()
    {
        $db = DB::getInstance();
        return $db->firstColumn('SELECT COUNT(*) FROM wiki_pages WHERE '.$this->_getLectureClause().';');
    }

    public function listBackBreadCrumbs($id)
    {
        if ($id == 0)
            return [];

        $db = DB::getInstance();
        $flat = [];
        $max = 0;

        while ($id > 0 && $max++ < 10)
        {
            $res = $db->first('SELECT parent, titre, uri
                FROM wiki_pages WHERE id = ? LIMIT 1;', (int)$id);

            $flat[] = [
                'id'        =>  $id,
                'titre'     =>  $res->titre,
                'uri'       =>  $res->uri,
            ];

            if ($id == $res->parent)
            {
                throw new \Exception('Parent! ' . $id . '/' . $res->parent);
            }

            $id = (int)$res->parent;
        }

        return array_reverse($flat);
    }

    public function listBackParentTree($id)
    {
        $db = DB::getInstance();
        $flat = [
            (object) [
                'id' => 0,
                'parent' => null,







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







329
330
331
332
333
334
335































336
337
338
339
340
341
342

    public function countRecentModifications()
    {
        $db = DB::getInstance();
        return $db->firstColumn('SELECT COUNT(*) FROM wiki_pages WHERE '.$this->_getLectureClause().';');
    }
































    public function listBackParentTree($id)
    {
        $db = DB::getInstance();
        $flat = [
            (object) [
                'id' => 0,
                'parent' => null,

Modified src/templates/web/_preview.tpl from [1c9551975d] to [9200569279].

1
2
3
4
5
6
7
{include file="admin/_head.tpl" title="Wiki" current="wiki" is_popup=1 body_id="transparent"}

<div class="wikiContent">
{$contenu|raw|format_wiki|liens_wiki:'#'}
</div>

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


|



1
2
3
4
5
6
7
{include file="admin/_head.tpl" title="Web" current="web" is_popup=1 body_id="transparent"}

<div class="wikiContent">
	{$content|raw}
</div>

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

Modified src/templates/web/edit.tpl from [3ef23491dd] to [712dadaf49].

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
				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"}







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
				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->raw() 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"}

Modified src/templates/web/page.tpl from [fc2fcb0602] to [702809c847].

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
{if !empty($page.titre) && $can_read}
    {include file="admin/_head.tpl" title=$page.titre current="wiki"}
{else}
    {include file="admin/_head.tpl" title="Wiki" current="wiki"}
{/if}

<nav class="tabs">






    <ul>

        {if $session->canAccess('wiki', Membres::DROIT_ECRITURE)}
            <li><a href="{$admin_url}wiki/creer.php?parent={if $page && $config.accueil_wiki != $page.uri}{$page.id}{else}0{/if}"><strong>Créer une nouvelle page</strong></a></li>
        {/if}
        {if $can_edit}
            <li><a href="{$admin_url}wiki/editer.php?id={$page.id}">Éditer</a></li>
        {/if}
        {if $can_read && $page && $page.contenu}
            <li><a href="{$admin_url}wiki/historique.php?id={$page.id}">Historique</a></li>
            {if $page.droit_lecture == Wiki::LECTURE_PUBLIC}
                <li><a href="{$www_url}{$page.uri}{if $has_public_children}/{/if}">Voir sur le site</a></li>
            {/if}
        {/if}
        {if $can_edit && $session->canAccess('wiki', Membres::DROIT_ADMIN)}
            <li><a href="{$admin_url}wiki/supprimer.php?id={$page.id}">Supprimer</a></li>
        {/if}
    </ul>
</nav>

{if !$can_read}
    <p class="block alert">Vous n'avez pas le droit de lire cette page.</p>
{else}
    <div class="breadCrumbs">
        <ul>
            <li><a href="./">Wiki</a></li>
            {if !empty($breadcrumbs)}
            {foreach from=$breadcrumbs item="crumb"}
            <li><a href="?{$crumb.uri}">{$crumb.titre}</a></li>
            {/foreach}
            {/if}
        </ul>
    </div>


    {if !$page}
        <p class="block error">
            Cette page n'existe pas.
        </p>

        {if $can_edit}
        <form method="post" action="{$admin_url}wiki/creer.php">
            <p class="submit">
                {csrf_field key="wiki_create"}
                <input type="hidden" name="titre" value="{$uri}" />
                {button type="submit" name="create" label="Créer cette page" shape="right" class="main"}
            </p>
        </form>
        {/if}
    {else}

        {if !empty($children)}
        <div class="wikiChildren">
            <h4>Dans cette rubrique</h4>
            <ul>
            {foreach from=$children item="child"}
                <li><a href="?{$child.uri}">{$child.titre}</a></li>
            {/foreach}
            </ul>
        </div>
        {/if}

        {if !$page.contenu}
            <p class="block alert">Cette page est vide, cliquez sur « Éditer » pour la modifier.</p>
        {else}

            {if $page.contenu.chiffrement}
                <noscript>
                    <div class="error">
                        Vous dever activer javascript pour pouvoir déchiffrer cette page.
                    </div>
                </noscript>
                <script type="text/javascript" src="{$admin_url}static/scripts/wiki-encryption.js"></script>
                <div id="wikiEncryptedMessage">
                    <p class="block alert">Cette page est chiffrée.
                        <input type="button" onclick="return wikiDecrypt(false);" value="Entrer le mot de passe" />
                    </p>
                </div>
                <div class="wikiContent" style="display: none;" id="wikiEncryptedContent">
                    {$page.contenu.contenu}
                </div>
            {else}
                <div class="wikiContent">
                    {$page.contenu.contenu|raw|format_wiki|liens_wiki:'?'}
                </div>
            {/if}


            {if !empty($images) || !empty($fichiers)}
            <div class="wikiFiles">
                <h3>Fichiers liés à cette page</h3>

                {if !empty($images)}
                <ul class="gallery">
                    {foreach from=$images item="file"}
                        <li>
                            <figure>
                                <a class="internal-image" href="{$file.url}"><img src="{$file.thumb}" alt="" title="{$file.nom}" /></a>
                            </figure>
                        </li>
                    {/foreach}
                </ul>
                {/if}

                {if !empty($fichiers)}
                <ul class="files">
                    {foreach from=$fichiers item="file"}
                        <li>
                            <aside class="fichier" class="internal-file"><a href="{$file.url}">{$file.nom}</a>
                            <small>({$file.type}, {$file.taille|format_bytes})</small></aside>
                       </li>
                    {/foreach}
                </ul>
                {/if}
            </div>
            {/if}

            <p class="wikiFooter">
                Dernière modification le {$page.date_modification|date_long}
                {if $session->canAccess('membres', Membres::DROIT_ACCES)}
                par <a href="{$admin_url}membres/fiche.php?id={$page.contenu.id_auteur}">{$auteur}</a>
                {/if}
            </p>
        {/if}
    {/if}
{/if}


{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

102
103
104
105

{include file="admin/_head.tpl" title=$page.title current="web"}




<nav class="tabs">
	{if $page.type == $page::TYPE_CATEGORY}
	<aside>
		{linkbutton shape="plus" label="Nouvelle page" href="new.php?type=%d&parent=%d"|args:$type_page,$parent}
		{linkbutton shape="plus" label="Nouvelle catégorie" href="new.php?type=%d&parent=%d"|args:$type_category,$parent}
	</aside>
	{/if}
	<ul>
		<li><a href="{$admin_url}web/?parent={$page.parent_id}">Retour à la liste</a></li>
		{if $session->canAccess($session::SECTION_WEB, Membres::DROIT_ECRITURE)}



			<li><a href="{$admin_url}web/edit.php?id={$page.id}">Modifier</a></li>
		{/if}


		{if $page.status == $page::STATUS_ONLINE}
			<li><a href="{$page->url()}">Voir sur le site</a></li>
		{/if}

		{if $session->canAccess($session::SECTION_WEB, Membres::DROIT_ADMIN)}
			<li><a href="{$admin_url}web/delete.php?id={$page.id}">Supprimer</a></li>
		{/if}
	</ul>
</nav>

{if !empty($breadcrumbs)}


<div class="breadCrumbs">
	<ul>


		{foreach from=$breadcrumbs key="id" item="title"}
			<li><a href="?id={$id}">{$title}</a></li>
		{/foreach}

	</ul>
</div>
{/if}

{if !$page}
	<p class="block error">
		Cette page n'existe pas.
	</p>

	{if $can_edit}
	<form method="post" action="{$admin_url}wiki/creer.php">
		<p class="submit">
			{csrf_field key="wiki_create"}
			<input type="hidden" name="titre" value="{$uri}" />
			{button type="submit" name="create" label="Créer cette page" shape="right" class="main"}
		</p>
	</form>
	{/if}
{else}

	{if !empty($children)}
	<div class="wikiChildren">
		<h4>Dans cette rubrique</h4>
		<ul>
		{foreach from=$children item="child"}
			<li><a href="?{$child.uri}">{$child.titre}</a></li>
		{/foreach}
		</ul>
	</div>
	{/if}

	{if !$content}
		<p class="block alert">Cette page est vide, cliquez sur « Éditer » pour la modifier.</p>
	{else}

















		<div class="wikiContent">
			{$content|raw}
		</div>



		{if !empty($images) || !empty($files)}
		<div class="wikiFiles">
			<h3>Fichiers liés à cette page</h3>

			{if !empty($images)}
			<ul class="gallery">
				{foreach from=$images item="file"}
					<li>
						<figure>
							<a class="internal-image" href="{$file.url}"><img src="{$file.thumb}" alt="" title="{$file.nom}" /></a>
						</figure>
					</li>
				{/foreach}
			</ul>
			{/if}

			{if !empty($files)}
			<ul class="files">
				{foreach from=$files item="file"}
					<li>
						<aside class="fichier" class="internal-file"><a href="{$file.url}">{$file.nom}</a>
						<small>({$file.type}, {$file.taille|format_bytes})</small></aside>
				   </li>
				{/foreach}
			</ul>
			{/if}
		</div>
		{/if}

		<p class="wikiFooter">
			Dernière modification le {$page.modified|date_long}

			par {$auteur}

		</p>
	{/if}

{/if}


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

Modified src/www/admin/static/scripts/wiki_editor.js from [888ea259ae] to [f642c2e0f6].

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
			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)
				{







|









|




|





|

|












|

|

|







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
			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 + 'web/_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 + 'web/_syntaxe.html');
			};

			var openFileInsert = function ()
			{
				openIFrame(g.admin_url + 'web/_attach.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)
				{
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
				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');







|
|
|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
				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');

Modified src/www/admin/web/_preview.php from [d803765203] to [ddb1e2954c].

1
2
3


4
5
6
7
8
9
10
11
<?php

namespace Garradin;



require_once __DIR__ . '/_inc.php';

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

$tpl->assign('contenu', f('contenu'));

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



>
>



|

|

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

namespace Garradin;

use Garradin\Web\Render\Skriv;

require_once __DIR__ . '/_inc.php';

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

$tpl->assign('content', Skriv::render(null, (string) f('content'), ['prefix' => '#']));

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

Modified src/www/admin/web/page.php from [373b4cc240] to [1ab49d03a5].

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
<?php

namespace Garradin;




require_once __DIR__ . '/_inc.php';

if (!empty($_SERVER['QUERY_STRING']))
{
    $page_uri = Wiki::transformTitleToURI(rawurldecode($_SERVER['QUERY_STRING']));
    $page = $wiki->getByURI($page_uri);
}
else
{
    $page = $wiki->getByURI($config->get('accueil_wiki'));
    $page_uri = '';
}

if (!$page)
{
    $tpl->assign('uri', $page_uri);
    $tpl->assign('can_edit', false);
    $tpl->assign('can_read', true);

}
else
{
    $membres = new Membres;
    $tpl->assign('can_read', $wiki->canReadPage($page->droit_lecture));
    $tpl->assign('can_edit', $wiki->canWritePage($page->droit_ecriture));
    $tpl->assign('children', $wiki->getList($page_uri == '' ? 0 : $page->id, true));
    $tpl->assign('has_public_children', $wiki->hasChildren($page_uri == '' ? 0 : $page->id, true));
    $tpl->assign('breadcrumbs', $wiki->listBackBreadCrumbs($page->id));
    $tpl->assign('auteur', $page->contenu ? $membres->getNom($page->contenu->id_auteur) : null);

    $images = Fichiers::listLinkedFiles(Fichiers::LIEN_WIKI, $page->id, true);

    if ($images && !empty($page->contenu->chiffrement))
    {
        $images = Fichiers::filterFilesUsedInText($images, $page->contenu->contenu);
    }

    $fichiers = Fichiers::listLinkedFiles(Fichiers::LIEN_WIKI, $page->id, false);

    if ($fichiers && !empty($page->contenu->chiffrement))
    {
        $fichiers = Fichiers::filterFilesUsedInText($fichiers, $page->contenu->contenu);
    }

    $tpl->assign('images', $images);
    $tpl->assign('fichiers', $fichiers);
}

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

$tpl->assign('custom_js', ['wiki_gallery.js']);

$tpl->display('admin/wiki/page.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
<?php

namespace Garradin;

use Garradin\Web;
use Garradin\Entities\Web\Page;

require_once __DIR__ . '/_inc.php';

if ($uri = qg('uri'))
{
	$page_uri = Wiki::transformTitleToURI($uri);
	$page = Web::getByURI($page_uri);
}
else
{

	$page = Web::get((int) qg('id'));
}



if (!$page) {


	throw new UserException('Page inconnue');
}


$membres = new Membres;




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

$tpl->assign('auteur', $page->file()->author_id ? $membres->getNom($page->file()->author_id) : null);






$images = $page->getImageGallery(false);

$files = $page->getAttachmentsGallery(false);




$content = $page->render(['prefix' => ADMIN_URL . 'web/page.php?uri=']);



$tpl->assign(compact('page', 'images', 'files', 'content'));


$tpl->assign('custom_js', ['wiki_gallery.js']);

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