summaryrefslogtreecommitdiff
path: root/platform/www
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www')
-rw-r--r--platform/www/conf/local.php15
-rw-r--r--platform/www/conf/local.php.bak.php16
-rw-r--r--platform/www/conf/plugins.local.php.bak9
-rw-r--r--platform/www/data/media/en/docs/markdown_headers.jpgbin0 -> 33832 bytes
-rw-r--r--platform/www/data/media_meta/en/docs/markdown_headers.jpg.changes1
-rw-r--r--platform/www/data/meta/de/index.changes1
-rw-r--r--platform/www/data/meta/de/index.indexed1
-rw-r--r--platform/www/data/meta/de/index.meta7
-rw-r--r--platform/www/data/meta/en/blog/2021-11-01-the_origins.indexed1
-rw-r--r--platform/www/data/meta/en/blog/2021-11-01-the_origins.meta3
-rw-r--r--platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed1
-rw-r--r--platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta3
-rw-r--r--platform/www/data/meta/en/blog/2022-10-01-xxx.meta3
-rw-r--r--platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.indexed1
-rw-r--r--platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.meta3
-rw-r--r--platform/www/data/meta/en/blog/2024-03-04-starting_regular_updates.meta3
-rw-r--r--platform/www/data/meta/en/blog/2024-03-05-apr_01.indexed1
-rw-r--r--platform/www/data/meta/en/blog/2024-03-05-apr_01.meta11
-rw-r--r--platform/www/data/meta/en/blog/index.changes4
-rw-r--r--platform/www/data/meta/en/blog/index.meta1
-rw-r--r--platform/www/data/meta/en/docs/index.changes4
-rw-r--r--platform/www/data/meta/en/docs/index.indexed1
-rw-r--r--platform/www/data/meta/en/docs/index.meta14
-rw-r--r--platform/www/data/meta/en/docs/text_format.changes19
-rw-r--r--platform/www/data/meta/en/docs/text_format.indexed1
-rw-r--r--platform/www/data/meta/en/docs/text_format.meta14
-rw-r--r--platform/www/data/meta/en/index.changes43
-rw-r--r--platform/www/data/meta/en/index.indexed2
-rw-r--r--platform/www/data/meta/en/index.meta6
-rw-r--r--platform/www/data/meta/en/tech.changes22
-rw-r--r--platform/www/data/meta/en/tech.indexed1
-rw-r--r--platform/www/data/meta/en/tech.meta12
-rw-r--r--platform/www/data/meta/es/blog/2021-11-01-the_origins.changes2
-rw-r--r--platform/www/data/meta/es/blog/2021-11-01-the_origins.indexed1
-rw-r--r--platform/www/data/meta/es/blog/2021-11-01-the_origins.meta3
-rw-r--r--platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.changes1
-rw-r--r--platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed1
-rw-r--r--platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta3
-rw-r--r--platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.indexed1
-rw-r--r--platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.meta3
-rw-r--r--platform/www/data/meta/es/blog/2024-03-05-apr_01.indexed1
-rw-r--r--platform/www/data/meta/es/blog/2024-03-05-apr_01.meta7
-rw-r--r--platform/www/data/meta/es/index.changes1
-rw-r--r--platform/www/data/meta/es/index.indexed1
-rw-r--r--platform/www/data/meta/es/index.meta5
-rw-r--r--platform/www/data/meta/fr/index.changes1
-rw-r--r--platform/www/data/meta/fr/index.indexed1
-rw-r--r--platform/www/data/meta/fr/index.meta5
-rw-r--r--platform/www/data/meta/it/index.changes1
-rw-r--r--platform/www/data/meta/it/index.indexed1
-rw-r--r--platform/www/data/meta/it/index.meta5
-rw-r--r--platform/www/data/meta/macros/macros.ser2
-rw-r--r--platform/www/data/meta/pt/index.changes1
-rw-r--r--platform/www/data/meta/pt/index.indexed1
-rw-r--r--platform/www/data/meta/pt/index.meta5
-rw-r--r--platform/www/data/pages/de/index.txt28
-rw-r--r--platform/www/data/pages/en/blog/2021-11-01-the_origins.txt15
-rw-r--r--platform/www/data/pages/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt18
-rw-r--r--platform/www/data/pages/en/blog/2024-03-04-starting_acervus_progress_reports.txt17
-rw-r--r--platform/www/data/pages/en/blog/2024-03-05-apr_01.txt39
-rw-r--r--platform/www/data/pages/en/blog/2024-03-20-apr_02.txt34
-rw-r--r--platform/www/data/pages/en/blog/2024-04-05-apr_03.md30
-rw-r--r--platform/www/data/pages/en/blog/2024-04-20-apr_04.md31
-rw-r--r--platform/www/data/pages/en/docs/index.txt57
-rw-r--r--platform/www/data/pages/en/docs/text_format.txt199
-rw-r--r--platform/www/data/pages/en/index.txt18
-rw-r--r--platform/www/data/pages/es/blog/2021-11-01-the_origins.txt15
-rw-r--r--platform/www/data/pages/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt18
-rw-r--r--platform/www/data/pages/es/blog/2024-03-04-starting_acervus_progress_reports.txt17
-rw-r--r--platform/www/data/pages/es/blog/2024-03-05-apr_01.txt39
-rw-r--r--platform/www/data/pages/es/blog/2024-03-20-apr_02.md34
-rw-r--r--platform/www/data/pages/es/blog/2024-04-05-apr_03.md30
-rw-r--r--platform/www/data/pages/es/blog/2024-04-20-apr_04.md31
-rw-r--r--platform/www/data/pages/es/index.txt28
-rw-r--r--platform/www/data/pages/fr/index.txt28
-rw-r--r--platform/www/data/pages/it/index.txt28
-rw-r--r--platform/www/data/pages/pt/index.txt28
-rw-r--r--platform/www/lib/plugins/blog/action.php4
-rw-r--r--platform/www/lib/plugins/blog/helper.php2
-rw-r--r--platform/www/lib/plugins/blog/lang/ca/lang.php30
-rw-r--r--platform/www/lib/plugins/blog/lang/ca/settings.php27
-rw-r--r--platform/www/lib/plugins/blog/lang/es/lang.php6
-rw-r--r--platform/www/lib/plugins/blog/lang/es/settings.php10
-rw-r--r--platform/www/lib/plugins/blog/lang/pt-br/lang.php2
-rw-r--r--platform/www/lib/plugins/blog/lang/vi/lang.php30
-rw-r--r--platform/www/lib/plugins/blog/lang/vi/settings.php27
-rw-r--r--platform/www/lib/plugins/blog/manager.dat2
-rw-r--r--platform/www/lib/plugins/blog/plugin.info.txt2
-rw-r--r--platform/www/lib/plugins/blog/syntax/blog.php26
-rw-r--r--platform/www/lib/plugins/include/.github/workflows/phpTestLinux.yml52
-rw-r--r--platform/www/lib/plugins/include/COPYING340
-rw-r--r--platform/www/lib/plugins/include/README11
-rw-r--r--platform/www/lib/plugins/include/_test/locallink_conversion.test.php42
-rw-r--r--platform/www/lib/plugins/include/_test/media_linktitle_conversion.test.php54
-rw-r--r--platform/www/lib/plugins/include/_test/namespace_includes.test.php182
-rw-r--r--platform/www/lib/plugins/include/_test/nested_include.test.php75
-rw-r--r--platform/www/lib/plugins/include/_test/pagemove_support.test.php76
-rw-r--r--platform/www/lib/plugins/include/_test/safeindex.test.php40
-rw-r--r--platform/www/lib/plugins/include/action.php370
-rw-r--r--platform/www/lib/plugins/include/conf/default.php30
-rw-r--r--platform/www/lib/plugins/include/conf/metadata.php33
-rw-r--r--platform/www/lib/plugins/include/deleted.files13
-rw-r--r--platform/www/lib/plugins/include/helper.php941
-rw-r--r--platform/www/lib/plugins/include/images/comment.gifbin0 -> 111 bytes
-rw-r--r--platform/www/lib/plugins/include/images/date.gifbin0 -> 123 bytes
-rw-r--r--platform/www/lib/plugins/include/images/link.gifbin0 -> 125 bytes
-rw-r--r--platform/www/lib/plugins/include/images/user.gifbin0 -> 116 bytes
-rw-r--r--platform/www/lib/plugins/include/lang/ar/lang.php12
-rw-r--r--platform/www/lib/plugins/include/lang/ar/settings.php20
-rw-r--r--platform/www/lib/plugins/include/lang/cs/lang.php10
-rw-r--r--platform/www/lib/plugins/include/lang/cs/settings.php41
-rw-r--r--platform/www/lib/plugins/include/lang/da/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/da/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/de-informal/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/de-informal/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/de/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/de/settings.php42
-rw-r--r--platform/www/lib/plugins/include/lang/en/lang.php12
-rw-r--r--platform/www/lib/plugins/include/lang/en/settings.php41
-rw-r--r--platform/www/lib/plugins/include/lang/eo/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/eo/settings.php38
-rw-r--r--platform/www/lib/plugins/include/lang/es/lang.php12
-rw-r--r--platform/www/lib/plugins/include/lang/es/settings.php41
-rw-r--r--platform/www/lib/plugins/include/lang/fr/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/fr/settings.php44
-rw-r--r--platform/www/lib/plugins/include/lang/hr/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/hr/settings.php38
-rw-r--r--platform/www/lib/plugins/include/lang/hu/lang.php9
-rw-r--r--platform/www/lib/plugins/include/lang/hu/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/it/lang.php10
-rw-r--r--platform/www/lib/plugins/include/lang/it/settings.php29
-rw-r--r--platform/www/lib/plugins/include/lang/ja/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/ja/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/ko/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/ko/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/nl/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/nl/settings.php40
-rw-r--r--platform/www/lib/plugins/include/lang/pl/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/pl/settings.php13
-rw-r--r--platform/www/lib/plugins/include/lang/pt-br/lang.php12
-rw-r--r--platform/www/lib/plugins/include/lang/pt-br/settings.php14
-rw-r--r--platform/www/lib/plugins/include/lang/pt/lang.php13
-rw-r--r--platform/www/lib/plugins/include/lang/ru/lang.php10
-rw-r--r--platform/www/lib/plugins/include/lang/ru/settings.php42
-rw-r--r--platform/www/lib/plugins/include/lang/sk/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/sk/settings.php37
-rw-r--r--platform/www/lib/plugins/include/lang/sl/lang.php12
-rw-r--r--platform/www/lib/plugins/include/lang/sl/settings.php16
-rw-r--r--platform/www/lib/plugins/include/lang/sv/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/sv/settings.php39
-rw-r--r--platform/www/lib/plugins/include/lang/tr/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/tr/settings.php36
-rw-r--r--platform/www/lib/plugins/include/lang/vi/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/vi/settings.php38
-rw-r--r--platform/www/lib/plugins/include/lang/zh/lang.php8
-rw-r--r--platform/www/lib/plugins/include/lang/zh/settings.php33
-rw-r--r--platform/www/lib/plugins/include/plugin.info.txt7
-rw-r--r--platform/www/lib/plugins/include/requirements.txt2
-rw-r--r--platform/www/lib/plugins/include/script.js22
-rw-r--r--platform/www/lib/plugins/include/style.css53
-rw-r--r--platform/www/lib/plugins/include/syntax/closelastsecedit.php36
-rw-r--r--platform/www/lib/plugins/include/syntax/editbtn.php43
-rw-r--r--platform/www/lib/plugins/include/syntax/footer.php133
-rw-r--r--platform/www/lib/plugins/include/syntax/header.php95
-rw-r--r--platform/www/lib/plugins/include/syntax/include.php173
-rw-r--r--platform/www/lib/plugins/include/syntax/locallink.php45
-rw-r--r--platform/www/lib/plugins/include/syntax/readmore.php43
-rw-r--r--platform/www/lib/plugins/include/syntax/sorttag.php60
-rw-r--r--platform/www/lib/plugins/include/syntax/wrap.php78
-rw-r--r--platform/www/lib/plugins/meta/_test/rendering.test.php80
-rw-r--r--platform/www/lib/plugins/meta/plugin.info.txt7
-rw-r--r--platform/www/lib/plugins/meta/syntax.php205
-rw-r--r--platform/www/lib/plugins/refnotes/action.php634
-rw-r--r--platform/www/lib/plugins/refnotes/admin.css100
-rw-r--r--platform/www/lib/plugins/refnotes/admin.js1035
-rw-r--r--platform/www/lib/plugins/refnotes/admin.php751
-rw-r--r--platform/www/lib/plugins/refnotes/admin.svg1
-rw-r--r--platform/www/lib/plugins/refnotes/bibtex.php669
-rw-r--r--platform/www/lib/plugins/refnotes/conf/namespaces.dat1
-rw-r--r--platform/www/lib/plugins/refnotes/conf/notes.dat1
-rw-r--r--platform/www/lib/plugins/refnotes/config.php77
-rw-r--r--platform/www/lib/plugins/refnotes/core.php483
-rw-r--r--platform/www/lib/plugins/refnotes/database.php563
-rw-r--r--platform/www/lib/plugins/refnotes/instructions.php318
-rw-r--r--platform/www/lib/plugins/refnotes/lang/en/__template.txt82
-rw-r--r--platform/www/lib/plugins/refnotes/lang/en/intro.txt15
-rw-r--r--platform/www/lib/plugins/refnotes/lang/en/lang.php146
-rw-r--r--platform/www/lib/plugins/refnotes/locale.php92
-rw-r--r--platform/www/lib/plugins/refnotes/namespace.php463
-rw-r--r--platform/www/lib/plugins/refnotes/note.php336
-rw-r--r--platform/www/lib/plugins/refnotes/plugin.info.txt7
-rw-r--r--platform/www/lib/plugins/refnotes/reference.php192
-rw-r--r--platform/www/lib/plugins/refnotes/refnote.php51
-rw-r--r--platform/www/lib/plugins/refnotes/rendering.php1272
-rw-r--r--platform/www/lib/plugins/refnotes/scope.php190
-rw-r--r--platform/www/lib/plugins/refnotes/script.js114
-rw-r--r--platform/www/lib/plugins/refnotes/style.css48
-rw-r--r--platform/www/lib/plugins/refnotes/syntax/notes.php221
-rw-r--r--platform/www/lib/plugins/refnotes/syntax/references.php348
-rw-r--r--platform/www/lib/tpl/acervus/css/basic.less2
-rw-r--r--platform/www/lib/tpl/acervus/css/hacks.css26
-rw-r--r--platform/www/lib/tpl/acervus/images/apple-touch-icon.pngbin23590 -> 38040 bytes
-rw-r--r--platform/www/lib/tpl/acervus/images/favicon.icobin371 -> 1150 bytes
-rw-r--r--platform/www/lib/tpl/acervus/images/logo.pngbin0 -> 1299837 bytes
-rw-r--r--platform/www/lib/tpl/acervus/main.php17
205 files changed, 13858 insertions, 34 deletions
diff --git a/platform/www/conf/local.php b/platform/www/conf/local.php
index 976def9..6b074ca 100644
--- a/platform/www/conf/local.php
+++ b/platform/www/conf/local.php
@@ -3,10 +3,10 @@
* Dokuwiki's Main Configuration File - Local Settings
* Auto-generated by config plugin
* Run for user: admin
- * Date: Sat, 12 Mar 2022 20:10:08 +0000
+ * Date: Mon, 26 Jun 2023 12:02:54 -0300
*/
-$conf['title'] = 'The Acervus Project';
+$conf['title'] = 'Acervus';
$conf['start'] = 'index';
$conf['template'] = 'acervus';
$conf['license'] = '';
@@ -18,9 +18,18 @@ $conf['disableactions'] = 'register';
$conf['htmlok'] = 1;
$conf['target']['extern'] = '_blank';
$conf['mailfrom'] = 'info@acerv.us';
+$conf['updatecheck'] = 0;
$conf['userewrite'] = '1';
$conf['plugin']['authldap']['attributes'] = array();
+$conf['plugin']['blog']['formposition'] = 'none';
+$conf['plugin']['include']['showfooter'] = 0;
+$conf['plugin']['include']['showdate'] = 0;
+$conf['plugin']['include']['showuser'] = 0;
+$conf['plugin']['include']['showcomments'] = 0;
+$conf['plugin']['include']['showlinkbacks'] = 0;
+$conf['plugin']['include']['showtags'] = 0;
$conf['plugin']['pageredirect']['show_note'] = 0;
+#$conf['plugin']['translation']['translations'] = 'en es de fr it pt';
$conf['plugin']['translation']['translations'] = 'en es';
$conf['plugin']['translation']['display'] = 'langcode,name';
$conf['plugin']['translation']['translateui'] = 1;
@@ -29,4 +38,6 @@ $conf['plugin']['translation']['copytrans'] = 1;
$conf['tpl']['acervus']['numberedHeading'] = 1;
$conf['tpl']['acervus']['tocPosition'] = 'dokuwiki';
$conf['tpl']['acervus']['footer'] = 'footer';
+$conf['plugin']['mdpage']['flavor'] = 'markdown-extra';
+$conf['plugin']['mdpage']['markdown_default'] = '1';
$conf['plugin']['fastwiki']['save'] = '1';
diff --git a/platform/www/conf/local.php.bak.php b/platform/www/conf/local.php.bak.php
index d4bc65f..02d9b84 100644
--- a/platform/www/conf/local.php.bak.php
+++ b/platform/www/conf/local.php.bak.php
@@ -3,7 +3,7 @@
* Dokuwiki's Main Configuration File - Local Settings
* Auto-generated by config plugin
* Run for user: admin
- * Date: Mon, 07 Mar 2022 01:33:50 +0000
+ * Date: Wed, 14 Jun 2023 14:32:18 -0300
*/
$conf['title'] = 'The Acervus Project';
@@ -16,9 +16,18 @@ $conf['useacl'] = 1;
$conf['superuser'] = 'admin';
$conf['disableactions'] = 'register';
$conf['htmlok'] = 1;
+$conf['target']['extern'] = '_blank';
+$conf['mailfrom'] = 'info@acerv.us';
+$conf['updatecheck'] = 0;
$conf['userewrite'] = '1';
$conf['plugin']['authldap']['attributes'] = array();
-$conf['plugin']['fastwiki']['save'] = 1;
+$conf['plugin']['include']['showfooter'] = 0;
+$conf['plugin']['include']['showdate'] = 0;
+$conf['plugin']['include']['showuser'] = 0;
+$conf['plugin']['include']['showcomments'] = 0;
+$conf['plugin']['include']['showlinkbacks'] = 0;
+$conf['plugin']['include']['showtags'] = 0;
+$conf['plugin']['pageredirect']['show_note'] = 0;
$conf['plugin']['translation']['translations'] = 'en es';
$conf['plugin']['translation']['display'] = 'langcode,name';
$conf['plugin']['translation']['translateui'] = 1;
@@ -27,3 +36,6 @@ $conf['plugin']['translation']['copytrans'] = 1;
$conf['tpl']['acervus']['numberedHeading'] = 1;
$conf['tpl']['acervus']['tocPosition'] = 'dokuwiki';
$conf['tpl']['acervus']['footer'] = 'footer';
+$conf['plugin']['mdpage']['flavor'] = 'markdown-extra';
+$conf['plugin']['mdpage']['markdown_default'] = '1';
+$conf['plugin']['fastwiki']['save'] = '1';
diff --git a/platform/www/conf/plugins.local.php.bak b/platform/www/conf/plugins.local.php.bak
new file mode 100644
index 0000000..fe50358
--- /dev/null
+++ b/platform/www/conf/plugins.local.php.bak
@@ -0,0 +1,9 @@
+<?php
+/*
+ * Local plugin enable/disable settings
+ * Auto-generated through plugin/extension manager
+ *
+ * NOTE: Plugins will not be added to this file unless there is a need to override a default setting. Plugins are
+ * enabled by default.
+ */
+$plugins['blog'] = 0;
diff --git a/platform/www/data/media/en/docs/markdown_headers.jpg b/platform/www/data/media/en/docs/markdown_headers.jpg
new file mode 100644
index 0000000..16b89e1
--- /dev/null
+++ b/platform/www/data/media/en/docs/markdown_headers.jpg
Binary files differ
diff --git a/platform/www/data/media_meta/en/docs/markdown_headers.jpg.changes b/platform/www/data/media_meta/en/docs/markdown_headers.jpg.changes
new file mode 100644
index 0000000..4bb7c11
--- /dev/null
+++ b/platform/www/data/media_meta/en/docs/markdown_headers.jpg.changes
@@ -0,0 +1 @@
+1707259176 192.168.56.1 C en:docs:markdown_headers.jpg admin created 33832
diff --git a/platform/www/data/meta/de/index.changes b/platform/www/data/meta/de/index.changes
new file mode 100644
index 0000000..68b7396
--- /dev/null
+++ b/platform/www/data/meta/de/index.changes
@@ -0,0 +1 @@
+1687791829 192.168.56.1 C de:index admin created 1919
diff --git a/platform/www/data/meta/de/index.indexed b/platform/www/data/meta/de/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/de/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/de/index.meta b/platform/www/data/meta/de/index.meta
new file mode 100644
index 0000000..c9b5a7b
--- /dev/null
+++ b/platform/www/data/meta/de/index.meta
@@ -0,0 +1,7 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1687791829;s:8:"modified";i:1687791829;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791829;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"de:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1919;}s:5:"title";s:19:"Das Acervus-Projekt";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:19:"das_acervus-projekt";s:5:"title";s:19:"Das Acervus-Projekt";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"updates";s:5:"title";s:7:"Updates";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:504:"~
+
+Das Acervus-Projekt
+
+Eine kollektive Wiederherstellung der Werke von Denkern und Aktivisten, die aus der Konvivialitätskonstellation um Ivan Illich hervorgegangen sind
+
+Die Initiative verfolgt ein doppeltes Ziel: einen Beitrag zum Verständnis der kritischen gegenwärtigen Situation und zur Analyse und Debatte der bestehenden Optionen zu leisten, basierend auf den Beiträgen des Kreises um Ivan Illich, und eine vollständige digitale Bibliothek seines Werks mit allgemeinem Zugang zu schaffen.…";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1687791829;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791829;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"de:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1919;}}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2021-11-01-the_origins.indexed b/platform/www/data/meta/en/blog/2021-11-01-the_origins.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2021-11-01-the_origins.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2021-11-01-the_origins.meta b/platform/www/data/meta/en/blog/2021-11-01-the_origins.meta
new file mode 100644
index 0000000..386d173
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2021-11-01-the_origins.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1635735600;s:8:"modified";i:1687790957;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:34:"The origins of the Acervus Project";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:34:"the_origins_of_the_acervus_project";s:5:"title";s:34:"The origins of the Acervus Project";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:507:"The origins of the Acervus Project
+
+In early 2020, we began to envision the need for an intergenerational effort to recover the work of Ivan Illich. We thought of “recovering” in a broad sense of the term, not only giving access, but also making intelligible and facilitating the navigation through the complex layers of his thought. Together with Gustavo Esteva and Franco Augusto, we began to outline the idea of providing open access, non-commercial and collaborative access to all of Ivan's work,…";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1687467078;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed b/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta b/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta
new file mode 100644
index 0000000..c41ac45
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1644375600;s:8:"modified";i:1709629601;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:104:"Centro Intercultural de Documentación de Cuernava (CIDOC): Recovering its past to transform our present";s:11:"description";a:2:{s:15:"tableofcontents";a:3:{i:0;a:4:{s:3:"hid";s:99:"centro_intercultural_de_documentacion_de_cuernava_cidocrecovering_its_past_to_transform_our_present";s:5:"title";s:104:"Centro Intercultural de Documentación de Cuernava (CIDOC): Recovering its past to transform our present";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:7:"details";s:5:"title";s:7:"Details";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:401:"Centro Intercultural de Documentación de Cuernava (CIDOC): Recovering its past to transform our present
+
+In this first public activity we will present the initiative to recover the history, intellectual production and textual, visual and oral memory of the Intercultural Center of Cuernavaca (CIDOC), which existed in the years 1966 and 1976 in Mexico. This mythical institution operated as a sort of";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1693346192;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2022-10-01-xxx.meta b/platform/www/data/meta/en/blog/2022-10-01-xxx.meta
new file mode 100644
index 0000000..67da07c
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2022-10-01-xxx.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1664593200;s:8:"modified";i:1686764546;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:19:"Title of blog entry";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:19:"title_of_blog_entry";s:5:"title";s:19:"Title of blog entry";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:12:"more_details";s:5:"title";s:12:"More details";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:266:"Title of blog entry
+
+Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem Lorem";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1687371597;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.indexed b/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.meta b/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.meta
new file mode 100644
index 0000000..61f2f30
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2024-03-04-starting_acervus_progress_reports.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1709521200;s:8:"modified";i:1709629433;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:40:"We started the Acervus Progress Reports!";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:39:"we_started_the_acervus_progress_reports";s:5:"title";s:40:"We started the Acervus Progress Reports!";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:279:"We started the Acervus Progress Reports!
+
+With the intention of generating a more fluid communication with the collaborators and beneficiaries of the Project, we have decided to start publishing regular reports summarizing the progress in the different work areas of the project.";}s:8:"relation";a:2:{s:10:"references";a:1:{s:25:"en:blog:2024-03-05-apr_01";b:1;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1709626419;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2024-03-04-starting_regular_updates.meta b/platform/www/data/meta/en/blog/2024-03-04-starting_regular_updates.meta
new file mode 100644
index 0000000..4ff2cdb
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2024-03-04-starting_regular_updates.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1710039600;s:8:"modified";i:1709626235;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:35:"Comenzamos los reportes de progreso";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:35:"comenzamos_los_reportes_de_progreso";s:5:"title";s:35:"Comenzamos los reportes de progreso";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:275:"Comenzamos los reportes de progreso
+
+Con la intención de generar una comunicación mas fluida con los colaboradores y beneficiarios del Proyecto, hemos decidido empezar a publicar reportes regulares que resuman los progresos en las diferentes áreas de trabajo del proyecto.";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1709626111;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2024-03-05-apr_01.indexed b/platform/www/data/meta/en/blog/2024-03-05-apr_01.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2024-03-05-apr_01.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/2024-03-05-apr_01.meta b/platform/www/data/meta/en/blog/2024-03-05-apr_01.meta
new file mode 100644
index 0000000..ef1ffa6
--- /dev/null
+++ b/platform/www/data/meta/en/blog/2024-03-05-apr_01.meta
@@ -0,0 +1,11 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1709607600;s:8:"modified";i:1709629118;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:27:"Acervus Progress Report #01";s:11:"description";a:2:{s:15:"tableofcontents";a:5:{i:0;a:4:{s:3:"hid";s:26:"acervus_progress_report_01";s:5:"title";s:27:"Acervus Progress Report #01";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:14:"illich_acervus";s:5:"title";s:14:"Illich Acervus";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:8:"articles";s:5:"title";s:8:"Articles";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:3;a:4:{s:3:"hid";s:10:"interviews";s:5:"title";s:10:"Interviews";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:4;a:4:{s:3:"hid";s:12:"audiovisuals";s:5:"title";s:12:"Audiovisuals";s:4:"type";s:2:"ul";s:5:"level";i:3;}}s:8:"abstract";s:329:"Acervus Progress Report #01
+
+This report covers the updates that took place during the last two weeks (2024-02-20 to 2024-03-05).
+
+Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+Articles
+
+ * 1958 - The End of Human Life: an interpretation of Death as the Supreme Form of Prayer";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1709626504;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/blog/index.changes b/platform/www/data/meta/en/blog/index.changes
new file mode 100644
index 0000000..e6f16a7
--- /dev/null
+++ b/platform/www/data/meta/en/blog/index.changes
@@ -0,0 +1,4 @@
+1693346819 192.168.56.1 C en:blog:index admin created 40
+1693346848 192.168.56.1 E en:blog:index admin 0
+1693346860 192.168.56.1 E en:blog:index admin 0
+1693346887 192.168.56.1 D en:blog:index admin removed -40
diff --git a/platform/www/data/meta/en/blog/index.meta b/platform/www/data/meta/en/blog/index.meta
new file mode 100644
index 0000000..48ee089
--- /dev/null
+++ b/platform/www/data/meta/en/blog/index.meta
@@ -0,0 +1 @@
+a:2:{s:7:"current";a:8:{s:4:"date";s:0:"";s:7:"creator";s:0:"";s:4:"user";s:0:"";s:11:"last_change";s:0:"";s:11:"contributor";s:0:"";s:8:"relation";s:0:"";s:8:"internal";s:0:"";s:11:"description";s:0:"";}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1693346819;s:8:"modified";i:1693346860;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1693346860;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:13:"en:blog:index";s:4:"user";s:5:"admin";s:3:"sum";s:0:"";s:5:"extra";s:0:"";s:10:"sizechange";i:0;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/docs/index.changes b/platform/www/data/meta/en/docs/index.changes
new file mode 100644
index 0000000..60266e7
--- /dev/null
+++ b/platform/www/data/meta/en/docs/index.changes
@@ -0,0 +1,4 @@
+1707363304 127.0.0.1 E en:docs:index external edit 1956
+1708032217 192.168.56.1 E en:docs:index admin 137
+1708518144 192.168.56.1 E en:docs:index admin [Features] 118
+1708518697 192.168.56.1 E en:docs:index admin [Features] 97
diff --git a/platform/www/data/meta/en/docs/index.indexed b/platform/www/data/meta/en/docs/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/docs/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/docs/index.meta b/platform/www/data/meta/en/docs/index.meta
new file mode 100644
index 0000000..430f9a3
--- /dev/null
+++ b/platform/www/data/meta/en/docs/index.meta
@@ -0,0 +1,14 @@
+a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1707253874;s:8:"modified";i:1708518697;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:11:"last_change";a:8:{s:4:"date";i:1708518697;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:13:"en:docs:index";s:4:"user";s:5:"admin";s:3:"sum";s:11:"[Features] ";s:5:"extra";s:0:"";s:10:"sizechange";i:97;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:22:"Internal documentation";s:11:"description";a:2:{s:15:"tableofcontents";a:10:{i:0;a:4:{s:3:"hid";s:22:"internal_documentation";s:5:"title";s:22:"Internal documentation";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:23:"technical_documentation";s:5:"title";s:23:"Technical documentation";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:2;a:4:{s:3:"hid";s:17:"design_principles";s:5:"title";s:17:"Design principles";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:3;a:4:{s:3:"hid";s:10:"operations";s:5:"title";s:10:"Operations";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:4;a:4:{s:3:"hid";s:23:"status_of_the_materials";s:5:"title";s:23:"Status of the materials";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:5;a:4:{s:3:"hid";s:34:"translating_string_of_the_platform";s:5:"title";s:34:"Translating string of the platform";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:6;a:4:{s:3:"hid";s:15:"text_management";s:5:"title";s:15:"Text management";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:7;a:4:{s:3:"hid";s:22:"audiovidual_management";s:5:"title";s:22:"Audiovidual management";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:8;a:4:{s:3:"hid";s:12:"useful_tools";s:5:"title";s:12:"Useful tools";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:9;a:4:{s:3:"hid";s:8:"features";s:5:"title";s:8:"Features";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:503:"Internal documentation
+
+Technical documentation
+
+This pages contains the Acervus technical documentation.
+
+Design principles
+
+This platform is centered on a model based on a design that seeks to be simple and based on more or less stable criteria. That is:
+* keep complexity to a minimum;
+* the web platform is a way to navigate and edit a content
+* we separate the content from its identifiers/metadata
+* everything is stored in folders and in plain text files, we do not use databases
+* content col…";}s:8:"relation";a:2:{s:10:"references";a:3:{s:13:"en:docs:index";b:1;s:19:"en:docs:text_format";b:1;s:19:"en:docs:d3-graphviz";b:0;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1707253874;s:8:"modified";i:1708518697;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:11:"last_change";a:8:{s:4:"date";i:1708518697;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:13:"en:docs:index";s:4:"user";s:5:"admin";s:3:"sum";s:11:"[Features] ";s:5:"extra";s:0:"";s:10:"sizechange";i:97;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/docs/text_format.changes b/platform/www/data/meta/en/docs/text_format.changes
new file mode 100644
index 0000000..d876cf5
--- /dev/null
+++ b/platform/www/data/meta/en/docs/text_format.changes
@@ -0,0 +1,19 @@
+1707256754 192.168.56.1 C en:docs:text_format admin created 987
+1707256873 192.168.56.1 E en:docs:text_format admin -196
+1707257019 192.168.56.1 E en:docs:text_format admin 285
+1707257044 192.168.56.1 E en:docs:text_format admin -65
+1707257097 192.168.56.1 E en:docs:text_format admin [Elements] 93
+1707257107 192.168.56.1 E en:docs:text_format admin 1
+1707257124 192.168.56.1 E en:docs:text_format admin [Headers] -73
+1707257172 192.168.56.1 E en:docs:text_format admin 93
+1707257205 192.168.56.1 E en:docs:text_format admin 79
+1707257221 192.168.56.1 E en:docs:text_format admin -8
+1707257257 192.168.56.1 E en:docs:text_format admin 0
+1707257365 192.168.56.1 E en:docs:text_format admin [Elements] 225
+1707258349 127.0.0.1 E en:docs:text_format external edit 1365
+1707258423 192.168.56.1 E en:docs:text_format admin -1
+1707259129 127.0.0.1 E en:docs:text_format external edit -25
+1707259199 192.168.56.1 E en:docs:text_format admin 41
+1707259245 127.0.0.1 E en:docs:text_format external edit -3
+1707259281 192.168.56.1 E en:docs:text_format admin [Headers] 42
+1708050388 192.168.56.1 E en:docs:text_format admin ` 461
diff --git a/platform/www/data/meta/en/docs/text_format.indexed b/platform/www/data/meta/en/docs/text_format.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/docs/text_format.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/docs/text_format.meta b/platform/www/data/meta/en/docs/text_format.meta
new file mode 100644
index 0000000..375c7df
--- /dev/null
+++ b/platform/www/data/meta/en/docs/text_format.meta
@@ -0,0 +1,14 @@
+a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1707256754;s:8:"modified";i:1708050388;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1708050388;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:19:"en:docs:text_format";s:4:"user";s:5:"admin";s:3:"sum";s:1:"`";s:5:"extra";s:0:"";s:10:"sizechange";i:461;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:15:"Formatting text";s:11:"description";a:2:{s:15:"tableofcontents";a:12:{i:0;a:4:{s:3:"hid";s:15:"formatting_text";s:5:"title";s:15:"Formatting text";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"headers";s:5:"title";s:7:"Headers";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:15:"text_formatting";s:5:"title";s:15:"Text formatting";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:3;a:4:{s:3:"hid";s:8:"elements";s:5:"title";s:8:"Elements";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:4;a:4:{s:3:"hid";s:11:"blockquotes";s:5:"title";s:11:"Blockquotes";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:5;a:4:{s:3:"hid";s:13:"ordered_lists";s:5:"title";s:13:"Ordered lists";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:6;a:4:{s:3:"hid";s:15:"unordered_lists";s:5:"title";s:15:"Unordered lists";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:7;a:4:{s:3:"hid";s:12:"nested_lists";s:5:"title";s:12:"Nested lists";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:8;a:4:{s:3:"hid";s:22:"mono-spaced_block_text";s:5:"title";s:22:"Mono-spaced block text";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:9;a:4:{s:3:"hid";s:5:"lines";s:5:"title";s:5:"Lines";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:10;a:4:{s:3:"hid";s:5:"links";s:5:"title";s:5:"Links";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:11;a:4:{s:3:"hid";s:9:"footnotes";s:5:"title";s:9:"Footnotes";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:366:"Formatting text
+
+In Acervus we use Markdown syntax to format all the contents. Here is a simple guideline on how to apply it:
+
+Headers
+
+
+
+# Header level 1 (only for main titles)
+## Header level 2 (Sections)
+### Header level 3 (Sub sections)
+#### Header level 4 (SubSub sections)
+##### Header level 5 (SubSubSub sections)
+###### Header level 6 (SubSubSubSub sections)";}s:8:"relation";a:2:{s:5:"media";a:1:{s:28:"en:docs:markdown_headers.jpg";b:1;}s:10:"firstimage";s:28:"en:docs:markdown_headers.jpg";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1707256754;s:8:"modified";i:1708050388;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1708050388;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:19:"en:docs:text_format";s:4:"user";s:5:"admin";s:3:"sum";s:1:"`";s:5:"extra";s:0:"";s:10:"sizechange";i:461;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/index.changes b/platform/www/data/meta/en/index.changes
index ea28e0b..0d752e4 100644
--- a/platform/www/data/meta/en/index.changes
+++ b/platform/www/data/meta/en/index.changes
@@ -2,3 +2,46 @@
1646767088 192.168.56.1 E en:index admin 1938
1656726728 127.0.0.1 E en:index external edit 1981
1660778261 192.168.56.1 E en:index admin -539
+1686687955 192.168.56.1 E en:index admin 19
+1686688041 192.168.56.1 E en:index admin 3
+1686688121 192.168.56.1 E en:index admin 1
+1686688178 192.168.56.1 E en:index admin 3
+1686688208 192.168.56.1 E en:index admin 12
+1686688425 192.168.56.1 E en:index admin 12
+1686688454 192.168.56.1 E en:index admin 1
+1686688469 192.168.56.1 E en:index admin [Blog] -10
+1686688474 192.168.56.1 E en:index admin 11
+1686688481 192.168.56.1 E en:index admin 1
+1686750898 192.168.56.1 E en:index admin [Blog] 14
+1686750919 192.168.56.1 E en:index admin 1
+1686754741 192.168.56.1 E en:index admin -6
+1686754773 192.168.56.1 E en:index admin -13
+1686754798 192.168.56.1 E en:index admin 6
+1686754820 192.168.56.1 E en:index admin -13
+1686754840 192.168.56.1 E en:index admin 11
+1686754875 192.168.56.1 E en:index admin 11
+1686754902 192.168.56.1 E en:index admin 11
+1686754937 192.168.56.1 E en:index admin -2
+1686764012 192.168.56.1 E en:index admin -13
+1686764037 192.168.56.1 E en:index admin -7
+1686764074 192.168.56.1 E en:index admin 15
+1686764315 192.168.56.1 E en:index admin 5
+1686764326 192.168.56.1 E en:index admin -9
+1686764484 192.168.56.1 E en:index admin 6
+1686764493 192.168.56.1 E en:index admin 1
+1686764509 192.168.56.1 E en:index admin -7
+1686764559 192.168.56.1 E en:index admin 7
+1687361166 192.168.56.1 E en:index admin -7
+1687371997 192.168.56.1 E en:index admin -5
+1687372028 192.168.56.1 E en:index admin [Blog] -20
+1687372085 192.168.56.1 R en:index admin old revision restored (2023/06/21 15:26) 1687371997 -16
+1687372090 192.168.56.1 E en:index admin 36
+1687372112 192.168.56.1 E en:index admin -36
+1687372118 192.168.56.1 E en:index admin 36
+1687372236 192.168.56.1 E en:index admin 2
+1687372430 192.168.56.1 E en:index admin -2
+1687372454 192.168.56.1 E en:index admin 9
+1687372480 192.168.56.1 E en:index admin -5
+1687378171 192.168.56.1 E en:index admin 77
+1687466966 192.168.56.1 E en:index admin 71
+1687466972 192.168.56.1 E en:index admin 1
diff --git a/platform/www/data/meta/en/index.indexed b/platform/www/data/meta/en/index.indexed
index ecc2267..7070c46 100644
--- a/platform/www/data/meta/en/index.indexed
+++ b/platform/www/data/meta/en/index.indexed
@@ -1 +1 @@
-8+plugin_tag=0.2.deaccent=1 \ No newline at end of file
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/index.meta b/platform/www/data/meta/en/index.meta
index 486c9be..ee90fa3 100644
--- a/platform/www/data/meta/en/index.meta
+++ b/platform/www/data/meta/en/index.meta
@@ -1,5 +1,5 @@
-a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1646766450;s:8:"modified";i:1660778261;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1660778261;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:8:"en:index";s:4:"user";s:5:"admin";s:3:"sum";s:0:"";s:5:"extra";s:0:"";s:10:"sizechange";i:-539;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:31:"Welcome to The Acervus Project!";s:11:"description";a:2:{s:15:"tableofcontents";a:1:{i:0;a:4:{s:3:"hid";s:30:"welcome_to_the_acervus_project";s:5:"title";s:31:"Welcome to The Acervus Project!";s:4:"type";s:2:"ul";s:5:"level";i:1;}}s:8:"abstract";s:386:"Welcome to The Acervus Project!
+a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1646766450;s:8:"modified";i:1687466972;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:19:"The Acervus Project";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:19:"the_acervus_project";s:5:"title";s:19:"The Acervus Project";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"updates";s:5:"title";s:7:"Updates";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:457:"The Acervus Project
-This project is under development, more news very soon!
+A collective recovery of the works of thinkers and activists that emerged out of the constellation of conviviality surrounding Ivan Illich
-The initiative has a double purpose: to contribute to the understanding of the critical current condition and to the analysis and debate of the existing options, based on the contributions of Ivan Illich’s circle, and to constitute a complete digital library of his work of general open access.";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1646766450;s:8:"modified";i:1660778261;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1660778261;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"E";s:2:"id";s:8:"en:index";s:4:"user";s:5:"admin";s:3:"sum";s:0:"";s:5:"extra";s:0:"";s:10:"sizechange";i:-539;}s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
+The initiative has a double purpose: to contribute to the understanding of the critical current condition and to the analysis and debate of the existing options, based on the contributions of Ivan Illich’s circle, and to constitute a complete digital library of his work of general open access.";}s:8:"relation";a:2:{s:7:"haspart";a:2:{s:69:"en:blog:2022-02-09-cidoc_recovering_its_past_to_transform_our_present";b:1;s:30:"en:blog:2021-11-01-the_origins";b:1;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1646766450;s:8:"modified";i:1687466972;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/en/tech.changes b/platform/www/data/meta/en/tech.changes
new file mode 100644
index 0000000..c6e177a
--- /dev/null
+++ b/platform/www/data/meta/en/tech.changes
@@ -0,0 +1,22 @@
+1660781040 192.168.56.1 C en:tech admin created 602
+1661997029 127.0.0.1 E en:tech external edit 906
+1663093868 192.168.56.1 E en:tech admin 177
+1663094129 192.168.56.1 E en:tech admin 59
+1663095336 192.168.56.1 E en:tech admin [Footnotes] 43
+1663096017 192.168.56.1 E en:tech admin -42
+1663096678 192.168.56.1 E en:tech admin [Footnotes] -1
+1663096687 192.168.56.1 E en:tech admin 1
+1663098932 192.168.56.1 E en:tech admin 2
+1663099023 192.168.56.1 E en:tech admin -7
+1663099741 192.168.56.1 E en:tech admin [Footnotes] -162
+1663099758 192.168.56.1 E en:tech admin [Footnotes] -2
+1663104217 192.168.56.1 E en:tech admin 53
+1663104839 192.168.56.1 E en:tech admin [Translating string of the platform] 139
+1663104958 192.168.56.1 E en:tech admin -192
+1663105012 192.168.56.1 E en:tech admin [Footnotes] -1
+1663105111 192.168.56.1 E en:tech admin [Footnotes] 2
+1663105135 192.168.56.1 E en:tech admin [Footnotes] 0
+1663105231 192.168.56.1 E en:tech admin [Footnotes] 0
+1663105271 192.168.56.1 E en:tech admin [Footnotes] -1
+1663105314 192.168.56.1 E en:tech admin [Footnotes] 0
+1663105367 192.168.56.1 E en:tech admin [Footnotes] 0
diff --git a/platform/www/data/meta/en/tech.indexed b/platform/www/data/meta/en/tech.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/en/tech.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/en/tech.meta b/platform/www/data/meta/en/tech.meta
new file mode 100644
index 0000000..cfbcb1e
--- /dev/null
+++ b/platform/www/data/meta/en/tech.meta
@@ -0,0 +1,12 @@
+a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1660781040;s:8:"modified";i:1663105367;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:23:"Technical documentation";s:11:"description";a:2:{s:15:"tableofcontents";a:7:{i:0;a:4:{s:3:"hid";s:23:"technical_documentation";s:5:"title";s:23:"Technical documentation";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:17:"design_principles";s:5:"title";s:17:"Design principles";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:10:"operations";s:5:"title";s:10:"Operations";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:3;a:4:{s:3:"hid";s:23:"status_of_the_materials";s:5:"title";s:23:"Status of the materials";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:4;a:4:{s:3:"hid";s:34:"translating_string_of_the_platform";s:5:"title";s:34:"Translating string of the platform";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:5;a:4:{s:3:"hid";s:15:"text_management";s:5:"title";s:15:"Text management";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:6;a:4:{s:3:"hid";s:9:"footnotes";s:5:"title";s:9:"Footnotes";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:503:"Technical documentation
+
+This pages contains the Acervus technical documentation.
+
+Design principles
+
+This platform is centered on a model based on a design that seeks to be simple and based on more or less stable criteria. That is:
+* keep complexity to a minimum;
+* the web platform is a way to navigate and edit a content
+* we separate the content from its identifiers/metadata
+* everything is stored in folders and in plain text files, we do not use databases
+* content collections (books, article…";}s:8:"relation";a:2:{s:10:"references";a:1:{s:8:"en:index";b:1;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1660781040;s:8:"modified";i:1663105367;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2021-11-01-the_origins.changes b/platform/www/data/meta/es/blog/2021-11-01-the_origins.changes
new file mode 100644
index 0000000..21b326c
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2021-11-01-the_origins.changes
@@ -0,0 +1,2 @@
+1687790654 192.168.56.1 C es:blog:2021-11-01-the_origins admin creado 2085
+1687790995 192.168.56.1 E es:blog:2021-11-01-the_origins admin 4
diff --git a/platform/www/data/meta/es/blog/2021-11-01-the_origins.indexed b/platform/www/data/meta/es/blog/2021-11-01-the_origins.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2021-11-01-the_origins.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2021-11-01-the_origins.meta b/platform/www/data/meta/es/blog/2021-11-01-the_origins.meta
new file mode 100644
index 0000000..54782b6
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2021-11-01-the_origins.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:9:{s:4:"date";a:2:{s:7:"created";i:1635735600;s:8:"modified";i:1687790995;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}s:5:"title";s:34:"Los orígenes del Proyecto Acervus";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:33:"los_origenes_del_proyecto_acervus";s:5:"title";s:34:"Los orígenes del Proyecto Acervus";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:511:"Los orígenes del Proyecto Acervus
+
+A comienzos del año 2020, comenzamos a vislumbrar la necesidad de llevar adelante un esfuerzo intergeneracional para recuperar la obra de Ivan Illich. Pensamos en “recuperar” en un sentido amplio del término, no solo dar acceso, también volver inteligible y facilitar el navegar por las complejas capas de su pensamiento. Junto a Gustavo Esteva y Franco Augusto, comenzamos a esbozar la idea de dar acceso abierto, sin fines comerciales y de forma colaborativa a to…";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:1;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:5:{s:4:"date";a:2:{s:7:"created";i:1687790654;s:8:"modified";i:1687790995;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:11:"contributor";a:1:{s:5:"admin";s:5:"admin";}}} \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.changes b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.changes
new file mode 100644
index 0000000..afebe12
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.changes
@@ -0,0 +1 @@
+1693370948 192.168.56.1 C es:blog:2022-02-09-cidoc_recovering_its_past_to_transform_our_present admin creado 1660
diff --git a/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta
new file mode 100644
index 0000000..67c1398
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1644375600;s:8:"modified";i:1693370948;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1693370948;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:69:"es:blog:2022-02-09-cidoc_recovering_its_past_to_transform_our_present";s:4:"user";s:5:"admin";s:3:"sum";s:6:"creado";s:5:"extra";s:0:"";s:10:"sizechange";i:1660;}s:5:"title";s:107:"Centro Intercultural de Documentación de Cuernavaca: recuperar su pasado para transformar nuestro presente";s:11:"description";a:2:{s:15:"tableofcontents";a:3:{i:0;a:4:{s:3:"hid";s:104:"centro_intercultural_de_documentacion_de_cuernavacarecuperar_su_pasado_para_transformar_nuestro_presente";s:5:"title";s:107:"Centro Intercultural de Documentación de Cuernavaca: recuperar su pasado para transformar nuestro presente";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:8:"detalles";s:5:"title";s:8:"Detalles";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:416:"Centro Intercultural de Documentación de Cuernavaca: recuperar su pasado para transformar nuestro presente
+
+En esta primera actividad pública presentaremos la iniciativa para recuperar la historia, producción intelectual y memoria textual, visual y oral del Centro Intercultural de Cuernavaca (CIDOC), que tuviera existencia en los años 1966 y 1976 en México. Esta mítica institución operó como una suerte de";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1693370948;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1693370948;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:69:"es:blog:2022-02-09-cidoc_recovering_its_past_to_transform_our_present";s:4:"user";s:5:"admin";s:3:"sum";s:6:"creado";s:5:"extra";s:0:"";s:10:"sizechange";i:1660;}}} \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.indexed b/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.meta b/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.meta
new file mode 100644
index 0000000..a8f9f93
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2024-03-04-starting_acervus_progress_reports.meta
@@ -0,0 +1,3 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1709607600;s:8:"modified";i:1709629791;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:35:"Comenzamos los Reportes de Progreso";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:35:"comenzamos_los_reportes_de_progreso";s:5:"title";s:35:"Comenzamos los Reportes de Progreso";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:7:"section";s:5:"title";s:0:"";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:275:"Comenzamos los Reportes de Progreso
+
+Con la intención de generar una comunicación mas fluida con los colaboradores y beneficiarios del Proyecto, hemos decidido empezar a publicar reportes regulares que resuman los progresos en las diferentes áreas de trabajo del proyecto.";}s:8:"relation";a:2:{s:10:"references";a:1:{s:25:"es:blog:2024-03-05-apr_01";b:1;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1709626436;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2024-03-05-apr_01.indexed b/platform/www/data/meta/es/blog/2024-03-05-apr_01.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2024-03-05-apr_01.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/es/blog/2024-03-05-apr_01.meta b/platform/www/data/meta/es/blog/2024-03-05-apr_01.meta
new file mode 100644
index 0000000..b717ed1
--- /dev/null
+++ b/platform/www/data/meta/es/blog/2024-03-05-apr_01.meta
@@ -0,0 +1,7 @@
+a:2:{s:7:"current";a:7:{s:4:"date";a:2:{s:7:"created";i:1709607600;s:8:"modified";i:1709629710;}s:4:"user";s:0:"";s:7:"creator";s:0:"";s:5:"title";s:31:"Acervus Reporte de Progreso #01";s:11:"description";a:2:{s:15:"tableofcontents";a:5:{i:0;a:4:{s:3:"hid";s:30:"acervus_reporte_de_progreso_01";s:5:"title";s:31:"Acervus Reporte de Progreso #01";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:14:"illich_acervus";s:5:"title";s:14:"Illich Acervus";s:4:"type";s:2:"ul";s:5:"level";i:2;}i:2;a:4:{s:3:"hid";s:9:"articulos";s:5:"title";s:10:"Artículos";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:3;a:4:{s:3:"hid";s:11:"entrevistas";s:5:"title";s:11:"Entrevistas";s:4:"type";s:2:"ul";s:5:"level";i:3;}i:4;a:4:{s:3:"hid";s:13:"audiovisuales";s:5:"title";s:13:"Audiovisuales";s:4:"type";s:2:"ul";s:5:"level";i:3;}}s:8:"abstract";s:249:"Acervus Reporte de Progreso #01
+
+Este informe cubre las actualizaciones que han tenido lugar durante las dos últimas semanas (2024-02-20 to 2024-03-05).
+
+Illich Acervus
+
+Hemos añadido los siguientes materiales a la pila de materiales por procesar:";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:3:{s:4:"date";a:1:{s:7:"created";i:1709629710;}s:4:"user";s:0:"";s:7:"creator";s:0:"";}} \ No newline at end of file
diff --git a/platform/www/data/meta/es/index.changes b/platform/www/data/meta/es/index.changes
new file mode 100644
index 0000000..7b52249
--- /dev/null
+++ b/platform/www/data/meta/es/index.changes
@@ -0,0 +1 @@
+1686764614 192.168.56.1 C es:index admin creado 1561
diff --git a/platform/www/data/meta/es/index.indexed b/platform/www/data/meta/es/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/es/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/es/index.meta b/platform/www/data/meta/es/index.meta
new file mode 100644
index 0000000..a5a8177
--- /dev/null
+++ b/platform/www/data/meta/es/index.meta
@@ -0,0 +1,5 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1686764614;s:8:"modified";i:1687791681;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;s:5:"title";s:19:"El Proyecto Acervus";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:19:"el_proyecto_acervus";s:5:"title";s:19:"El Proyecto Acervus";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:9:"novedades";s:5:"title";s:9:"Novedades";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:452:"El Proyecto Acervus
+
+Una recuperación colectiva de las obras de pensadores y activistas surgidos de la constelación de convivencia en torno a Ivan Illich
+
+La iniciativa tiene un doble propósito: contribuir a la comprensión de la crítica condición actual y al análisis y debate de las opciones existentes, a partir de las aportaciones del círculo de Ivan Illich, y constituir una completa biblioteca digital de su obra de acceso abierto general.";}s:8:"relation";a:2:{s:7:"haspart";a:4:{s:25:"es:blog:2024-03-05-apr_01";b:1;s:52:"es:blog:2024-03-04-starting_acervus_progress_reports";b:1;s:69:"es:blog:2022-02-09-cidoc_recovering_its_past_to_transform_our_present";b:1;s:30:"es:blog:2021-11-01-the_origins";b:1;}s:10:"firstimage";s:0:"";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1686764614;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";b:0;}} \ No newline at end of file
diff --git a/platform/www/data/meta/fr/index.changes b/platform/www/data/meta/fr/index.changes
new file mode 100644
index 0000000..779f3b2
--- /dev/null
+++ b/platform/www/data/meta/fr/index.changes
@@ -0,0 +1 @@
+1687791864 192.168.56.1 C fr:index admin created 1787
diff --git a/platform/www/data/meta/fr/index.indexed b/platform/www/data/meta/fr/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/fr/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/fr/index.meta b/platform/www/data/meta/fr/index.meta
new file mode 100644
index 0000000..f07ad6f
--- /dev/null
+++ b/platform/www/data/meta/fr/index.meta
@@ -0,0 +1,5 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1687791864;s:8:"modified";i:1687791864;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791864;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"fr:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1787;}s:5:"title";s:17:"Le projet Acervus";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:17:"le_projet_acervus";s:5:"title";s:17:"Le projet Acervus";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:12:"mises_a_jour";s:5:"title";s:13:"Mises à jour";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:459:"Le projet Acervus
+
+Une récupération collective des travaux de penseurs et d'activistes qui ont émergé de la constellation de convivialité autour d'Ivan Illich.
+
+L'initiative a un double objectif : contribuer à la compréhension de la condition critique actuelle et à l'analyse et au débat des options existantes, sur la base des contributions du cercle d'Ivan Illich, et constituer une bibliothèque numérique complète de son œuvre en libre accès.";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1687791864;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791864;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"fr:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1787;}}} \ No newline at end of file
diff --git a/platform/www/data/meta/it/index.changes b/platform/www/data/meta/it/index.changes
new file mode 100644
index 0000000..3fd03eb
--- /dev/null
+++ b/platform/www/data/meta/it/index.changes
@@ -0,0 +1 @@
+1687791887 192.168.56.1 C it:index admin created 1670
diff --git a/platform/www/data/meta/it/index.indexed b/platform/www/data/meta/it/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/it/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/it/index.meta b/platform/www/data/meta/it/index.meta
new file mode 100644
index 0000000..c785382
--- /dev/null
+++ b/platform/www/data/meta/it/index.meta
@@ -0,0 +1,5 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1687791887;s:8:"modified";i:1687791887;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791887;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"it:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1670;}s:5:"title";s:19:"Il Progetto Acervus";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:19:"il_progetto_acervus";s:5:"title";s:19:"Il Progetto Acervus";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:13:"aggiornamenti";s:5:"title";s:13:"Aggiornamenti";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:432:"Il Progetto Acervus
+
+Recupero collettivo delle opere di pensatori e attivisti emerse dalla costellazione di convivialità intorno a Ivan Illich
+
+L'iniziativa ha un duplice scopo: contribuire alla comprensione della condizione critica attuale e all'analisi e al dibattito delle opzioni esistenti, sulla base dei contributi della cerchia di Ivan Illich, e costituire una biblioteca digitale completa della sua opera di libero accesso.";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1687791887;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791887;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"it:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1670;}}} \ No newline at end of file
diff --git a/platform/www/data/meta/macros/macros.ser b/platform/www/data/meta/macros/macros.ser
index cee3e6c..1c3afcf 100644
--- a/platform/www/data/meta/macros/macros.ser
+++ b/platform/www/data/meta/macros/macros.ser
@@ -1 +1 @@
-a:7:{s:12:"LANG_authors";s:12:"LANG_authors";s:13:"LANG_comments";s:13:"LANG_comments";s:20:"LANG_publicationdate";s:20:"LANG_publicationdate";s:13:"LANG_textfull";s:13:"LANG_textfull";s:14:"LANG_titleorig";s:14:"LANG_titleorig";s:13:"LANG_versions";s:13:"LANG_versions";s:17:"LANG_translations";s:17:"LANG_translations";} \ No newline at end of file
+a:11:{s:12:"LANG_authors";s:12:"LANG_authors";s:13:"LANG_comments";s:13:"LANG_comments";s:12:"LANG_lang_en";s:12:"LANG_lang_en";s:12:"LANG_lang_es";s:12:"LANG_lang_es";s:13:"LANG_langorig";s:13:"LANG_langorig";s:20:"LANG_publicationdate";s:20:"LANG_publicationdate";s:13:"LANG_textfull";s:13:"LANG_textfull";s:14:"LANG_titleorig";s:14:"LANG_titleorig";s:17:"LANG_translations";s:17:"LANG_translations";s:13:"LANG_versions";s:13:"LANG_versions";s:16:"LANG_translators";s:16:"LANG_translators";} \ No newline at end of file
diff --git a/platform/www/data/meta/pt/index.changes b/platform/www/data/meta/pt/index.changes
new file mode 100644
index 0000000..cec7d56
--- /dev/null
+++ b/platform/www/data/meta/pt/index.changes
@@ -0,0 +1 @@
+1687791907 192.168.56.1 C pt:index admin created 1676
diff --git a/platform/www/data/meta/pt/index.indexed b/platform/www/data/meta/pt/index.indexed
new file mode 100644
index 0000000..7070c46
--- /dev/null
+++ b/platform/www/data/meta/pt/index.indexed
@@ -0,0 +1 @@
+8+plugin_include=0.1.safeindex=1+plugin_tag=0.2.deaccent=1 \ No newline at end of file
diff --git a/platform/www/data/meta/pt/index.meta b/platform/www/data/meta/pt/index.meta
new file mode 100644
index 0000000..338a85a
--- /dev/null
+++ b/platform/www/data/meta/pt/index.meta
@@ -0,0 +1,5 @@
+a:2:{s:7:"current";a:8:{s:4:"date";a:2:{s:7:"created";i:1687791907;s:8:"modified";i:1687791907;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791907;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"pt:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1676;}s:5:"title";s:17:"O Projeto Acervus";s:11:"description";a:2:{s:15:"tableofcontents";a:2:{i:0;a:4:{s:3:"hid";s:17:"o_projeto_acervus";s:5:"title";s:17:"O Projeto Acervus";s:4:"type";s:2:"ul";s:5:"level";i:1;}i:1;a:4:{s:3:"hid";s:13:"actualizacoes";s:5:"title";s:15:"Actualizações";s:4:"type";s:2:"ul";s:5:"level";i:2;}}s:8:"abstract";s:434:"O Projeto Acervus
+
+Uma recuperação colectiva das obras de pensadores e activistas que emergiram da constelação de convívio em torno de Ivan Illich
+
+A iniciativa tem um duplo objetivo: contribuir para a compreensão da condição crítica atual e para a análise e debate das opções existentes, com base nos contributos do círculo de Ivan Illich, e constituir uma biblioteca digital completa da sua obra de acesso aberto geral.";}s:8:"internal";a:2:{s:5:"cache";b:1;s:3:"toc";b:0;}s:8:"relation";a:1:{s:10:"firstimage";s:0:"";}}s:10:"persistent";a:4:{s:4:"date";a:1:{s:7:"created";i:1687791907;}s:7:"creator";s:5:"admin";s:4:"user";s:5:"admin";s:11:"last_change";a:8:{s:4:"date";i:1687791907;s:2:"ip";s:12:"192.168.56.1";s:4:"type";s:1:"C";s:2:"id";s:8:"pt:index";s:4:"user";s:5:"admin";s:3:"sum";s:7:"created";s:5:"extra";s:0:"";s:10:"sizechange";i:1676;}}} \ No newline at end of file
diff --git a/platform/www/data/pages/de/index.txt b/platform/www/data/pages/de/index.txt
new file mode 100644
index 0000000..2a78b12
--- /dev/null
+++ b/platform/www/data/pages/de/index.txt
@@ -0,0 +1,28 @@
+~~NOTOC~~~
+
+# Das Acervus-Projekt
+
+**Eine kollektive Wiederherstellung der Werke von Denkern und Aktivisten, die aus der Konvivialitätskonstellation um Ivan Illich hervorgegangen sind**
+
+
+Die Initiative verfolgt ein doppeltes Ziel: einen Beitrag zum Verständnis der kritischen gegenwärtigen Situation und zur Analyse und Debatte der bestehenden Optionen zu leisten, basierend auf den Beiträgen des Kreises um Ivan Illich, und eine vollständige digitale Bibliothek seines Werks mit allgemeinem Zugang zu schaffen.
+
+Die Initiative zielt darauf ab, einen digitalen Acervus von verschiedenen Autoren wie Ivan Illich, Jean Robert, Gustavo Esteva und anderen zu erstellen. Das gesamte Material wird auf einer digitalen Plattform präsentiert, die speziell für den einfachen Zugang, das Nachschlagen, die Lektüre auf verschiedenen Trägern/Formaten und die Neuauflage in Papierform durch unabhängige Gruppen mit gemeinnützigen Zwecken konzipiert ist.
+
+Dieser virtuelle Raum wird unter Verwendung von Open-Source-Technologien entwickelt, die auf Zusammenarbeit, dezentralisierte Selbstveröffentlichung und Interaktion mit den Inhalten auf vielfältige Weise ausgerichtet sind. Auf diese Weise wird es möglich sein, eine zuverlässige, lesbare und dauerhafte Quelle zu schaffen, die sowohl den Zugang zu jedem Werk als auch den Verweis auf bestimmte Teile und Auszüge ermöglicht.
+
+Die Bibliothek wird aus Büchern, ihren verschiedenen Versionen in unterschiedlichen Sprachen (mit der Angabe, ob es sich um direkte Übersetzungen anderer Versionen handelt), Zusammenstellungen, Artikeln, Interviews, Audio- und Videoaufnahmen bestehen. Es wird eine dynamische und kollaborative Veröffentlichungsplattform sein.
+
+**Wenn Sie uns erreichen wollen, schreiben Sie bitte an <info@acerv.us>**
+
+## Updates
+
+{{blog>de:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display: none !important;
+}
+</style>
+</html>
diff --git a/platform/www/data/pages/en/blog/2021-11-01-the_origins.txt b/platform/www/data/pages/en/blog/2021-11-01-the_origins.txt
new file mode 100644
index 0000000..8cabc13
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2021-11-01-the_origins.txt
@@ -0,0 +1,15 @@
+~~META:
+date created = 2021-11-01
+~~
+
+# The origins of the Acervus Project
+
+In early 2020, we began to envision the need for an intergenerational effort to recover the work of Ivan Illich. We thought of "recovering" in a broad sense of the term, not only giving access, but also making intelligible and facilitating the navigation through the complex layers of his thought. Together with Gustavo Esteva and Franco Augusto, we began to outline the idea of providing open access, non-commercial and collaborative access to all of Ivan's work, starting with the original texts. At the beginning we informally called this effort _"Illich's Archives"_.
+
+##
+
+In the midst of the COVID-19 pandemic, we exchanged emails with hundreds of people linked to his work, to CIDOC in Cuernavaca, and we searched every possible corner of the web to put together what began to be an enormous digital collection of works written by Ivan himself, his friends and collaborators. We not only found texts, but also sound material, old documents rusted by time and we began to understand that ours would be an effort of several years devoted to rebuild an intellectual building scattered in several cities around the world.
+
+At the same time, we knew that this was not just an archival exercise. Our search, from the beginning, was guided by the need to find clues that would help us understand the convulsed present, the struggles of those from below, the need to invent here and now ways out of the civilizational crises. Our project would be like that crab that sought to advance with its eyes fixed on the past.
+
+The ideas and hypotheses that we advanced during this year were condensed in a collective text entitled ["Towards Illich's 'Legibility': Returning to Ivan through the Mirror of the Past"](https://journals.psu.edu/illichstudies/article/view/62315/61623), which was published in Vol. 7 No. 1 of ["The International Journal of Illich Studies"](https://journals.psu.edu/illichstudies).
diff --git a/platform/www/data/pages/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt b/platform/www/data/pages/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt
new file mode 100644
index 0000000..f7027ee
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt
@@ -0,0 +1,18 @@
+~~META:
+date created = 2022-02-09
+~~
+~~NOTOC~~
+
+
+# Centro Intercultural de Documentación de Cuernava (CIDOC): Recovering its past to transform our present
+
+In this first public activity we will present the initiative to recover the history, intellectual production and textual, visual and oral memory of the Intercultural Center of Cuernavaca (CIDOC), which existed in the years 1966 and 1976 in Mexico. This mythical institution operated as a sort of "alternative university" and was the origin of reflections and intellectual productions that forever changed education in Latin America and the world.
+
+##
+
+A series of dialogues, debates and writings took place there, featuring Ivan Illich, John Holt, Everett Reimer, Paul Goodman, Paulo Freire and many other theoreticians of education and social change. CIDOC had a decisive impact in its time and its effects are still strongly felt today in ways that we are only now beginning to understand. It was the cradle of a series of revolutionary ideas that today, in the global context of the so-called "post-pandemic", take on an unusual relevance: unschooling; education without school; liberation pedagogy; degrowth; limits to development; ecosocialism; critique of institutionalized medicine; deprofessionalization; appropriable technologies; open source; the hacker movement; decoloniality; conviviality; among so many others, have in CIDOC their undeniable mark of origin.
+
+## Details
+
+* Date and time: Wednesday 9th at 4:30 pm (UTC)
+* Place: Virtual and in place (Unitierra Oaxaca)
diff --git a/platform/www/data/pages/en/blog/2024-03-04-starting_acervus_progress_reports.txt b/platform/www/data/pages/en/blog/2024-03-04-starting_acervus_progress_reports.txt
new file mode 100644
index 0000000..8d4069c
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2024-03-04-starting_acervus_progress_reports.txt
@@ -0,0 +1,17 @@
+~~META:
+date created = 2024-03-04
+~~
+~~NOTOC~~
+
+
+# We started the Acervus Progress Reports!
+
+With the intention of generating a more fluid communication with the collaborators and beneficiaries of the Project, we have decided to start publishing regular reports summarizing the progress in the different work areas of the project.
+
+##
+
+So far, those of us involved in the Acervus Project have been working quietly, working hard to process and organize the enormous amount of material we have collected. We continue to make progress in the recovery of content for the different collections, focusing especially on Illich's and CIDOC's collections. We have accessed new articles, interviews and audio recordings. Since we have already made substantial progress in the construction of the index of sources, in the coming weeks we will be publishing regular updates with the progress we are making. We expect these updates to be published every 2 weeks.
+
+In these brief reports we plan to share new acquisitions, status of digitizations, progress in the development of the web platform and other issues that we consider valuable to inform those who follow closely this collaborative initiative.
+
+Without further ado, we share with you the link to access the [[2024-03-05-apr_01|first report]].
diff --git a/platform/www/data/pages/en/blog/2024-03-05-apr_01.txt b/platform/www/data/pages/en/blog/2024-03-05-apr_01.txt
new file mode 100644
index 0000000..4562370
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2024-03-05-apr_01.txt
@@ -0,0 +1,39 @@
+~~META:
+date created = 2024-03-05
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #01
+
+This report covers the updates that took place during the last two weeks (2024-02-20 to 2024-03-05).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1958 - The End of Human Life: an interpretation of Death as the Supreme Form of Prayer
+* 1960 - Problemas teológicos de Latino América
+* 1966 - Financial Aid for Latin America
+* 1969 - Between Jail and Campus: The Chaplain's Halfway House
+* 1969 - The need for counterfoil research
+* 1971 - The Alternative to Schooling; Extended Version
+* 1971 - Ivan Illich Challenges Education
+* 1971 - Look Out Practitioners
+* 1972 - A Convivial Society for Melanesia?
+* 1972 - Gradual change or violent revolution in Latin America?
+* 1972 - The illusion of unlimited health insurance
+* 1972 - Bibliografía Límites; agosto-septiembre de 1972
+* 1972 - Growth: myth and reality
+
+### Interviews
+
+* 1974 - On Growth: Interview with Ivan Illich
+
+### Audiovisuals
+
+* 1978 - The Art of Suffering
+* 1968 - Elspeth Chisholm visits Ivan Illich in Cuernavaca
+* 1968 - Elspeth Chisholm interviews Ivan Illich in Cuernavaca
+* 1969 - CBC Tuesday Night - Visit to Cuernavaca
diff --git a/platform/www/data/pages/en/blog/2024-03-20-apr_02.txt b/platform/www/data/pages/en/blog/2024-03-20-apr_02.txt
new file mode 100644
index 0000000..f9b64f2
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2024-03-20-apr_02.txt
@@ -0,0 +1,34 @@
+~~META:
+date created = 2024-03-20
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #02
+
+This report covers the updates that took place during the last two weeks (2024-03-06 to 2024-03-20).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1973 - Energy and Equity: final draft
+* 1973 - Energie, Vitesse et Justice Sociale
+* 1974 - Energy and Equity
+* 1974 - Les coûts de l'education a vie
+* 1975 - Les enseignants sont-ils necessaires?
+* 1975 - Le piège de l'école à vie
+* 1976 - Imprisoned in the Global Classroom
+* 1976 - Bibliographical Supplement To: Medical Nemesis, Pantheon, 1976 & Limits To Medicine, Boyars, 1976
+* 1976 - Disabling Professions: notes for a lecture
+* 1977 - Useful Unemployment and its Professional Enemies
+* 1977 - L’incompétence spécialisée
+* 1978 - Introducción a "Lo inverso de la salud administrada" de Valentina Borremans
+* 1979 - Von ende des entwicklungsverhabens
+* 1979 - Allocution prononcée lors de la séance de clôture du Colloque International sur l'Informatique et la Société
+
+### Audiovisuals
+
+* 1970 - Ivan Illich at conference called Milieu 70 held in Winnipeg
+* 1971 - The Institutionalization of Truth
diff --git a/platform/www/data/pages/en/blog/2024-04-05-apr_03.md b/platform/www/data/pages/en/blog/2024-04-05-apr_03.md
new file mode 100644
index 0000000..9cb5cf1
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2024-04-05-apr_03.md
@@ -0,0 +1,30 @@
+~~META:
+date created = 2024-04-05
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #03
+
+This report covers the updates that took place during the last two weeks (2024-03-21 to 2024-04-05).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1980 - Alternativas del desarrollo
+* 1980 - Salud y calidad de vida
+* 1980 - Shadow-Work, a draft
+* 1980 - Vernacular Virtue
+* 1980 - Erziehung für ein leben im 7? Stock? Danke, nein!
+* 1981 - Vernacular Gender
+* 1982 - The Right to Dignified Silence
+* 1983 - Dank as die Gastfreunde
+* 1983 - La reivindicación de la casa
+* 1984 - La salud y la calidad de vida en la escasez
+* 1984 - El hedor de la ciudad y sus aguas
+
+### Audiovisuals
+
+* 1971 - Balance and Biosphere
diff --git a/platform/www/data/pages/en/blog/2024-04-20-apr_04.md b/platform/www/data/pages/en/blog/2024-04-20-apr_04.md
new file mode 100644
index 0000000..1a36407
--- /dev/null
+++ b/platform/www/data/pages/en/blog/2024-04-20-apr_04.md
@@ -0,0 +1,31 @@
+~~META:
+date created = 2024-04-20
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #04
+
+This report covers the updates that took place during the last two weeks (2024-04-06 to 2024-04-20).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1984 - Newspeak and uniquack in 1984
+* 1984 - Phaidros
+* 1985 - Tecnológica verde
+* 1985 - La búsqueda de nuevos commons
+* 1985 - Pilgernder und kriegender Individualismus
+* 1985 - Hacia una historia de las necesidades
+* 1985 - Development: metaphor, myth, threat
+* 1986 - My Affair with Education
+* 1987 - Reflections on Jaques Ellul, La subversion du christianisme
+* 1992 - Reading the Intangible
+* 1992 - Lectio divina
+
+### Audiovisuals
+
+* 1971 - Ivan Illich Challenges Education
+* 1972 - Ideas. The Law and Society
diff --git a/platform/www/data/pages/en/docs/index.txt b/platform/www/data/pages/en/docs/index.txt
new file mode 100644
index 0000000..7011cb8
--- /dev/null
+++ b/platform/www/data/pages/en/docs/index.txt
@@ -0,0 +1,57 @@
+# Internal documentation
+
+# Technical documentation
+
+This pages contains the Acervus technical documentation.
+
+## Design principles
+
+This platform is centered on a model based on a design that seeks to be simple and based on more or less stable criteria. That is:
+* keep complexity to a minimum;
+* the web platform is a way to navigate and edit a content
+* we separate the content from its identifiers/metadata
+* everything is stored in folders and in plain text files, we do not use databases
+* content collections (books, articles, etc) have priority, and must be usable without the platform.
+
+## Operations
+
+### Status of the materials
+
+We defined three categories to describe the status of an item of the collection:
+
+* **Available**: item is fully processed and available in the online platform. Tag definition is ```{{tag>available}}```.
+* **Pending**: item is available in some digital format, but is pending to be processed to accomplish the platform technical requirements. Tag definition is ```{{tag>pending}}```.
+* **Missing**: item is not available yet in any digital format. Tag definition is ```{{tag>missing}}```.
+
+## Translating string of the platform
+
+Two files needs to be edited:
+
+* ```i18n/textinsert_strings.php```
+* ```www/data/meta/macros/macros.ser```
+
+First add the reference to the array in ```www/data/meta/macros/macros.ser```. This also can be done in the webinterface ([[/index?do=admin&page=textinsert|this link]]). Then edit ```i18n/textinsert_strings.php``` to incorporate the localized string text.
+
+## Text management
+
+Here are some docs related to the way we manage the text contents
+
+* [[text_format|Text format]]
+
+## Audiovidual management
+
+### Useful tools
+
+To generate a subtitle from a video, using AI:
+
+```/home/yaco/python/bin/whisper_autosrt -S es -D en 2022_02_09-Acervus_CIDOC_presentacion.mp4```
+
+More information about ```whisper_autosrt```, it's available here: https://github.com/botbahlul/whisper_autosrt
+
+## Features
+
+Ideas to consider:
+
+* Improve diff visualizations of text versions using [[https://diff2html.xyz/index.html|diff2html.js]]
+
+* Implement some type of visualization of pages using GraphViz DOT and D3, see: [[d3-graphviz|https://github.com/magjac/d3-graphviz]] and [[https://github.com/mountainstorm/jquery.graphviz.svg|jquery.graphviz.svg]] \ No newline at end of file
diff --git a/platform/www/data/pages/en/docs/text_format.txt b/platform/www/data/pages/en/docs/text_format.txt
new file mode 100644
index 0000000..d295772
--- /dev/null
+++ b/platform/www/data/pages/en/docs/text_format.txt
@@ -0,0 +1,199 @@
+# Formatting text
+
+In Acervus we use [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax to format all the contents. Here is a simple guideline on how to apply it:
+
+## Headers
+
+```
+# Header level 1 (only for main titles)
+## Header level 2 (Sections)
+### Header level 3 (Sub sections)
+#### Header level 4 (SubSub sections)
+##### Header level 5 (SubSubSub sections)
+###### Header level 6 (SubSubSubSub sections)
+```
+
+{{:en:docs:markdown_headers.jpg?nolink|}}
+
+## Text formatting
+
+```*This text will be italic*```
+
+*This text will be italic*
+
+----
+
+```_This text will be italic_```
+
+_This text will be italic_
+
+----
+
+```**This text will be bold**```
+
+**This text will be bold**
+
+----
+
+```***This text will be bold and italic***```
+
+***This text will be bold and italic***
+
+
+
+## Elements
+
+### Blockquotes
+
+```> This is a blockquote. We use it for quotes and also for poems.```
+
+> This is a blockquote. We use it for quotes and also for poems.
+
+
+### Ordered lists
+
+```
+1. Item 1
+2. Item 2
+3. Item 3
+```
+
+1. Item 1
+2. Item 2
+3. Item 3
+
+```
+1. Item 1
+1. Item 2
+1. Item 3
+```
+
+1. Item 1
+1. Item 2
+1. Item 3
+
+
+### Unordered lists
+
+```
+* Item 1
+* Item 2
+* Item 3
+```
+
+* Item 1
+* Item 2
+* Item 3
+
+```
+- Item 4
+- Item 5
+- Item 6
+```
+
+- Item 4
+- Item 5
+- Item 6
+
+### Nested lists
+
+#### Unsorted
+
+```
+* Item 1
+ * Item 1.1
+ * Item 1.1.1
+ * Item 1.1.2
+ * Item 1.2
+* Item 2
+ * Item 2.1
+* Item 3
+```
+
+
+* Item 1
+ * Item 1.1
+ * Item 1.1.1
+ * Item 1.1.2
+ * Item 1.2
+* Item 2
+ * Item 2.1
+* Item 3
+
+
+#### Sorted
+
+```
+1. Item 1
+ 1. Item 1.1
+ 1. Item 1.1.1
+ 1. Item 1.1.2
+ 1. Item 1.2
+1. Item 2
+ 1. Item 2.1
+1. Item 3
+```
+
+
+1. Item 1
+ 1. Item 1.1
+ 1. Item 1.1.1
+ 1. Item 1.1.2
+ 1. Item 1.2
+1. Item 2
+ 1. Item 2.1
+1. Item 3
+
+##### Avoiding numbered bullet formatting
+
+In certain cases, we want to start a sentence with a numeration. To avoid this to be recognized as a numbered bullet and getting a left margin, we use the following code that replaces regular whitespace with a [[https://en.wikipedia.org/wiki/Non-breaking_space#Width_variation|"Narrw No-Break Space"]]. This is the result that can be copy-pasted:
+
+```1. ```
+
+1. This is a numbered sentence without buller format
+
+
+## Mono-spaced block text
+
+```
+```We can mark text in monospaced font using this format```
+```
+
+```
+We can mark text in monospaced font using this format
+```
+
+## Lines
+
+* ```--``` becomes --
+* ```---``` becomes ---
+* ```----``` becomes a full width horizontal lines, useful to divide elements, below you can see it:
+
+----
+
+## Links
+
+```[Text of the link](https://acerv.us).```
+
+[Text of the link](https://acerv.us).
+
+## Footnotes
+
+```
+This a paragraph with some footnotes. We put the reference like this[^n01]. And we can other reference at the end of this sentence[^n02]. Then at the end of the article, we list the reference and write a footnote in a single line each of them.
+
+...
+
+[^n01:] This is the first footnote. ]
+
+[^n02:] This is the second footnote. .]
+```
+
+
+This a paragraph with some footnotes. We put the reference like this[^n01]. And we can other reference at the end of this sentence[^n02]. Then at the end of the article, we list the reference and write a footnote in a single line each of them.
+
+...
+
+[^n01:] This is the first footnote. ]
+
+[^n02:] This is the second footnote. .]
diff --git a/platform/www/data/pages/en/index.txt b/platform/www/data/pages/en/index.txt
index 6bbce37..915b2f7 100644
--- a/platform/www/data/pages/en/index.txt
+++ b/platform/www/data/pages/en/index.txt
@@ -1,6 +1,9 @@
-# Welcome to The Acervus Project!
+~~NOTOC~~
+
+# The Acervus Project
+
+**A collective recovery of the works of thinkers and activists that emerged out of the constellation of conviviality surrounding Ivan Illich**
-**This project is under development, more news very soon!**
The initiative has a double purpose: to contribute to the understanding of the critical current condition and to the analysis and debate of the existing options, based on the contributions of Ivan Illich’s circle, and to constitute a complete digital library of his work of general open access.
@@ -12,3 +15,14 @@ The library will consist of the books, their various versions in different langu
**If you want to reach us, please write to <info@acerv.us>**
+## Updates
+
+{{blog>en:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display: none !important;
+}
+</style>
+</html>
diff --git a/platform/www/data/pages/es/blog/2021-11-01-the_origins.txt b/platform/www/data/pages/es/blog/2021-11-01-the_origins.txt
new file mode 100644
index 0000000..669954f
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2021-11-01-the_origins.txt
@@ -0,0 +1,15 @@
+~~META:
+date created = 2021-11-01
+~~
+
+# Los orígenes del Proyecto Acervus
+
+A comienzos del año 2020, comenzamos a vislumbrar la necesidad de llevar adelante un esfuerzo intergeneracional para recuperar la obra de Ivan Illich. Pensamos en "recuperar" en un sentido amplio del término, no solo dar acceso, también volver inteligible y facilitar el navegar por las complejas capas de su pensamiento. Junto a Gustavo Esteva y Franco Augusto, comenzamos a esbozar la idea de dar acceso abierto, sin fines comerciales y de forma colaborativa a toda la obra de Ivan, empezando por los textos originales. Al comienzo denominamos informalmente a este esfuerzo como _"Illich's Archives"_.
+
+##
+
+En plena pandemia del COVID-19 intercambiamos correos con cientos de personas vinculadas a su obra, al CIDOC de Cuernavaca y rastreamos todos los rincones posibles de la red para confeccionar lo que comenzó a ser un enorme acervo digital de obras escritos por el mismísimo Iván, sus amigos y colaboradores. No solo dimos con textos, también con material sonoro, antiguos documentos oxidados por el tiempo y comenzamos a comprender que el nuestro sería un esfuerzo de varios años abocados a reconstruir un edificio intelectual disperso en varias ciudades del mundo.
+
+Al mismo tiempo, sabíamos que no se trataba solamente de un ejercicio archivística. Nuestra búsqueda, desde el comienzo, estuvo guiada por la necesidad de encontrar pistas que nos ayudaran a comprender el convulsionado presente, las luchas de los de abajo, la necesidad de inventar aquí y ahora salidas frente a las crisis civilizatorias. Nuestro proyecto sería como aquel cangrejo que buscaba avanzar con los ojos puestos fijamente en el pasado.
+
+Las ideas e hipótesis que avanzamos en este año se condensaron en un texto colectivo titulado _["Towards Illich's 'Legibility': Returning to Ivan through the Mirror of the Past"](https://journals.psu.edu/illichstudies/article/view/62315/61623)_, que fue publicado en el Vol. 7 No. 1 del _["The International Journal of Illich Studies"](https://journals.psu.edu/illichstudies)_.
diff --git a/platform/www/data/pages/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt b/platform/www/data/pages/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt
new file mode 100644
index 0000000..2da449c
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2022-02-09-cidoc_recovering_its_past_to_transform_our_present.txt
@@ -0,0 +1,18 @@
+~~META:
+date created = 2022-02-09
+~~
+~~NOTOC~~
+
+
+# Centro Intercultural de Documentación de Cuernavaca: recuperar su pasado para transformar nuestro presente
+
+En esta primera actividad pública presentaremos la iniciativa para recuperar la historia, producción intelectual y memoria textual, visual y oral del Centro Intercultural de Cuernavaca (CIDOC), que tuviera existencia en los años 1966 y 1976 en México. Esta mítica institución operó como una suerte de "universidad alternativa" y fue el origen de reflexiones y producciones intelectuales que cambiaron para siempre la educación en América Latina y el mundo.
+
+##
+
+Allí tuvieron lugar una serie de diálogos, debates y escritos protagonizados por Ivan Illich, John Holt, Everett Reimer, Paul Goodman, Paulo Freire y otrxs tantxs teóricxs de la educación y el cambio social. El CIDOC tuvo un impacto decisivo en su tiempo y sus efectos llegan con fuerza a hasta nuestro días de formas que apenas ahora empezamos a comprender. Fue la cuna de una de serie de ideas revolucionarias que hoy, en el contexto global de la llamada "post-pandemia", cobran una relevancia inusitada: la desescolarización; la educación sin escuela; la pedagogía de la liberación; el decrecimiento; los límites al desarrollo; el ecosocialismo; la crítica a la medicina institucionalizada; la desprofesionalización; las tecnologías apropiables; el código abierto; el movimiento hacker; la decolonialidad; la convivencialidad; entre tantos otros, tienen en el CIDOC su marca de origen innegable.
+
+## Detalles
+
+* Fecha y tiempo: Miércoles 9 a las 4:30 pm (UTC)
+* Lugar: Virtual y presencial (Unitierra Oaxaca)
diff --git a/platform/www/data/pages/es/blog/2024-03-04-starting_acervus_progress_reports.txt b/platform/www/data/pages/es/blog/2024-03-04-starting_acervus_progress_reports.txt
new file mode 100644
index 0000000..16a8814
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2024-03-04-starting_acervus_progress_reports.txt
@@ -0,0 +1,17 @@
+~~META:
+date created = 2024-03-05
+~~
+~~NOTOC~~
+
+
+# Comenzamos los Reportes de Progreso
+
+Con la intención de generar una comunicación mas fluida con los colaboradores y beneficiarios del Proyecto, hemos decidido empezar a publicar reportes regulares que resuman los progresos en las diferentes áreas de trabajo del proyecto.
+
+##
+
+Hasta ahora quienes hacemos el Proyecto Acervus hemos estado trabajando silenciosamente, abocados fuertemente a procesar y ordernar la enorme cantidad de material hemos recopilado. Seguimos avanzando en la recuperación de contenidos para las diferentes colecciones, abocados especialmente a la de Illich y la del CIDOC. Hemos accedido a nuevos artículos, entrevistas y grabaciones de audio. Siendo que ya tenemos un avance sustancial en la construcción del índice de fuentes, en las próximas semanas iremos publicando actualizaciones regulares con los avances que vayamos realizando. Esperamos que estas novedades se publiquen cada 2 semanas.
+
+En estos breves reportes pensamos compartir las nuevas adquisiciones, estado de las digitalizaciones, avances en el desarrollo de la plataforma web y otras cuestiones que consideremos valioso de informar a quienes siguen de cerca esta iniciativa colaborativa.
+
+Sin más que agregar, les compartimos el enlace para acceder al [[2024-03-05-apr_01|primer reporte]].
diff --git a/platform/www/data/pages/es/blog/2024-03-05-apr_01.txt b/platform/www/data/pages/es/blog/2024-03-05-apr_01.txt
new file mode 100644
index 0000000..b5d5010
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2024-03-05-apr_01.txt
@@ -0,0 +1,39 @@
+~~META:
+date created = 2024-03-05
+~~
+~~NOTOC~~
+
+# Acervus Reporte de Progreso #01
+
+Este informe cubre las actualizaciones que han tenido lugar durante las dos últimas semanas (2024-02-20 to 2024-03-05).
+
+## Illich Acervus
+
+Hemos añadido los siguientes materiales a la pila de materiales por procesar:
+
+### Artículos
+
+* 1958 - The End of Human Life: an interpretation of Death as the Supreme Form of Prayer
+* 1960 - Problemas teológicos de Latino América
+* 1966 - Financial Aid for Latin America
+* 1969 - Between Jail and Campus: The Chaplain's Halfway House
+* 1969 - The need for counterfoil research
+* 1971 - The Alternative to Schooling; Extended Version
+* 1971 - Ivan Illich Challenges Education
+* 1971 - Look Out Practitioners
+* 1972 - A Convivial Society for Melanesia?
+* 1972 - Gradual change or violent revolution in Latin America?
+* 1972 - The illusion of unlimited health insurance
+* 1972 - Bibliografía Límites; agosto-septiembre de 1972
+* 1972 - Growth: myth and reality
+
+### Entrevistas
+
+* 1974 - On Growth: Interview with Ivan Illich
+
+### Audiovisuales
+
+* 1978 - The Art of Suffering
+* 1968 - Elspeth Chisholm visits Ivan Illich in Cuernavaca
+* 1968 - Elspeth Chisholm interviews Ivan Illich in Cuernavaca
+* 1969 - CBC Tuesday Night - Visit to Cuernavaca
diff --git a/platform/www/data/pages/es/blog/2024-03-20-apr_02.md b/platform/www/data/pages/es/blog/2024-03-20-apr_02.md
new file mode 100644
index 0000000..f9b64f2
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2024-03-20-apr_02.md
@@ -0,0 +1,34 @@
+~~META:
+date created = 2024-03-20
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #02
+
+This report covers the updates that took place during the last two weeks (2024-03-06 to 2024-03-20).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1973 - Energy and Equity: final draft
+* 1973 - Energie, Vitesse et Justice Sociale
+* 1974 - Energy and Equity
+* 1974 - Les coûts de l'education a vie
+* 1975 - Les enseignants sont-ils necessaires?
+* 1975 - Le piège de l'école à vie
+* 1976 - Imprisoned in the Global Classroom
+* 1976 - Bibliographical Supplement To: Medical Nemesis, Pantheon, 1976 & Limits To Medicine, Boyars, 1976
+* 1976 - Disabling Professions: notes for a lecture
+* 1977 - Useful Unemployment and its Professional Enemies
+* 1977 - L’incompétence spécialisée
+* 1978 - Introducción a "Lo inverso de la salud administrada" de Valentina Borremans
+* 1979 - Von ende des entwicklungsverhabens
+* 1979 - Allocution prononcée lors de la séance de clôture du Colloque International sur l'Informatique et la Société
+
+### Audiovisuals
+
+* 1970 - Ivan Illich at conference called Milieu 70 held in Winnipeg
+* 1971 - The Institutionalization of Truth
diff --git a/platform/www/data/pages/es/blog/2024-04-05-apr_03.md b/platform/www/data/pages/es/blog/2024-04-05-apr_03.md
new file mode 100644
index 0000000..9cb5cf1
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2024-04-05-apr_03.md
@@ -0,0 +1,30 @@
+~~META:
+date created = 2024-04-05
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #03
+
+This report covers the updates that took place during the last two weeks (2024-03-21 to 2024-04-05).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1980 - Alternativas del desarrollo
+* 1980 - Salud y calidad de vida
+* 1980 - Shadow-Work, a draft
+* 1980 - Vernacular Virtue
+* 1980 - Erziehung für ein leben im 7? Stock? Danke, nein!
+* 1981 - Vernacular Gender
+* 1982 - The Right to Dignified Silence
+* 1983 - Dank as die Gastfreunde
+* 1983 - La reivindicación de la casa
+* 1984 - La salud y la calidad de vida en la escasez
+* 1984 - El hedor de la ciudad y sus aguas
+
+### Audiovisuals
+
+* 1971 - Balance and Biosphere
diff --git a/platform/www/data/pages/es/blog/2024-04-20-apr_04.md b/platform/www/data/pages/es/blog/2024-04-20-apr_04.md
new file mode 100644
index 0000000..1a36407
--- /dev/null
+++ b/platform/www/data/pages/es/blog/2024-04-20-apr_04.md
@@ -0,0 +1,31 @@
+~~META:
+date created = 2024-04-20
+~~
+~~NOTOC~~
+
+# Acervus Progress Report #04
+
+This report covers the updates that took place during the last two weeks (2024-04-06 to 2024-04-20).
+
+## Illich Acervus
+
+We added the following source materials to the pile of materials to be processed:
+
+### Articles
+
+* 1984 - Newspeak and uniquack in 1984
+* 1984 - Phaidros
+* 1985 - Tecnológica verde
+* 1985 - La búsqueda de nuevos commons
+* 1985 - Pilgernder und kriegender Individualismus
+* 1985 - Hacia una historia de las necesidades
+* 1985 - Development: metaphor, myth, threat
+* 1986 - My Affair with Education
+* 1987 - Reflections on Jaques Ellul, La subversion du christianisme
+* 1992 - Reading the Intangible
+* 1992 - Lectio divina
+
+### Audiovisuals
+
+* 1971 - Ivan Illich Challenges Education
+* 1972 - Ideas. The Law and Society
diff --git a/platform/www/data/pages/es/index.txt b/platform/www/data/pages/es/index.txt
new file mode 100644
index 0000000..f0572c6
--- /dev/null
+++ b/platform/www/data/pages/es/index.txt
@@ -0,0 +1,28 @@
+~~NOTOC~~
+
+# El Proyecto Acervus
+
+**Una recuperación colectiva de las obras de pensadores y activistas surgidos de la constelación de convivencia en torno a Ivan Illich**
+
+
+La iniciativa tiene un doble propósito: contribuir a la comprensión de la crítica condición actual y al análisis y debate de las opciones existentes, a partir de las aportaciones del círculo de Ivan Illich, y constituir una completa biblioteca digital de su obra de acceso abierto general.
+
+La iniciativa pretende constituir un acervo digital de diferentes autores como Ivan Illich, Jean Robert, Gustavo Esteva y otros. Todo el material se presentará en una plataforma digital especialmente diseñada para facilitar su acceso, referenciación, lectura en diferentes soportes/formatos y reedición en papel por grupos independientes sin ánimo de lucro.
+
+Este espacio virtual se desarrollará utilizando tecnologías de código abierto orientadas a la colaboración, la autopublicación descentralizada y la interacción con los contenidos de diversas formas. Esto permitirá consolidar una fuente fiable, legible y duradera que permitirá acceder a cada obra así como referirse a porciones y extractos específicos.
+
+La biblioteca estará compuesta por los libros, sus diversas versiones en distintos idiomas (identificando si son traducciones directas de otras versiones), recopilaciones, artículos, entrevistas, grabaciones de audio y vídeo. Será una plataforma de publicación dinámica y colaborativa.
+
+**Si desea ponerse en contacto con nosotros, escriba a <info@acerv.us>**
+
+## Novedades
+
+{{blog>es:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display: none !important;
+}
+</style>
+</html>
diff --git a/platform/www/data/pages/fr/index.txt b/platform/www/data/pages/fr/index.txt
new file mode 100644
index 0000000..fe0a0c7
--- /dev/null
+++ b/platform/www/data/pages/fr/index.txt
@@ -0,0 +1,28 @@
+~~NOTOC~~
+
+# Le projet Acervus
+
+**Une récupération collective des travaux de penseurs et d'activistes qui ont émergé de la constellation de convivialité autour d'Ivan Illich**.
+
+
+L'initiative a un double objectif : contribuer à la compréhension de la condition critique actuelle et à l'analyse et au débat des options existantes, sur la base des contributions du cercle d'Ivan Illich, et constituer une bibliothèque numérique complète de son œuvre en libre accès.
+
+L'initiative vise à constituer un acervus numérique de différents auteurs comme Ivan Illich, Jean Robert, Gustavo Esteva et d'autres. Tout le matériel sera présenté sur une plateforme numérique spécialement conçue pour faciliter l'accès, le référencement, la lecture sur différents supports/formats et la réédition sur papier par des groupes indépendants à but non lucratif.
+
+Cet espace virtuel sera développé à l'aide de technologies open source orientées vers la collaboration, l'auto-publication décentralisée et l'interaction avec le contenu de diverses manières. Il sera ainsi possible de consolider une source fiable, lisible et durable qui permettra d'accéder à chaque ouvrage et de se référer à des parties et des extraits spécifiques.
+
+La bibliothèque comprendra les livres, leurs différentes versions dans différentes langues (en identifiant s'il s'agit de traductions directes d'autres versions), des compilations, des articles, des interviews, des enregistrements audio et vidéo. Il s'agira d'une plateforme de publication dynamique et collaborative.
+
+**Si vous souhaitez nous contacter, écrivez-nous à <info@acerv.us>***.
+
+## Mises à jour
+
+{{blog>fr:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display : none !important ;
+}
+</style>
+</html>
diff --git a/platform/www/data/pages/it/index.txt b/platform/www/data/pages/it/index.txt
new file mode 100644
index 0000000..e251332
--- /dev/null
+++ b/platform/www/data/pages/it/index.txt
@@ -0,0 +1,28 @@
+~~NOTOC~~
+
+# Il Progetto Acervus
+
+**Recupero collettivo delle opere di pensatori e attivisti emerse dalla costellazione di convivialità intorno a Ivan Illich**
+
+
+L'iniziativa ha un duplice scopo: contribuire alla comprensione della condizione critica attuale e all'analisi e al dibattito delle opzioni esistenti, sulla base dei contributi della cerchia di Ivan Illich, e costituire una biblioteca digitale completa della sua opera di libero accesso.
+
+L'iniziativa mira a costituire un acervus digitale di diversi autori come Ivan Illich, Jean Robert, Gustavo Esteva e altri. Tutto il materiale sarà presentato in una piattaforma digitale appositamente progettata per un facile accesso, consultazione, lettura in diversi supporti/formati e riedizione cartacea da parte di gruppi indipendenti senza scopo di lucro.
+
+Questo spazio virtuale sarà sviluppato utilizzando tecnologie open source orientate alla collaborazione, all'autopubblicazione decentralizzata e all'interazione con i contenuti in una serie di modi diversi. Ciò consentirà di consolidare una fonte affidabile, leggibile e duratura che permetterà di accedere a ogni opera e di fare riferimento a porzioni ed estratti specifici.
+
+La biblioteca sarà costituita dai libri, dalle loro varie versioni in diverse lingue (identificando se si tratta di traduzioni dirette di altre versioni), da compilazioni, articoli, interviste, registrazioni audio e video. Sarà una piattaforma editoriale dinamica e collaborativa.
+
+**Se volete contattarci, scrivete a <info@acerv.us>**
+
+## Aggiornamenti
+
+{{blog>it:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display: none !important;
+}
+</style>
+</html>
diff --git a/platform/www/data/pages/pt/index.txt b/platform/www/data/pages/pt/index.txt
new file mode 100644
index 0000000..96d2d89
--- /dev/null
+++ b/platform/www/data/pages/pt/index.txt
@@ -0,0 +1,28 @@
+~~NOTOC~~
+
+# O Projeto Acervus
+
+**Uma recuperação colectiva das obras de pensadores e activistas que emergiram da constelação de convívio em torno de Ivan Illich**
+
+
+A iniciativa tem um duplo objetivo: contribuir para a compreensão da condição crítica atual e para a análise e debate das opções existentes, com base nos contributos do círculo de Ivan Illich, e constituir uma biblioteca digital completa da sua obra de acesso aberto geral.
+
+A iniciativa pretende constituir um acervo digital de diferentes autores como Ivan Illich, Jean Robert, Gustavo Esteva e outros. Todo o material será apresentado numa plataforma digital especialmente concebida para facilitar o acesso, a referenciação, a leitura em diferentes suportes/formatos e a reedição em papel por grupos independentes sem fins lucrativos.
+
+Este espaço virtual será desenvolvido com recurso a tecnologias open source orientadas para a colaboração, auto-publicação descentralizada e interação com os conteúdos de diversas formas. Isto permitirá consolidar uma fonte fiável, legível e duradoura que permitirá o acesso a cada obra, bem como a referência a partes e extractos específicos.
+
+A biblioteca será constituída pelos livros, as suas várias versões em diferentes línguas (identificando se são traduções directas de outras versões), compilações, artigos, entrevistas, gravações áudio e vídeo. Será uma plataforma de publicação dinâmica e colaborativa.
+
+**Se quiser contactar-nos, por favor escreva para <info@acerv.us>**
+
+## Actualizações
+
+{{blog>pt:blog?5&firstseconly&readmore}}
+
+<html>
+<style>
+::before {
+ display: none !important;
+}
+</style>
+</html>
diff --git a/platform/www/lib/plugins/blog/action.php b/platform/www/lib/plugins/blog/action.php
index 61ffd9e..2328399 100644
--- a/platform/www/lib/plugins/blog/action.php
+++ b/platform/www/lib/plugins/blog/action.php
@@ -88,8 +88,7 @@ class action_plugin_blog extends DokuWiki_Action_Plugin {
global $ID, $INFO;
$ns = cleanID($_REQUEST['ns']);
- $title = str_replace(':', '', $_REQUEST['title']);
- $ID = $this->_newEntryID($ns, $title);
+ $ID = $this->_newEntryID($ns, $_REQUEST['title']);
$INFO = pageinfo();
// check if we are allowed to create this file
@@ -210,6 +209,7 @@ class action_plugin_blog extends DokuWiki_Action_Plugin {
);
}
$pre = strftime($dateprefix);
+ $title = str_replace([':', ';', '#', '&', '%', '/', '\\', '?'], '', $title);
return cleanID(($ns ? $ns.':' : '').$pre.$title);
}
diff --git a/platform/www/lib/plugins/blog/helper.php b/platform/www/lib/plugins/blog/helper.php
index 9dd8b9a..f29dc7b 100644
--- a/platform/www/lib/plugins/blog/helper.php
+++ b/platform/www/lib/plugins/blog/helper.php
@@ -70,7 +70,7 @@ class helper_plugin_blog extends DokuWiki_Plugin {
// skip drafts unless for users with create priviledge
$meta = p_get_metadata($id, '', false);
- $draft = ($meta['type'] == 'draft');
+ $draft = isset($meta['type']) && ($meta['type'] == 'draft');
if ($draft && ($perm < AUTH_CREATE)) continue;
// filter by author
diff --git a/platform/www/lib/plugins/blog/lang/ca/lang.php b/platform/www/lib/plugins/blog/lang/ca/lang.php
new file mode 100644
index 0000000..9acf319
--- /dev/null
+++ b/platform/www/lib/plugins/blog/lang/ca/lang.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Marc Zulet <marczulet@gmail.com>
+ */
+$lang['blog'] = 'Bloc';
+$lang['older'] = 'Entrades anteriors';
+$lang['newer'] = 'Entrades noves';
+$lang['newentry'] = 'Nova entrada al bloc:';
+$lang['missing_includeplugin'] = 'El plugin Include ha d\'estar instal·lat perquè el bloc funcioni correctament.';
+$lang['missing_pagelistplugin'] = 'El plugin Pagelist ha d\'estar instal·lat perquè funcionin els llistats d\'arxiu.';
+$lang['missing_tagplugin'] = 'El plugin Tag ha d\'estar instal·lat perquè funcionin les etiquetes.';
+$lang['autoarchive'] = '%1$d Publicació(ns) de %2$s %3$s';
+$lang['month_01'] = 'Gener';
+$lang['month_02'] = 'Febrer';
+$lang['month_03'] = 'Març';
+$lang['month_04'] = 'Abril';
+$lang['month_05'] = 'Maig';
+$lang['month_06'] = 'Juny';
+$lang['month_07'] = 'Juliol';
+$lang['month_08'] = 'Agost';
+$lang['month_09'] = 'Setembre';
+$lang['month_10'] = 'Octubre';
+$lang['month_11'] = 'Novembre';
+$lang['month_12'] = 'Desembre';
+$lang['entries'] = 'entrades';
+$lang['entry'] = 'entrada';
+$lang['archive_title'] = 'Històric';
diff --git a/platform/www/lib/plugins/blog/lang/ca/settings.php b/platform/www/lib/plugins/blog/lang/ca/settings.php
new file mode 100644
index 0000000..0f9a49d
--- /dev/null
+++ b/platform/www/lib/plugins/blog/lang/ca/settings.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Marc Zulet <marczulet@gmail.com>
+ */
+$lang['namespace'] = 'namespace predeterminat per al bloc';
+$lang['formposition'] = 'posició del formulari de nova entrada';
+$lang['formposition_o_top'] = 'amunt';
+$lang['formposition_o_bottom'] = 'avall';
+$lang['formposition_o_none'] = 'cap';
+$lang['newentrytitle'] = 'títol del formulari de nova entrada';
+$lang['dateprefix'] = 'afegir un prefix de data a les publicacions noves';
+$lang['sortkey'] = 'ordenar entrades per';
+$lang['sortkey_o_cdate'] = 'data de creació';
+$lang['sortkey_o_mdate'] = 'data de modificació';
+$lang['sortkey_o_pagename'] = 'nom de la pàgina';
+$lang['sortkey_o_id'] = 'ID de la pàgina';
+$lang['sortkey_o_title'] = 'títol';
+$lang['sortorder'] = 'ordre';
+$lang['sortorder_o_ascending'] = 'ascendent';
+$lang['sortorder_o_descending'] = 'descendent';
+$lang['excluded_pages'] = 'exclou determinades pàgines de la llista de blocs (es requereix una expressió regular)';
+$lang['showhistogram'] = 'Mostra l\'histograma en la representació de l\'arxiu';
+$lang['max_months'] = 'Màxim de mesos per mostrar a l\'histograma';
+$lang['histogram_height'] = 'Alçada de l\'histograma (en píxels)';
diff --git a/platform/www/lib/plugins/blog/lang/es/lang.php b/platform/www/lib/plugins/blog/lang/es/lang.php
index 68ef65a..6eba94a 100644
--- a/platform/www/lib/plugins/blog/lang/es/lang.php
+++ b/platform/www/lib/plugins/blog/lang/es/lang.php
@@ -2,8 +2,9 @@
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- *
- * @author Herman Fabián Sandoval Manrique <hfsandovalm@emzac.com>
+ *
+ * @author Marc Zulet <marczulet@gmail.com>
+ * @author Herman Fabián Sandoval Manrique <hfsandovalm@emzac.com>
* @author r0sk <r0sk10@gmail.com>
*/
$lang['blog'] = 'Blog';
@@ -13,6 +14,7 @@ $lang['newentry'] = 'Nueva entrada en el blog:';
$lang['missing_includeplugin'] = 'El plugin Include debe estar instalado para que el blog funcione.';
$lang['missing_pagelistplugin'] = 'El plugin Pagelist debe estar instalado para que funcionen los listados de archivo.';
$lang['missing_tagplugin'] = 'El plugin Tag debe estar instalado para que funcionen los tags.';
+$lang['autoarchive'] = '%1$d Entrada(s) de %2$s %3$s';
$lang['month_01'] = 'Enero';
$lang['month_02'] = 'Febrero';
$lang['month_03'] = 'Marzo';
diff --git a/platform/www/lib/plugins/blog/lang/es/settings.php b/platform/www/lib/plugins/blog/lang/es/settings.php
index d86f15a..05d62f0 100644
--- a/platform/www/lib/plugins/blog/lang/es/settings.php
+++ b/platform/www/lib/plugins/blog/lang/es/settings.php
@@ -2,8 +2,9 @@
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- *
- * @author Herman Fabián Sandoval Manrique <hfsandovalm@emzac.com>
+ *
+ * @author Marc Zulet <marczulet@gmail.com>
+ * @author Herman Fabián Sandoval Manrique <hfsandovalm@emzac.com>
* @author r0sk <r0sk10@gmail.com>
*/
$lang['namespace'] = 'namespace predeterminado para el blog';
@@ -12,6 +13,7 @@ $lang['formposition_o_top'] = 'arriba';
$lang['formposition_o_bottom'] = 'abajo';
$lang['formposition_o_none'] = 'ninguna';
$lang['newentrytitle'] = 'título del formulario de nueva entrada';
+$lang['dateprefix'] = 'prefijar la fecha a los ID de entradas nuevas';
$lang['sortkey'] = 'ordenar entradas por';
$lang['sortkey_o_cdate'] = 'fecha de creación';
$lang['sortkey_o_mdate'] = 'fecha de modificación';
@@ -21,3 +23,7 @@ $lang['sortkey_o_title'] = 'título';
$lang['sortorder'] = 'ordenamiento';
$lang['sortorder_o_ascending'] = 'ascendente';
$lang['sortorder_o_descending'] = 'descendente';
+$lang['excluded_pages'] = 'excluir ciertas páginas de la lista de blogs (se requiere una expresión regular)';
+$lang['showhistogram'] = 'Mostrar histograma en la página del archivo';
+$lang['max_months'] = 'Máximo de meses para mostrar en el histograma';
+$lang['histogram_height'] = 'Altura del histograma (en píxeles)';
diff --git a/platform/www/lib/plugins/blog/lang/pt-br/lang.php b/platform/www/lib/plugins/blog/lang/pt-br/lang.php
index bd219ba..a163727 100644
--- a/platform/www/lib/plugins/blog/lang/pt-br/lang.php
+++ b/platform/www/lib/plugins/blog/lang/pt-br/lang.php
@@ -3,6 +3,7 @@
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
+ * @author Felipo Antonoff <contato@codemarket.com.br>
* @author Flávio Roberto Santos <flavio.barata@gmail.com>
* @author Samory Pereira Santos <samory.santos@gmail.com>
*/
@@ -13,6 +14,7 @@ $lang['newentry'] = 'Novo registro do blog:';
$lang['missing_includeplugin'] = 'O plugin Inlude deve estar instalado para que o blog funcione.';
$lang['missing_pagelistplugin'] = 'O plugin Pagelist deve estar instalado para que a listagem de arquivo funcione,';
$lang['missing_tagplugin'] = 'O plugin Tag deve estar instalado para usar refinamentos de etiquetagem.';
+$lang['autoarchive'] = '%1$d Postagem(s) para %2$s %3$s';
$lang['month_01'] = 'Janeiro';
$lang['month_02'] = 'Fevereiro';
$lang['month_03'] = 'Março';
diff --git a/platform/www/lib/plugins/blog/lang/vi/lang.php b/platform/www/lib/plugins/blog/lang/vi/lang.php
new file mode 100644
index 0000000..a397709
--- /dev/null
+++ b/platform/www/lib/plugins/blog/lang/vi/lang.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Minh <phandinhminh@protonmail.ch>
+ */
+$lang['blog'] = 'Blog';
+$lang['older'] = 'Những bài viết cũ hơn';
+$lang['newer'] = 'Những bài viết mới hơn';
+$lang['newentry'] = 'Mục blog mới:';
+$lang['missing_includeplugin'] = 'Tiện ích Plugin \'Bao gồm\' phải được cài đặt để blog hoạt động.';
+$lang['missing_pagelistplugin'] = 'Tiện ích Plugin \'Danh sách trang\' phải được cài đặt để danh sách lưu trữ hoạt động.';
+$lang['missing_tagplugin'] = 'Tiện ích Plugin \'Tag\' phải được cài đặt để sử dụng sàng lọc Tag.';
+$lang['autoarchive'] = '%1$d (các) bài đăng cho %2$s %3$s';
+$lang['month_01'] = 'Tháng Một';
+$lang['month_02'] = 'Tháng Hai';
+$lang['month_03'] = 'Tháng Ba';
+$lang['month_04'] = 'Tháng Tư';
+$lang['month_05'] = 'Tháng Năm';
+$lang['month_06'] = 'Tháng Sáu';
+$lang['month_07'] = 'Tháng Bảy';
+$lang['month_08'] = 'Tháng Tám';
+$lang['month_09'] = 'Tháng Chín';
+$lang['month_10'] = 'Tháng Mười';
+$lang['month_11'] = 'Tháng Mười Một';
+$lang['month_12'] = 'Tháng Mười Hai';
+$lang['entries'] = 'các mục bài viết';
+$lang['entry'] = 'nhập';
+$lang['archive_title'] = 'Lịch sử Blog';
diff --git a/platform/www/lib/plugins/blog/lang/vi/settings.php b/platform/www/lib/plugins/blog/lang/vi/settings.php
new file mode 100644
index 0000000..a0b7d49
--- /dev/null
+++ b/platform/www/lib/plugins/blog/lang/vi/settings.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Minh <phandinhminh@protonmail.ch>
+ */
+$lang['namespace'] = 'không gian tên namespace mặc định cho blog';
+$lang['formposition'] = 'vị trí của mẫu nhập mới';
+$lang['formposition_o_top'] = 'đầu';
+$lang['formposition_o_bottom'] = 'cuối';
+$lang['formposition_o_none'] = 'trống';
+$lang['newentrytitle'] = 'tiêu đề của mẫu nhập mới';
+$lang['dateprefix'] = 'ngày tiền tố cho ID mục nhập mới';
+$lang['sortkey'] = 'sắp xếp các bài đăng blog theo';
+$lang['sortkey_o_cdate'] = 'ngày tạo';
+$lang['sortkey_o_mdate'] = 'ngày chỉnh sửa';
+$lang['sortkey_o_pagename'] = 'tên trang';
+$lang['sortkey_o_id'] = 'ID trang';
+$lang['sortkey_o_title'] = 'tiêu đề';
+$lang['sortorder'] = 'sắp xếp vị trí';
+$lang['sortorder_o_ascending'] = 'tăng dần';
+$lang['sortorder_o_descending'] = 'giảm dần';
+$lang['excluded_pages'] = 'loại trừ một số trang nhất định khỏi danh sách blog (yêu cầu diễn đạt thông thường)';
+$lang['showhistogram'] = 'Hiển thị biểu đồ trên báo cáo kết xuất lưu trữ';
+$lang['max_months'] = 'Số tháng tối đa để hiển thị trong biểu đồ';
+$lang['histogram_height'] = 'Chiều cao của biểu đồ (tính bằng pixel)';
diff --git a/platform/www/lib/plugins/blog/manager.dat b/platform/www/lib/plugins/blog/manager.dat
deleted file mode 100644
index 1eadc20..0000000
--- a/platform/www/lib/plugins/blog/manager.dat
+++ /dev/null
@@ -1,2 +0,0 @@
-downloadurl=https://github.com/dokufreaks/plugin-blog/archive/master.zip
-installed=Sat, 19 Mar 2022 15:05:39 +0000
diff --git a/platform/www/lib/plugins/blog/plugin.info.txt b/platform/www/lib/plugins/blog/plugin.info.txt
index 73bd83c..8f35668 100644
--- a/platform/www/lib/plugins/blog/plugin.info.txt
+++ b/platform/www/lib/plugins/blog/plugin.info.txt
@@ -2,7 +2,7 @@
base blog
author Michael Hamann, Michael Klier, Gina Haeussge
email michael@content-space.de
-date 2022-02-20
+date 2023-01-12
name Blog
desc Use DokuWiki as blogging tool. (previous authors: Esther Brunner)
url https://www.dokuwiki.org/plugin:blog
diff --git a/platform/www/lib/plugins/blog/syntax/blog.php b/platform/www/lib/plugins/blog/syntax/blog.php
index 2ca56d8..10ab45d 100644
--- a/platform/www/lib/plugins/blog/syntax/blog.php
+++ b/platform/www/lib/plugins/blog/syntax/blog.php
@@ -22,11 +22,11 @@ class syntax_plugin_blog_blog extends DokuWiki_Syntax_Plugin {
global $ID;
$match = substr($match, 7, -2); // strip {{blog> from start and }} from end
- list($match, $flags) = explode('&', $match, 2);
+ list($match, $flags) = array_pad(explode('&', $match, 2), 2, null);
$flags = explode('&', $flags);
array_unshift($flags, 'link'); // always make the first header of a blog entry a permalink (unless nolink is set)
- list($match, $refine) = explode(' ', $match, 2);
- list($ns, $num) = explode('?', $match, 2);
+ list($match, $refine) = array_pad(explode(' ', $match, 2), 2, null);
+ list($ns, $num) = array_pad(explode('?', $match, 2), 2, null);
if (!is_numeric($num)) {
if (is_numeric($ns)) {
@@ -46,9 +46,11 @@ class syntax_plugin_blog_blog extends DokuWiki_Syntax_Plugin {
}
function render($mode, Doku_Renderer $renderer, $data) {
+ global $INPUT;
+
list($ns, $num, $flags, $refine) = $data;
- $first = $_REQUEST['first'];
+ $first = $INPUT->int('first');
if (!is_numeric($first)) $first = 0;
// get the blog entries for our namespace
@@ -114,16 +116,24 @@ class syntax_plugin_blog_blog extends DokuWiki_Syntax_Plugin {
// close current section
if ($clevel && !$include_flags['inline']) $renderer->doc .= '</div>'.DOKU_LF;
- $renderer->doc .= '<div class="hfeed">'.DOKU_LF;
+ $renderer->doc .= '<div class="bloglist hfeed">'.DOKU_LF;
+
+
}
// now include the blog entries
foreach ($entries as $entry) {
if ($mode == 'xhtml' || $mode == 'code') {
- if(auth_quickaclcheck($entry['id']) >= AUTH_READ) {
- // prevent blog include loops
- if(!$this->included_pages[$entry['id']]) {
+ if(isset($entry['id']) && (auth_quickaclcheck($entry['id']) >= AUTH_READ)) {
+ // prevent blog include loop
+
+ // hack to disply formated dates per blog post
+ $d = strftime("%d", $entry['date']);
+ $m = strftime("%m", $entry['date']);
+ $y = strftime("%Y", $entry['date']);
+ $renderer->doc .= "<div class='date-frontpage date'><div class='date-dm'>$d/$m</div><div class='date-y'>$y</div>";
+ if(!array_key_exists($entry['id'], $this->included_pages) || !$this->included_pages[$entry['id']]) {
$this->included_pages[$entry['id']] = true;
$renderer->nest($include->_get_instructions($entry['id'], '', 'page', $clevel, $include_flags));
$this->included_pages[$entry['id']] = false;
diff --git a/platform/www/lib/plugins/include/.github/workflows/phpTestLinux.yml b/platform/www/lib/plugins/include/.github/workflows/phpTestLinux.yml
new file mode 100644
index 0000000..d76e2a9
--- /dev/null
+++ b/platform/www/lib/plugins/include/.github/workflows/phpTestLinux.yml
@@ -0,0 +1,52 @@
+name: PHP Tests on Linux
+
+on: [push, pull_request]
+
+jobs:
+ testLinux:
+ name: PHP ${{ matrix.php-versions }} DokuWiki ${{ matrix.dokuwiki-branch }}
+ runs-on: ubuntu-latest
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
+
+ strategy:
+ matrix:
+ php-versions: ['7.2', '7.3', '7.4', '8.0']
+ dokuwiki-branch: [ 'master', 'stable']
+ exclude:
+ - dokuwiki-branch: 'stable'
+ php-versions: '8.0'
+ fail-fast: false
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: mbstring, intl, PDO, pdo_sqlite, bz2
+
+ - name: Setup problem matchers
+ run: |
+ echo ::add-matcher::${{ runner.tool_cache }}/php.json
+ echo ::add-matcher::${{ runner.tool_cache }}/phpunit.json
+
+ - name: Download DokuWiki Test-setup
+ run: wget https://raw.github.com/splitbrain/dokuwiki-travis/master/travis.sh
+
+ - name: Run DokuWiki Test-setup
+ env:
+ CI_SERVER: 1
+ DOKUWIKI: ${{ matrix.dokuwiki-branch }}
+ run: sh travis.sh
+
+ - name: Setup PHPUnit
+ run: |
+ php _test/fetchphpunit.php
+ cd _test
+
+ - name: Run PHPUnit
+ run: |
+ cd _test
+ php phpunit.phar --verbose --stderr --group plugin_include
diff --git a/platform/www/lib/plugins/include/COPYING b/platform/www/lib/plugins/include/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/platform/www/lib/plugins/include/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/platform/www/lib/plugins/include/README b/platform/www/lib/plugins/include/README
new file mode 100644
index 0000000..0fb6119
--- /dev/null
+++ b/platform/www/lib/plugins/include/README
@@ -0,0 +1,11 @@
+====== Include Plugin for DokuWiki ======
+
+All documentation for the Include Plugin is available online at:
+
+ * http://dokuwiki.org/plugin:include
+
+(c) 2005 - 2007 by Esther Brunner <wikidesign@gmail.com> and Christopher
+Smith <chris@jalakai.co.uk>
+(c) 2008 - 2009 by Gina Häußge, Michael Klier <dokuwiki@chimeric.de>
+(c) 2010 - 2012 by Michael Hamann <michael@content-space.de>, Gina Häußge and Michael Klier <dokuwiki@chimeric.de>
+See COPYING for license info.
diff --git a/platform/www/lib/plugins/include/_test/locallink_conversion.test.php b/platform/www/lib/plugins/include/_test/locallink_conversion.test.php
new file mode 100644
index 0000000..e4c95a3
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/locallink_conversion.test.php
@@ -0,0 +1,42 @@
+<?php
+
+if (!defined('DOKU_INC')) die();
+
+/**
+ * Test the conversion of local links to internal links if the page hasn't been fully included
+ *
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_locallink_conversion_test extends DokuWikiTest {
+ /** @var helper_plugin_include $helper */
+ private $helper;
+
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp();
+
+ $this->helper = plugin_load('helper', 'include');
+
+ saveWikiText('included', 'Example content with link [[#jump]]', 'Test setup');
+ idx_addPage('test:included');
+
+ saveWikiText('test:includefull', '{{page>..:included}}', 'Test setup');
+ idx_addPage('test:includefull');
+
+ saveWikiText('test:includefirst', '{{page>..:included&firstseconly}}', 'Test setup');
+ idx_addPage('test:includefirst');
+ }
+
+ public function testLocalConverted() {
+ $html = p_wiki_xhtml('test:includefirst');
+ $this->assertContains('href="'.wl('included').'#jump"', $html);
+ $this->assertNotContains('href="#jump"', $html);
+ }
+
+ public function testLocalExistsIfIncluded() {
+ $html = p_wiki_xhtml('test:includefull');
+ $this->assertContains('href="#jump"', $html);
+ }
+}
diff --git a/platform/www/lib/plugins/include/_test/media_linktitle_conversion.test.php b/platform/www/lib/plugins/include/_test/media_linktitle_conversion.test.php
new file mode 100644
index 0000000..ea7787f
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/media_linktitle_conversion.test.php
@@ -0,0 +1,54 @@
+<?php
+
+if (!defined('DOKU_INC')) die();
+
+/**
+ * Test the conversion of media references in link titles
+ *
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_media_linktitle_conversion_test extends DokuWikiTest {
+ /** @var helper_plugin_include $helper */
+ private $helper;
+
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp();
+
+ $this->helper = plugin_load('helper', 'include');
+
+ saveWikiText('wiki:included', <<<EOF
+ * [[test|{{dokuwiki.png}}]]
+ * [[#test|{{dokuwiki.png?w=200}}]]
+ * [[doku>test|{{dokuwiki.png?w=300}}]]
+ * [[test|{{https://www.dokuwiki.org/lib/tpl/dokuwiki/images/logo.png}}]]
+EOF
+ , 'Test setup');
+ idx_addPage('wiki:included');
+
+ saveWikiText('test:include', '{{page>..:wiki:included}}', 'Test setup');
+ idx_addPage('test:include');
+ }
+
+ public function testInternalLinkTitleConversion() {
+ $html = p_wiki_xhtml('test:include');
+ $this->assertContains('src="'.ml('wiki:dokuwiki.png').'"', $html);
+ }
+
+ public function testLocalLinkTitleConversion() {
+ $html = p_wiki_xhtml('test:include');
+ $this->assertContains('src="'.ml('wiki:dokuwiki.png', array('w' => '200')).'"', $html);
+ }
+
+ public function testInterWikiLinkTitleConversion() {
+ $html = p_wiki_xhtml('test:include');
+ $this->assertContains('src="'.ml('wiki:dokuwiki.png', array('w' => '300')).'"', $html);
+ }
+
+ public function testExternalMediaNotConverted() {
+ $html = p_wiki_xhtml('test:include');
+ $this->assertContains('src="'.ml('https://www.dokuwiki.org/lib/tpl/dokuwiki/images/logo.png').'"', $html);
+ }
+}
diff --git a/platform/www/lib/plugins/include/_test/namespace_includes.test.php b/platform/www/lib/plugins/include/_test/namespace_includes.test.php
new file mode 100644
index 0000000..1da3234
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/namespace_includes.test.php
@@ -0,0 +1,182 @@
+<?php
+
+if (!defined('DOKU_INC')) die();
+
+/**
+ * Test namespace includes
+ *
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_namespaces_includes_test extends DokuWikiTest {
+ /**
+ * @var helper_plugin_include $helper
+ */
+ private $helper;
+
+ /**
+ * Setup - enable and load the include plugin and create the test pages
+ */
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp(); // this enables the include plugin
+ $this->helper = plugin_load('helper', 'include');
+
+ global $conf;
+ $conf['hidepages'] = 'inclhidden:hidden';
+
+ // for testing hidden pages
+ saveWikiText('inclhidden:hidden', 'Hidden page', 'Created hidden page');
+ saveWikiText('inclhidden:visible', 'Visible page', 'Created visible page');
+
+ // pages on different levels
+ saveWikiText('incltest:level1', 'Page on level 1', 'Created page on level 1');
+ saveWikiText('incltest:ns:level2', 'Page on level 2', 'Created page on level 2');
+ saveWikiText('incltest:ns:ns:level3', 'Page on level 3', 'Created page on level 3');
+
+ // for page ordering
+ saveWikiText('inclorder:page1', 'Page 1', 'Created page 1');
+ saveWikiText('inclorder:page2', 'Page 2', 'Created page 2');
+ saveWikiText('inclorder:page3', '{{include_n>10}} Page 3/10', 'created page 3/1');
+ saveWikiText('inclorder:page4', '{{include_n>2}} Page 4/2', 'created page 4/0');
+ }
+
+ /**
+ * Helper function to read dir content
+ */
+ protected function getDirContent ($dir) {
+ if (is_dir($dir)) {
+ $pages = array();
+ if ($handle = opendir($dir)) {
+ while (($file = readdir($handle)) !== false) {
+ if ($file != '.' && $file != '..') {
+ $pages [] = $file;
+ }
+ }
+ closedir($handle);
+ return $pages;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Test hiding of hidden pages in namespace includes
+ */
+ public function test_hidden() {
+ $flags = $this->helper->get_flags(array());
+ $pages = $this->helper->_get_included_pages('namespace', 'inclhidden:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'inclhidden:visible', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ }
+
+ /**
+ * Test include depth limit
+ */
+ public function test_depth() {
+ $flags = $this->helper->get_flags(array());
+ $pages = $this->helper->_get_included_pages('namespace', 'incltest:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'incltest:level1', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ $flags = $this->helper->get_flags(array('depth=2'));
+ $pages = $this->helper->_get_included_pages('namespace', 'incltest:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'incltest:level1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'incltest:ns:level2', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ $flags = $this->helper->get_flags(array('depth=2'));
+ $pages = $this->helper->_get_included_pages('namespace', 'incltest:ns', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'incltest:ns:level2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'incltest:ns:ns:level3', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ $flags = $this->helper->get_flags(array('depth=0'));
+ $pages = $this->helper->_get_included_pages('namespace', 'incltest:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'incltest:level1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'incltest:ns:level2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'incltest:ns:ns:level3', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+
+ // test include of the root namespace
+ $flags = $this->helper->get_flags(array());
+ $pages = $this->helper->_get_included_pages('namespace', ':', '', '', $flags);
+ $this->assertEquals(array(array('id' => 'mailinglist', 'exists' => true, 'parent_id' => '')), $pages);
+ $flags = $this->helper->get_flags(array('depth=2'));
+ $pages = $this->helper->_get_included_pages('namespace', ':', '', '', $flags);
+ $expected = array(
+ array('id' => 'inclhidden:visible', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page3', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page4', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'incltest:level1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'mailinglist', 'exists' => true, 'parent_id' => ''),
+ //array('id' => 'wiki:dokuwiki', 'exists' => true, 'parent_id' => ''),
+ //array('id' => 'wiki:syntax', 'exists' => true, 'parent_id' => ''),
+ //$wikiPages,
+ );
+
+ // page int:editandsavetest exists in DokuWiki after September 2017
+ if (page_exists('int:editandsavetest')) {
+ $expected [] = array('id' => 'int:editandsavetest', 'exists' => true, 'parent_id' => '');
+ }
+
+ // Add pages in namespace wiki
+ $dir = $this->getDirContent(dirname(__FILE__).'/../../../../_test/data/pages/wiki');
+ $this->assertTrue($dir !== null);
+ foreach ($dir as $page) {
+ $page = substr($page, 0, -4);
+ $expected [] = array('id' => 'wiki:'.$page, 'exists' => true, 'parent_id' => '');
+ }
+
+ array_multisort($expected);
+ array_multisort($pages);
+ $this->assertEquals($expected, $pages);
+ }
+
+ /**
+ * Test ordering of namespace includes
+ */
+ public function test_order() {
+
+ $flags = $this->helper->get_flags(array());
+ $pages = $this->helper->_get_included_pages('namespace', 'inclorder:', '', '', $flags);
+
+ $this->assertEquals(array(
+ array('id' => 'inclorder:page1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page3', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page4', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+
+ $flags = $this->helper->get_flags(array('rsort'));
+ $pages = $this->helper->_get_included_pages('namespace', 'inclorder:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'inclorder:page4', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page3', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page1', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ $flags = $this->helper->get_flags(array('order=custom'));
+ $pages = $this->helper->_get_included_pages('namespace', 'inclorder:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'inclorder:page4', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page3', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page2', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+
+ $flags = $this->helper->get_flags(array('order=custom', 'rsort'));
+ $pages = $this->helper->_get_included_pages('namespace', 'inclorder:', '', '', $flags);
+ $this->assertEquals(array(
+ array('id' => 'inclorder:page2', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page1', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page3', 'exists' => true, 'parent_id' => ''),
+ array('id' => 'inclorder:page4', 'exists' => true, 'parent_id' => ''),
+ ), $pages);
+ }
+}
diff --git a/platform/www/lib/plugins/include/_test/nested_include.test.php b/platform/www/lib/plugins/include/_test/nested_include.test.php
new file mode 100644
index 0000000..745f180
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/nested_include.test.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Class plugin_include_nested_test
+ *
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_nested_test extends DokuWikiTest {
+ private $ids = array(
+ 'test:plugin_include:nested:start',
+ 'test:plugin_include:nested:second',
+ 'test:plugin_include:nested:third'
+ );
+
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp();
+ }
+
+ public function test_outer_to_inner() {
+ $this->_createPages();
+ $mainHTML = p_wiki_xhtml('test:plugin_include:nested:start');
+ $secondHTML = p_wiki_xhtml('test:plugin_include:nested:second');
+ $thirdHTML = p_wiki_xhtml('test:plugin_include:nested:third');
+ $this->_validateContent($mainHTML, $secondHTML, $thirdHTML);
+ }
+
+ public function test_inner_to_outer() {
+ $this->_createPages();
+ $thirdHTML = p_wiki_xhtml('test:plugin_include:nested:third');
+ $secondHTML = p_wiki_xhtml('test:plugin_include:nested:second');
+ $mainHTML = p_wiki_xhtml('test:plugin_include:nested:start');
+ $this->_validateContent($mainHTML, $secondHTML, $thirdHTML);
+ }
+
+ private function _validateContent($mainHTML, $secondHTML, $thirdHTML) {
+ $this->assertTrue(strpos($mainHTML, 'Main Content') !== false, 'Main content contains "Main Content"');
+ $this->assertTrue($this->_matchHeader('1', 'Main Test Page', $mainHTML), 'Main page header is h1');
+ $this->assertTrue(strpos($mainHTML, 'Second Content') !== false, 'Main content contains "Second Content"');
+ $this->assertTrue($this->_matchHeader('2', 'Second Test Page', $mainHTML), 'Second page header on main page is h2');
+ $this->assertTrue(strpos($mainHTML, 'Third Content') !== false, 'Main content contains "Third Content"');
+ $this->assertTrue($this->_matchHeader('3', 'Third Test Page', $mainHTML), 'Third page header on main page is h3');
+ $this->assertTrue(strpos($secondHTML, 'Second Content') !== false, 'Second content contains "Second Content"');
+ $this->assertTrue($this->_matchHeader('1', 'Second Test Page', $secondHTML), 'Second page header on second page is h1');
+ $this->assertTrue(strpos($secondHTML, 'Third Content') !== false, 'Second content contains "Third Content"');
+ $this->assertTrue($this->_matchHeader('2', 'Third Test Page', $secondHTML), 'Third page header on second page is h2');
+ $this->assertTrue(strpos($thirdHTML, 'Third Content') !== false, 'Third content contains "Third Content"');
+ $this->assertTrue($this->_matchHeader('1', 'Third Test Page', $thirdHTML), 'Third page header on third page is h1');
+ }
+
+ private function _matchHeader($level, $text, $html) {
+ return preg_match('/<h'.$level.'[^>]*>(<a[^>]*>)?'.$text.'/', $html) > 0;
+ }
+
+ private function _createPages() {
+ saveWikiText('test:plugin_include:nested:start',
+ '====== Main Test Page ======'.DOKU_LF.DOKU_LF
+ .'Main Content'.rand().DOKU_LF.DOKU_LF
+ .'{{page>second}}'.DOKU_LF,
+ 'setup for test');
+ saveWikiText('test:plugin_include:nested:second',
+ '====== Second Test Page ======'.DOKU_LF.DOKU_LF
+ .'Second Content'.rand().DOKU_LF.DOKU_LF
+ .'{{page>third}}'.DOKU_LF,
+ 'setup for test');
+ saveWikiText('test:plugin_include:nested:third',
+ '====== Third Test Page ======'.DOKU_LF.DOKU_LF
+ .'Third Content'.rand().DOKU_LF.DOKU_LF
+ .'{{page>third}}'.DOKU_LF,
+ 'setup for test');
+ }
+}
+
diff --git a/platform/www/lib/plugins/include/_test/pagemove_support.test.php b/platform/www/lib/plugins/include/_test/pagemove_support.test.php
new file mode 100644
index 0000000..58c9425
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/pagemove_support.test.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Tests the move support for adapting the syntax of the include plugin
+ *
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_pagemove_support_test extends DokuWikiTest {
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'move';
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp();
+ }
+
+ public function test_relative_include() {
+ /** @var $move helper_plugin_move_op */
+ $move = plugin_load('helper', 'move_op');
+ if (!$move) {
+ $this->markTestSkipped('the move plugin is not installed');
+ return;
+ }
+ saveWikiText('editx', '{{page>start#start}} %%{{page>start}}%% {{section>wiki:syntax#tables&nofooter}} {{page>:}} {{section>test:start#test}}', 'Testcase created');
+ idx_addPage('editx');
+ $this->assertTrue($move->movePage('editx', 'test:editx'));
+ $this->assertEquals('{{page>:start#start}} %%{{page>start}}%% {{section>wiki:syntax#tables&nofooter}} {{page>:}} {{section>test:start#test}}',rawWiki('test:editx'));
+ }
+
+ public function test_rename() {
+ /** @var $move helper_plugin_move_op */
+ $move = plugin_load('helper', 'move_op');
+ if (!$move) {
+ $this->markTestSkipped('the move plugin is not installed');
+ return;
+ }
+ saveWikiText('editx', 'Page to rename', 'Testcase create');
+ saveWikiText('links', '{{section>links#foo}} {{page>editx}} {{page>:eDitX&nofooter}} {{section>editx#test}} {{page>editx&nofooter}}', 'Testcase created');
+ idx_addPage('editx');
+ idx_addPage('links');
+
+ $this->assertTrue($move->movePage('editx', 'test:edit'));
+ $this->assertEquals('{{section>links#foo}} {{page>test:edit}} {{page>test:edit&nofooter}} {{section>test:edit#test}} {{page>test:edit&nofooter}}', rawWiki('links'));
+ }
+
+ public function test_relative_include_adaption() {
+ /** @var $move helper_plugin_move_op */
+ $move = plugin_load('helper', 'move_op');
+ if (!$move) {
+ $this->markTestSkipped('the move plugin is not installed');
+ return;
+ }
+
+ $text = '====== Main ======
+
+This is a test page
+
+[[.1:page_1|link]]
+
+{{page>.1:page_1&nofooter&noeditbutton}}
+
+{{page>.1:page_2&nofooter&noeditbutton}}';
+
+ saveWikiText('old:namespace:main', $text, 'Created');
+ saveWikiText('old:namespace:1:page_1', 'Page 1', 'Created');
+ saveWikiText('old:namespace:1:page_2', 'Page 2', 'Created');
+ idx_addPage('old:namespace:main');
+ idx_addPage('old:namespace:1:page_1');
+ idx_addPage('old:namespace:1:page_2');
+
+ $this->assertTrue($move->movePage('old:namespace:main', 'new:namespace:main'));
+ $this->assertTrue($move->movePage('old:namespace:1:page_1', 'new:namespace:1:page_1'));
+ $this->assertTrue($move->movePage('old:namespace:1:page_2', 'new:namespace:1:page_2'));
+ $this->assertEquals($text, rawWiki('new:namespace:main'));
+ }
+}
diff --git a/platform/www/lib/plugins/include/_test/safeindex.test.php b/platform/www/lib/plugins/include/_test/safeindex.test.php
new file mode 100644
index 0000000..247c7e6
--- /dev/null
+++ b/platform/www/lib/plugins/include/_test/safeindex.test.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * @group plugin_include
+ * @group plugins
+ */
+class plugin_include_safeindex_test extends DokuWikiTest {
+ public function setUp() : void
+ {
+ $this->pluginsEnabled[] = 'include';
+ parent::setUp();
+ }
+
+ public function test_safeindex() {
+ global $conf;
+ global $AUTH_ACL;
+ $conf['superuser'] = 'john';
+ $conf['useacl'] = 1;
+
+ $AUTH_ACL = array(
+ '* @ALL 0',
+ '* @user 8',
+ 'public @ALL 1',
+ );
+
+ $_SERVER['REMOTE_USER'] = 'john';
+
+ saveWikiText('parent', "{{page>child}}\n\n[[public_link]]\n\n{{page>public}}", 'Test parent created');
+ saveWikiText('child', "[[foo:private]]", 'Test child created');
+ saveWikiText('public', "[[foo:public]]", 'Public page created');
+
+ idx_addPage('parent');
+ idx_addPage('child');
+ idx_addPage('public');
+
+ $this->assertEquals(array('parent', 'public'), ft_backlinks('foo:public'));
+ $this->assertEquals(array('child'), ft_backlinks('foo:private'));
+ $this->assertEquals(array('parent'), ft_backlinks('public_link'));
+ }
+}
+
diff --git a/platform/www/lib/plugins/include/action.php b/platform/www/lib/plugins/include/action.php
new file mode 100644
index 0000000..b5388ba
--- /dev/null
+++ b/platform/www/lib/plugins/include/action.php
@@ -0,0 +1,370 @@
+<?php
+/**
+ * Include Plugin: Display a wiki page within another wiki page
+ *
+ * Action plugin component, for cache validity determination
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @author Michael Klier <chi@chimeric.de>
+ */
+
+/**
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ */
+class action_plugin_include extends DokuWiki_Action_Plugin {
+
+ /* @var helper_plugin_include $helper */
+ var $helper = null;
+
+ function __construct() {
+ $this->helper = plugin_load('helper', 'include');
+ }
+
+ /**
+ * plugin should use this method to register its handlers with the dokuwiki's event controller
+ */
+ function register(Doku_Event_Handler $controller) {
+ /* @var Doku_event_handler $controller */
+ $controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, 'handle_indexer');
+ $controller->register_hook('INDEXER_VERSION_GET', 'BEFORE', $this, 'handle_indexer_version');
+ $controller->register_hook('PARSER_CACHE_USE','BEFORE', $this, '_cache_prepare');
+ $controller->register_hook('HTML_EDITFORM_OUTPUT', 'BEFORE', $this, 'handle_form'); // todo remove
+ $controller->register_hook('FORM_EDIT_OUTPUT', 'BEFORE', $this, 'handle_form');
+ $controller->register_hook('HTML_CONFLICTFORM_OUTPUT', 'BEFORE', $this, 'handle_form'); // todo remove
+ $controller->register_hook('FORM_CONFLICT_OUTPUT', 'BEFORE', $this, 'handle_form');
+ $controller->register_hook('HTML_DRAFTFORM_OUTPUT', 'BEFORE', $this, 'handle_form'); // todo remove
+ $controller->register_hook('FORM_DRAFT_OUTPUT', 'BEFORE', $this, 'handle_form');
+ $controller->register_hook('ACTION_SHOW_REDIRECT', 'BEFORE', $this, 'handle_redirect');
+ $controller->register_hook('PARSER_HANDLER_DONE', 'BEFORE', $this, 'handle_parser');
+ $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, 'handle_metadata');
+ $controller->register_hook('HTML_SECEDIT_BUTTON', 'BEFORE', $this, 'handle_secedit_button');
+ $controller->register_hook('PLUGIN_MOVE_HANDLERS_REGISTER', 'BEFORE', $this, 'handle_move_register');
+ }
+
+ /**
+ * Add a version string to the index so it is rebuilt
+ * whenever the handler is updated or the safeindex setting is changed
+ */
+ public function handle_indexer_version($event, $param) {
+ $event->data['plugin_include'] = '0.1.safeindex='.$this->getConf('safeindex');
+ }
+
+ /**
+ * Handles the INDEXER_PAGE_ADD event, prevents indexing of metadata from included pages that aren't public if enabled
+ *
+ * @param Doku_Event $event the event object
+ * @param array $params optional parameters (unused)
+ */
+ public function handle_indexer(Doku_Event $event, $params) {
+ global $USERINFO;
+
+ // check if the feature is enabled at all
+ if (!$this->getConf('safeindex')) return;
+
+ // is there a user logged in at all? If not everything is fine already
+ if (is_null($USERINFO) && !isset($_SERVER['REMOTE_USER'])) return;
+
+ // get the include metadata in order to see which pages were included
+ $inclmeta = p_get_metadata($event->data['page'], 'plugin_include', METADATA_RENDER_UNLIMITED);
+ $all_public = true; // are all included pages public?
+ // check if the current metadata indicates that non-public pages were included
+ if ($inclmeta !== null && isset($inclmeta['pages'])) {
+ foreach ($inclmeta['pages'] as $page) {
+ if (auth_aclcheck($page['id'], '', array()) < AUTH_READ) { // is $page public?
+ $all_public = false;
+ break;
+ }
+ }
+ }
+
+ if (!$all_public) { // there were non-public pages included - action required!
+ // backup the user information
+ $userinfo_backup = $USERINFO;
+ $remote_user = $_SERVER['REMOTE_USER'];
+ // unset user information - temporary logoff!
+ $USERINFO = null;
+ unset($_SERVER['REMOTE_USER']);
+
+ // metadata is only rendered once for a page in one request - thus we need to render manually.
+ $meta = p_read_metadata($event->data['page']); // load the original metdata
+ $meta = p_render_metadata($event->data['page'], $meta); // render the metadata
+ p_save_metadata($event->data['page'], $meta); // save the metadata so other event handlers get the public metadata, too
+
+ $meta = $meta['current']; // we are only interested in current metadata.
+
+ // check if the tag plugin handler has already been called before the include plugin
+ $tag_called = isset($event->data['metadata']['subject']);
+
+ // Reset the metadata in the renderer. This removes data from all other event handlers, but we need to be on the safe side here.
+ $event->data['metadata'] = array('title' => $meta['title']);
+
+ // restore the relation references metadata
+ if (isset($meta['relation']['references'])) {
+ $event->data['metadata']['relation_references'] = array_keys($meta['relation']['references']);
+ } else {
+ $event->data['metadata']['relation_references'] = array();
+ }
+
+ // restore the tag metadata if the tag plugin handler has been called before the include plugin handler.
+ if ($tag_called) {
+ $tag_helper = $this->loadHelper('tag', false);
+ if ($tag_helper) {
+ if (isset($meta['subject'])) {
+ $event->data['metadata']['subject'] = $tag_helper->_cleanTagList($meta['subject']);
+ } else {
+ $event->data['metadata']['subject'] = array();
+ }
+ }
+ }
+
+ // restore user information
+ $USERINFO = $userinfo_backup;
+ $_SERVER['REMOTE_USER'] = $remote_user;
+ }
+ }
+
+ /**
+ * Used for debugging purposes only
+ */
+ function handle_metadata(&$event, $param) {
+ global $conf;
+ if($conf['allowdebug'] && $this->getConf('debugoutput')) {
+ dbglog('---- PLUGIN INCLUDE META DATA START ----');
+ dbglog($event->data);
+ dbglog('---- PLUGIN INCLUDE META DATA END ----');
+ }
+ }
+
+ /**
+ * Supplies the current section level to the include syntax plugin
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function handle_parser(Doku_Event $event, $param) {
+ global $ID;
+
+ $level = 0;
+ $ins =& $event->data->calls;
+ $num = count($ins);
+ for($i=0; $i<$num; $i++) {
+ switch($ins[$i][0]) {
+ case 'plugin':
+ switch($ins[$i][1][0]) {
+ case 'include_include':
+ $ins[$i][1][1][4] = $level;
+ break;
+ /* FIXME: this doesn't work anymore that way with the new structure
+ // some plugins already close open sections
+ // so we need to make sure we don't close them twice
+ case 'box':
+ $this->helper->sec_close = false;
+ break;
+ */
+ }
+ break;
+ case 'section_open':
+ $level = $ins[$i][1][0];
+ break;
+ }
+ }
+ }
+
+ /**
+ * Add a hidden input to the form to preserve the redirect_id
+ */
+ function handle_form(Doku_Event $event, $param)
+ {
+ if (!array_key_exists('redirect_id', $_REQUEST)) return;
+
+ if(is_a($event->data, \dokuwiki\Form\Form::class)) {
+ $event->data->setHiddenField('redirect_id', cleanID($_REQUEST['redirect_id']));
+ } else {
+ // todo remove when old FORM events are no longer supported
+ $event->data->addHidden('redirect_id', cleanID($_REQUEST['redirect_id']));
+ }
+ }
+
+ /**
+ * Modify the data for the redirect when there is a redirect_id set
+ */
+ function handle_redirect(Doku_Event &$event, $param) {
+ if (array_key_exists('redirect_id', $_REQUEST)) {
+ // Render metadata when this is an older DokuWiki version where
+ // metadata is not automatically re-rendered as the page has probably
+ // been changed but is not directly displayed
+ $versionData = getVersionData();
+ if ($versionData['date'] < '2010-11-23') {
+ p_set_metadata($event->data['id'], array(), true);
+ }
+ $event->data['id'] = cleanID($_REQUEST['redirect_id']);
+ $event->data['title'] = '';
+ }
+ }
+
+ /**
+ * prepare the cache object for default _useCache action
+ */
+ function _cache_prepare(Doku_Event &$event, $param) {
+ global $conf;
+
+ /* @var cache_renderer $cache */
+ $cache =& $event->data;
+
+ if(!isset($cache->page)) return;
+ if(!isset($cache->mode) || $cache->mode == 'i') return;
+
+ $depends = p_get_metadata($cache->page, 'plugin_include');
+
+ if($conf['allowdebug'] && $this->getConf('debugoutput')) {
+ dbglog('---- PLUGIN INCLUDE CACHE DEPENDS START ----');
+ dbglog($depends);
+ dbglog('---- PLUGIN INCLUDE CACHE DEPENDS END ----');
+ }
+
+ if (!is_array($depends)) return; // nothing to do for us
+
+ if (!is_array($depends['pages']) ||
+ !is_array($depends['instructions']) ||
+ $depends['pages'] != $this->helper->_get_included_pages_from_meta_instructions($depends['instructions']) ||
+ // the include_content url parameter may change the behavior for included pages
+ $depends['include_content'] != isset($_REQUEST['include_content'])) {
+
+ $cache->depends['purge'] = true; // included pages changed or old metadata - request purge.
+ if($conf['allowdebug'] && $this->getConf('debugoutput')) {
+ dbglog('---- PLUGIN INCLUDE: REQUESTING CACHE PURGE ----');
+ dbglog('---- PLUGIN INCLUDE CACHE PAGES FROM META START ----');
+ dbglog($depends['pages']);
+ dbglog('---- PLUGIN INCLUDE CACHE PAGES FROM META END ----');
+ dbglog('---- PLUGIN INCLUDE CACHE PAGES FROM META_INSTRUCTIONS START ----');
+ dbglog($this->helper->_get_included_pages_from_meta_instructions($depends['instructions']));
+ dbglog('---- PLUGIN INCLUDE CACHE PAGES FROM META_INSTRUCTIONS END ----');
+
+ }
+ } else {
+ // add plugin.info.txt to depends for nicer upgrades
+ $cache->depends['files'][] = dirname(__FILE__) . '/plugin.info.txt';
+ foreach ($depends['pages'] as $page) {
+ if (!$page['exists']) continue;
+ $file = wikiFN($page['id']);
+ if (!in_array($file, $cache->depends['files'])) {
+ $cache->depends['files'][] = $file;
+ }
+ }
+ }
+ }
+
+ /**
+ * Handle special section edit buttons for the include plugin to get the current page
+ * and replace normal section edit buttons when the current page is different from the
+ * global $ID.
+ */
+ function handle_secedit_button(Doku_Event &$event, $params) {
+ // stack of included pages in the form ('id' => page, 'rev' => modification time, 'writable' => bool)
+ static $page_stack = array();
+
+ global $ID, $lang;
+
+ $data = $event->data;
+
+ if ($data['target'] == 'plugin_include_start' || $data['target'] == 'plugin_include_start_noredirect') {
+ // handle the "section edits" added by the include plugin
+ $fn = wikiFN($data['name']);
+ $perm = auth_quickaclcheck($data['name']);
+ array_unshift($page_stack, array(
+ 'id' => $data['name'],
+ 'rev' => @filemtime($fn),
+ 'writable' => (page_exists($data['name']) ? (is_writable($fn) && $perm >= AUTH_EDIT) : $perm >= AUTH_CREATE),
+ 'redirect' => ($data['target'] == 'plugin_include_start'),
+ ));
+ } elseif ($data['target'] == 'plugin_include_end') {
+ array_shift($page_stack);
+ } elseif ($data['target'] == 'plugin_include_editbtn') {
+ if ($page_stack[0]['writable']) {
+ $params = array('do' => 'edit',
+ 'id' => $page_stack[0]['id']);
+ if ($page_stack[0]['redirect']) {
+ $params['redirect_id'] = $ID;
+ $params['hid'] = $data['hid'];
+ }
+ $event->result = '<div class="secedit">' . DOKU_LF .
+ html_btn('incledit', $page_stack[0]['id'], '',
+ $params, 'post',
+ $data['name'],
+ $lang['btn_secedit'].' ('.$page_stack[0]['id'].')') .
+ '</div>' . DOKU_LF;
+ }
+ } elseif (!empty($page_stack)) {
+
+ // Special handling for the edittable plugin
+ if ($data['target'] == 'table' && !plugin_isdisabled('edittable')) {
+ /* @var action_plugin_edittable_editor $edittable */
+ $edittable = plugin_load('action', 'edittable_editor');
+ if (is_null($edittable))
+ $edittable = plugin_load('action', 'edittable');
+ $data['name'] = $edittable->getLang('secedit_name');
+ }
+
+ if ($page_stack[0]['writable'] && isset($data['name']) && $data['name'] !== '') {
+ $name = $data['name'];
+ unset($data['name']);
+
+ $secid = $data['secid'];
+ unset($data['secid']);
+
+ if ($page_stack[0]['redirect'])
+ $data['redirect_id'] = $ID;
+
+ $event->result = "<div class='secedit editbutton_" . $data['target'] .
+ " editbutton_" . $secid . "'>" .
+ html_btn('secedit', $page_stack[0]['id'], '',
+ array_merge(array('do' => 'edit',
+ 'rev' => $page_stack[0]['rev'],
+ 'summary' => '['.$name.'] '), $data),
+ 'post', $name) . '</div>';
+ } else {
+ $event->result = '';
+ }
+ } else {
+ return; // return so the event won't be stopped
+ }
+
+ $event->preventDefault();
+ $event->stopPropagation();
+ }
+
+ public function handle_move_register(Doku_Event $event, $params) {
+ $event->data['handlers']['include_include'] = array($this, 'rewrite_include');
+ }
+
+ public function rewrite_include($match, $pos, $state, $plugin, helper_plugin_move_handler $handler) {
+ $syntax = substr($match, 2, -2); // strip markup
+ $replacers = explode('|', $syntax);
+ $syntax = array_shift($replacers);
+ list($syntax, $flags) = array_pad(explode('&', $syntax, 2), 2, "");
+
+ // break the pattern up into its parts
+ list($mode, $page, $sect) = array_pad(preg_split('/>|#/u', $syntax, 3), 3, "");
+
+ if (method_exists($handler, 'adaptRelativeId')) { // move plugin before version 2015-05-16
+ $newpage = $handler->adaptRelativeId($page);
+ } else {
+ $newpage = $handler->resolveMoves($page, 'page');
+ $newpage = $handler->relativeLink($page, $newpage, 'page');
+ }
+
+ if ($newpage == $page) {
+ return $match;
+ } else {
+ $result = '{{'.$mode.'>'.$newpage;
+ if ($sect) $result .= '#'.$sect;
+ if ($flags) $result .= '&'.$flags;
+ if ($replacers) $result .= '|'.$replacers;
+ $result .= '}}';
+ return $result;
+ }
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/conf/default.php b/platform/www/lib/plugins/include/conf/default.php
new file mode 100644
index 0000000..c619005
--- /dev/null
+++ b/platform/www/lib/plugins/include/conf/default.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Options for the Include Plugin
+ */
+$conf['noheader'] = 0; // Don't display the header of the inserted section
+$conf['firstseconly'] = 0; // limit entries on main blog page to first section
+$conf['showtaglogos'] = 0; // display image for first tag
+$conf['showfooter'] = 1; // display meta line below blog entries
+$conf['showlink'] = 0; // link headlines of blog entries
+$conf['showpermalink'] = 0; // show permalink below blog entries
+$conf['showdate'] = 1; // show date below blog entries
+$conf['showmdate'] = 0; // show modification date below blog entries
+$conf['showuser'] = 1; // show username below blog entries
+$conf['showcomments'] = 1; // show number of comments below blog entries
+$conf['showlinkbacks'] = 1; // show number of linkbacks below blog entries
+$conf['showtags'] = 1; // show tags below blog entries
+$conf['showeditbtn'] = 1; // show the edit button
+$conf['doredirect'] = 1; // redirect back to original page after an edit
+$conf['doindent'] = 1; // indent included pages relative to the page they get included
+$conf['linkonly'] = 0; // link only to the included pages instead of including the content
+$conf['title'] = 0; // use first header of page in link
+$conf['pageexists'] = 0; // no link if page does not exist
+$conf['parlink'] = 1; // paragraph around link
+$conf['safeindex'] = 1; // prevent indexing of protected metadata
+$conf['order'] = 'id'; // order in which the pages are included in the case of multiple pages
+$conf['rsort'] = 0; // reverse sort order
+$conf['depth'] = 1; // maximum depth of namespace includes, 0 for unlimited depth
+$conf['readmore'] = 1; // Show readmore link in case of firstsection only
+$conf['debugoutput'] = 0; // print debug information to debuglog if global allowdebug is enabled
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/conf/metadata.php b/platform/www/lib/plugins/include/conf/metadata.php
new file mode 100644
index 0000000..a0fa7b1
--- /dev/null
+++ b/platform/www/lib/plugins/include/conf/metadata.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Metadata for configuration manager plugin
+ * Additions for the Include Plugin
+ *
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+$meta['noheader'] = array('onoff');
+$meta['firstseconly'] = array('onoff');
+$meta['showtaglogos'] = array('onoff');
+$meta['showlink'] = array('onoff');
+$meta['showfooter'] = array('onoff');
+$meta['showpermalink'] = array('onoff');
+$meta['showdate'] = array('onoff');
+$meta['showmdate'] = array('onoff');
+$meta['showuser'] = array('onoff');
+$meta['showcomments'] = array('onoff');
+$meta['showlinkbacks'] = array('onoff');
+$meta['showtags'] = array('onoff');
+$meta['showeditbtn'] = array('onoff');
+$meta['doredirect'] = array('onoff');
+$meta['doindent'] = array('onoff');
+$meta['linkonly'] = array('onoff');
+$meta['title'] = array('onoff');
+$meta['pageexists'] = array('onoff');
+$meta['parlink'] = array('onoff');
+$meta['safeindex'] = array('onoff');
+$meta['order'] = array('multichoice', '_choices' => array('id', 'title', 'created', 'modified', 'indexmenu', 'custom'));
+$meta['rsort'] = array('onoff');
+$meta['depth'] = array('numeric', '_min' => 0);
+$meta['readmore'] = array('onoff');
+$meta['debugoutput'] = array('onoff');
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/deleted.files b/platform/www/lib/plugins/include/deleted.files
new file mode 100644
index 0000000..518236e
--- /dev/null
+++ b/platform/www/lib/plugins/include/deleted.files
@@ -0,0 +1,13 @@
+.travis.yaml
+lang/sl-si/lang.php
+lang/sl-si/settings.php
+_test/editx_support.test.php
+_test/include.group.php
+syntax/close_last_secedit.php
+syntax/div.php
+syntax/meta.php
+VERSION
+syntax.php
+images/tag.gif
+inc/include.php
+.travis.yml
diff --git a/platform/www/lib/plugins/include/helper.php b/platform/www/lib/plugins/include/helper.php
new file mode 100644
index 0000000..ebde44f
--- /dev/null
+++ b/platform/www/lib/plugins/include/helper.php
@@ -0,0 +1,941 @@
+<?php
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @author Gina Häußge, Michael Klier <dokuwiki@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+
+/**
+ * Helper functions for the include plugin and other plugins that want to include pages.
+ */
+class helper_plugin_include extends DokuWiki_Plugin { // DokuWiki_Helper_Plugin
+
+ var $defaults = array();
+ var $sec_close = true;
+ /** @var helper_plugin_tag $taghelper */
+ var $taghelper = null;
+ var $includes = array(); // deprecated - compatibility code for the blog plugin
+
+ /**
+ * Constructor loads default config settings once
+ */
+ function __construct() {
+ $this->defaults['noheader'] = $this->getConf('noheader');
+ $this->defaults['firstsec'] = $this->getConf('firstseconly');
+ $this->defaults['editbtn'] = $this->getConf('showeditbtn');
+ $this->defaults['taglogos'] = $this->getConf('showtaglogos');
+ $this->defaults['footer'] = $this->getConf('showfooter');
+ $this->defaults['redirect'] = $this->getConf('doredirect');
+ $this->defaults['date'] = $this->getConf('showdate');
+ $this->defaults['mdate'] = $this->getConf('showmdate');
+ $this->defaults['user'] = $this->getConf('showuser');
+ $this->defaults['comments'] = $this->getConf('showcomments');
+ $this->defaults['linkbacks'] = $this->getConf('showlinkbacks');
+ $this->defaults['tags'] = $this->getConf('showtags');
+ $this->defaults['link'] = $this->getConf('showlink');
+ $this->defaults['permalink'] = $this->getConf('showpermalink');
+ $this->defaults['indent'] = $this->getConf('doindent');
+ $this->defaults['linkonly'] = $this->getConf('linkonly');
+ $this->defaults['title'] = $this->getConf('title');
+ $this->defaults['pageexists'] = $this->getConf('pageexists');
+ $this->defaults['parlink'] = $this->getConf('parlink');
+ $this->defaults['inline'] = false;
+ $this->defaults['order'] = $this->getConf('order');
+ $this->defaults['rsort'] = $this->getConf('rsort');
+ $this->defaults['depth'] = $this->getConf('depth');
+ $this->defaults['readmore'] = $this->getConf('readmore');
+ }
+
+ /**
+ * Available methods for other plugins
+ */
+ function getMethods() {
+ $result = array();
+ $result[] = array(
+ 'name' => 'get_flags',
+ 'desc' => 'overrides standard values for showfooter and firstseconly settings',
+ 'params' => array('flags' => 'array'),
+ );
+ return $result;
+ }
+
+ /**
+ * Overrides standard values for showfooter and firstseconly settings
+ */
+ function get_flags($setflags) {
+ // load defaults
+ $flags = $this->defaults;
+ foreach ($setflags as $flag) {
+ $value = '';
+ if (strpos($flag, '=') !== false) {
+ list($flag, $value) = explode('=', $flag, 2);
+ }
+ switch ($flag) {
+ case 'footer':
+ $flags['footer'] = 1;
+ break;
+ case 'nofooter':
+ $flags['footer'] = 0;
+ break;
+ case 'firstseconly':
+ case 'firstsectiononly':
+ $flags['firstsec'] = 1;
+ break;
+ case 'fullpage':
+ $flags['firstsec'] = 0;
+ break;
+ case 'showheader':
+ case 'header':
+ $flags['noheader'] = 0;
+ break;
+ case 'noheader':
+ $flags['noheader'] = 1;
+ break;
+ case 'editbtn':
+ case 'editbutton':
+ $flags['editbtn'] = 1;
+ break;
+ case 'noeditbtn':
+ case 'noeditbutton':
+ $flags['editbtn'] = 0;
+ break;
+ case 'permalink':
+ $flags['permalink'] = 1;
+ break;
+ case 'nopermalink':
+ $flags['permalink'] = 0;
+ break;
+ case 'redirect':
+ $flags['redirect'] = 1;
+ break;
+ case 'noredirect':
+ $flags['redirect'] = 0;
+ break;
+ case 'link':
+ $flags['link'] = 1;
+ break;
+ case 'nolink':
+ $flags['link'] = 0;
+ break;
+ case 'user':
+ $flags['user'] = 1;
+ break;
+ case 'nouser':
+ $flags['user'] = 0;
+ break;
+ case 'comments':
+ $flags['comments'] = 1;
+ break;
+ case 'nocomments':
+ $flags['comments'] = 0;
+ break;
+ case 'linkbacks':
+ $flags['linkbacks'] = 1;
+ break;
+ case 'nolinkbacks':
+ $flags['linkbacks'] = 0;
+ break;
+ case 'tags':
+ $flags['tags'] = 1;
+ break;
+ case 'notags':
+ $flags['tags'] = 0;
+ break;
+ case 'date':
+ $flags['date'] = 1;
+ break;
+ case 'nodate':
+ $flags['date'] = 0;
+ break;
+ case 'mdate':
+ $flags['mdate'] = 1;
+ break;
+ case 'nomdate':
+ $flags['mdate'] = 0;
+ break;
+ case 'indent':
+ $flags['indent'] = 1;
+ break;
+ case 'noindent':
+ $flags['indent'] = 0;
+ break;
+ case 'linkonly':
+ $flags['linkonly'] = 1;
+ break;
+ case 'nolinkonly':
+ case 'include_content':
+ $flags['linkonly'] = 0;
+ break;
+ case 'inline':
+ $flags['inline'] = 1;
+ break;
+ case 'title':
+ $flags['title'] = 1;
+ break;
+ case 'notitle':
+ $flags['title'] = 0;
+ break;
+ case 'pageexists':
+ $flags['pageexists'] = 1;
+ break;
+ case 'nopageexists':
+ $flags['pageexists'] = 0;
+ break;
+ case 'existlink':
+ $flags['pageexists'] = 1;
+ $flags['linkonly'] = 1;
+ break;
+ case 'parlink':
+ $flags['parlink'] = 1;
+ break;
+ case 'noparlink':
+ $flags['parlink'] = 0;
+ break;
+ case 'order':
+ $flags['order'] = $value;
+ break;
+ case 'sort':
+ $flags['rsort'] = 0;
+ break;
+ case 'rsort':
+ $flags['rsort'] = 1;
+ break;
+ case 'depth':
+ $flags['depth'] = max(intval($value), 0);
+ break;
+ case 'beforeeach':
+ $flags['beforeeach'] = $value;
+ break;
+ case 'aftereach':
+ $flags['aftereach'] = $value;
+ break;
+ case 'readmore':
+ $flags['readmore'] = 1;
+ break;
+ case 'noreadmore':
+ $flags['readmore'] = 0;
+ break;
+ case 'exclude':
+ $flags['exclude'] = $value;
+ break;
+ }
+ }
+ // the include_content URL parameter overrides flags
+ if (isset($_REQUEST['include_content']))
+ $flags['linkonly'] = 0;
+ return $flags;
+ }
+
+ /**
+ * Returns the converted instructions of a give page/section
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function _get_instructions($page, $sect, $mode, $lvl, $flags, $root_id = null, $included_pages = array()) {
+ $key = ($sect) ? $page . '#' . $sect : $page;
+ $this->includes[$key] = true; // legacy code for keeping compatibility with other plugins
+
+ // keep compatibility with other plugins that don't know the $root_id parameter
+ if (is_null($root_id)) {
+ global $ID;
+ $root_id = $ID;
+ }
+
+ if ($flags['linkonly']) {
+ if (page_exists($page) || $flags['pageexists'] == 0) {
+ $title = '';
+ if ($flags['title'])
+ $title = p_get_first_heading($page);
+ if($flags['parlink']) {
+ $ins = array(
+ array('p_open', array()),
+ array('internallink', array(':'.$key, $title)),
+ array('p_close', array()),
+ );
+ } else {
+ $ins = array(array('internallink', array(':'.$key,$title)));
+ }
+ }else {
+ $ins = array();
+ }
+ } else {
+ if (page_exists($page)) {
+ global $ID;
+ $backupID = $ID;
+ $ID = $page; // Change the global $ID as otherwise plugins like the discussion plugin will save data for the wrong page
+ $ins = p_cached_instructions(wikiFN($page), false, $page);
+ $ID = $backupID;
+ } else {
+ $ins = array();
+ }
+
+ $this->_convert_instructions($ins, $lvl, $page, $sect, $flags, $root_id, $included_pages);
+ }
+ return $ins;
+ }
+
+ /**
+ * Converts instructions of the included page
+ *
+ * The funcion iterates over the given list of instructions and generates
+ * an index of header and section indicies. It also removes document
+ * start/end instructions, converts links, and removes unwanted
+ * instructions like tags, comments, linkbacks.
+ *
+ * Later all header/section levels are convertet to match the current
+ * inclusion level.
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _convert_instructions(&$ins, $lvl, $page, $sect, $flags, $root_id, $included_pages = array()) {
+ global $conf;
+
+ // filter instructions if needed
+ if(!empty($sect)) {
+ $this->_get_section($ins, $sect); // section required
+ }
+
+ if($flags['firstsec']) {
+ $this->_get_firstsec($ins, $page, $flags); // only first section
+ }
+
+ $ns = getNS($page);
+ $num = count($ins);
+
+ $conv_idx = array(); // conversion index
+ $lvl_max = false; // max level
+ $first_header = -1;
+ $no_header = false;
+ $sect_title = false;
+ $endpos = null; // end position of the raw wiki text
+
+ $this->adapt_links($ins, $page, $included_pages);
+
+ for($i=0; $i<$num; $i++) {
+ switch($ins[$i][0]) {
+ case 'document_start':
+ case 'document_end':
+ case 'section_edit':
+ unset($ins[$i]);
+ break;
+ case 'header':
+ // get section title of first section
+ if($sect && !$sect_title) {
+ $sect_title = $ins[$i][1][0];
+ }
+ // check if we need to skip the first header
+ if((!$no_header) && $flags['noheader']) {
+ $no_header = true;
+ }
+
+ $conv_idx[] = $i;
+ // get index of first header
+ if($first_header == -1) $first_header = $i;
+ // get max level of this instructions set
+ if(!$lvl_max || ($ins[$i][1][1] < $lvl_max)) {
+ $lvl_max = $ins[$i][1][1];
+ }
+ break;
+ case 'section_open':
+ if ($flags['inline'])
+ unset($ins[$i]);
+ else
+ $conv_idx[] = $i;
+ break;
+ case 'section_close':
+ if ($flags['inline'])
+ unset($ins[$i]);
+ break;
+ case 'nest':
+ $this->adapt_links($ins[$i][1][0], $page, $included_pages);
+ break;
+ case 'plugin':
+ // FIXME skip other plugins?
+ switch($ins[$i][1][0]) {
+ case 'tag_tag': // skip tags
+ case 'discussion_comments': // skip comments
+ case 'linkback': // skip linkbacks
+ case 'data_entry': // skip data plugin
+ case 'meta': // skip meta plugin
+ case 'indexmenu_tag': // skip indexmenu sort tag
+ case 'include_sorttag': // skip include plugin sort tag
+ unset($ins[$i]);
+ break;
+ // adapt indentation level of nested includes
+ case 'include_include':
+ if (!$flags['inline'] && $flags['indent'])
+ $ins[$i][1][1][4] += $lvl;
+ break;
+ /*
+ * if there is already a closelastsecedit instruction (was added by one of the section
+ * functions), store its position but delete it as it can't be determined yet if it is needed,
+ * i.e. if there is a header which generates a section edit (depends on the levels, level
+ * adjustments, $no_header, ...)
+ */
+ case 'include_closelastsecedit':
+ $endpos = $ins[$i][1][1][0];
+ unset($ins[$i]);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // calculate difference between header/section level and include level
+ $diff = 0;
+ if (!isset($lvl_max)) $lvl_max = 0; // if no level found in target, set to 0
+ $diff = $lvl - $lvl_max + 1;
+ if ($no_header) $diff -= 1; // push up one level if "noheader"
+
+ // convert headers and set footer/permalink
+ $hdr_deleted = false;
+ $has_permalink = false;
+ $footer_lvl = false;
+ $contains_secedit = false;
+ $section_close_at = false;
+ foreach($conv_idx as $idx) {
+ if($ins[$idx][0] == 'header') {
+ if ($section_close_at === false && isset($ins[$idx+1]) && $ins[$idx+1][0] == 'section_open') {
+ // store the index of the first heading that is followed by a new section
+ // the wrap plugin creates sections without section_open so the section shouldn't be closed before them
+ $section_close_at = $idx;
+ }
+
+ if($no_header && !$hdr_deleted) {
+ unset ($ins[$idx]);
+ $hdr_deleted = true;
+ continue;
+ }
+
+ if($flags['indent']) {
+ $lvl_new = (($ins[$idx][1][1] + $diff) > 5) ? 5 : ($ins[$idx][1][1] + $diff);
+ $ins[$idx][1][1] = $lvl_new;
+ }
+
+ if($ins[$idx][1][1] <= $conf['maxseclevel'])
+ $contains_secedit = true;
+
+ // set permalink
+ if($flags['link'] && !$has_permalink && ($idx == $first_header)) {
+ $this->_permalink($ins[$idx], $page, $sect, $flags);
+ $has_permalink = true;
+ }
+
+ // set footer level
+ if(!$footer_lvl && ($idx == $first_header) && !$no_header) {
+ if($flags['indent'] && isset($lvl_new)) {
+ $footer_lvl = $lvl_new;
+ } else {
+ $footer_lvl = $lvl_max;
+ }
+ }
+ } else {
+ // it's a section
+ if($flags['indent']) {
+ $lvl_new = (($ins[$idx][1][0] + $diff) > 5) ? 5 : ($ins[$idx][1][0] + $diff);
+ $ins[$idx][1][0] = $lvl_new;
+ }
+
+ // check if noheader is used and set the footer level to the first section
+ if($no_header && !$footer_lvl) {
+ if($flags['indent'] && isset($lvl_new)) {
+ $footer_lvl = $lvl_new;
+ } else {
+ $footer_lvl = $lvl_max;
+ }
+ }
+ }
+ }
+
+ // close last open section of the included page if there is any
+ if ($contains_secedit) {
+ array_push($ins, array('plugin', array('include_closelastsecedit', array($endpos))));
+ }
+
+ $include_secid = (isset($flags['include_secid']) ? $flags['include_secid'] : NULL);
+
+ // add edit button
+ if($flags['editbtn']) {
+ $this->_editbtn($ins, $page, $sect, $sect_title, ($flags['redirect'] ? $root_id : false), $include_secid);
+ }
+
+ // add footer
+ if($flags['footer']) {
+ $ins[] = $this->_footer($page, $sect, $sect_title, $flags, $footer_lvl, $root_id);
+ }
+
+ // wrap content at the beginning of the include that is not in a section in a section
+ if ($lvl > 0 && $section_close_at !== 0 && $flags['indent'] && !$flags['inline']) {
+ if ($section_close_at === false) {
+ $ins[] = array('section_close', array());
+ array_unshift($ins, array('section_open', array($lvl)));
+ } else {
+ $section_close_idx = array_search($section_close_at, array_keys($ins));
+ if ($section_close_idx > 0) {
+ $before_ins = array_slice($ins, 0, $section_close_idx);
+ $after_ins = array_slice($ins, $section_close_idx);
+ $ins = array_merge($before_ins, array(array('section_close', array())), $after_ins);
+ array_unshift($ins, array('section_open', array($lvl)));
+ }
+ }
+ }
+
+ // add instructions entry wrapper
+ array_unshift($ins, array('plugin', array('include_wrap', array('open', $page, $flags['redirect'], $include_secid))));
+ if (isset($flags['beforeeach']))
+ array_unshift($ins, array('entity', array($flags['beforeeach'])));
+ array_push($ins, array('plugin', array('include_wrap', array('close'))));
+ if (isset($flags['aftereach']))
+ array_push($ins, array('entity', array($flags['aftereach'])));
+
+ // close previous section if any and re-open after inclusion
+ if($lvl != 0 && $this->sec_close && !$flags['inline']) {
+ array_unshift($ins, array('section_close', array()));
+ $ins[] = array('section_open', array($lvl));
+ }
+ }
+
+ /**
+ * Appends instruction item for the include plugin footer
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _footer($page, $sect, $sect_title, $flags, $footer_lvl, $root_id) {
+ $footer = array();
+ $footer[0] = 'plugin';
+ $footer[1] = array('include_footer', array($page, $sect, $sect_title, $flags, $root_id, $footer_lvl));
+ return $footer;
+ }
+
+ /**
+ * Appends instruction item for an edit button
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _editbtn(&$ins, $page, $sect, $sect_title, $root_id, $hid = '') {
+ $title = ($sect) ? $sect_title : $page;
+ $editbtn = array();
+ $editbtn[0] = 'plugin';
+ $editbtn[1] = array('include_editbtn', array($title, $hid));
+ $ins[] = $editbtn;
+ }
+
+ /**
+ * Convert instruction item for a permalink header
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _permalink(&$ins, $page, $sect, $flags) {
+ $ins[0] = 'plugin';
+ $ins[1] = array('include_header', array($ins[1][0], $ins[1][1], $ins[1][2], $page, $sect, $flags));
+ }
+
+ /**
+ * Convert internal and local links depending on the included pages
+ *
+ * @param array $ins The instructions that shall be adapted
+ * @param string $page The included page
+ * @param array $included_pages The array of pages that are included
+ */
+ private function adapt_links(&$ins, $page, $included_pages = null) {
+ $num = count($ins);
+ $ns = getNS($page);
+
+ for($i=0; $i<$num; $i++) {
+ // adjust links with image titles
+ if (strpos($ins[$i][0], 'link') !== false && isset($ins[$i][1][1]) && is_array($ins[$i][1][1]) && $ins[$i][1][1]['type'] == 'internalmedia') {
+ // resolve relative ids, but without cleaning in order to preserve the name
+ $media_id = resolve_id($ns, $ins[$i][1][1]['src']);
+ // make sure that after resolving the link again it will be the same link
+ if ($media_id[0] != ':') $media_id = ':'.$media_id;
+ $ins[$i][1][1]['src'] = $media_id;
+ }
+ switch($ins[$i][0]) {
+ case 'internallink':
+ case 'internalmedia':
+ // make sure parameters aren't touched
+ $link_params = '';
+ $link_id = $ins[$i][1][0];
+ $link_parts = explode('?', $link_id, 2);
+ if (count($link_parts) === 2) {
+ $link_id = $link_parts[0];
+ $link_params = $link_parts[1];
+ }
+ // resolve the id without cleaning it
+ $link_id = resolve_id($ns, $link_id, false);
+ // this id is internal (i.e. absolute) now, add ':' to make resolve_id work again
+ if ($link_id[0] != ':') $link_id = ':'.$link_id;
+ // restore parameters
+ $ins[$i][1][0] = ($link_params != '') ? $link_id.'?'.$link_params : $link_id;
+
+ if ($ins[$i][0] == 'internallink' && !empty($included_pages)) {
+ // change links to included pages into local links
+ // only adapt links without parameters
+ $link_id = $ins[$i][1][0];
+ $link_parts = explode('?', $link_id, 2);
+ if (count($link_parts) === 1) {
+ $exists = false;
+ resolve_pageid($ns, $link_id, $exists);
+
+ $link_parts = explode('#', $link_id, 2);
+ $hash = '';
+ if (count($link_parts) === 2) {
+ list($link_id, $hash) = $link_parts;
+ }
+ if (array_key_exists($link_id, $included_pages)) {
+ if ($hash) {
+ // hopefully the hash is also unique in the including page (otherwise this might be the wrong link target)
+ $ins[$i][0] = 'locallink';
+ $ins[$i][1][0] = $hash;
+ } else {
+ // the include section ids are different from normal section ids (so they won't conflict) but this
+ // also means that the normal locallink function can't be used
+ $ins[$i][0] = 'plugin';
+ $ins[$i][1] = array('include_locallink', array($included_pages[$link_id]['hid'], $ins[$i][1][1], $ins[$i][1][0]));
+ }
+ }
+ }
+ }
+ break;
+ case 'locallink':
+ /* Convert local links to internal links if the page hasn't been fully included */
+ if ($included_pages == null || !array_key_exists($page, $included_pages)) {
+ $ins[$i][0] = 'internallink';
+ $ins[$i][1][0] = ':'.$page.'#'.$ins[$i][1][0];
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get a section including its subsections
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _get_section(&$ins, $sect) {
+ $num = count($ins);
+ $offset = false;
+ $lvl = false;
+ $end = false;
+ $endpos = null; // end position in the input text, needed for section edit buttons
+
+ $check = array(); // used for sectionID() in order to get the same ids as the xhtml renderer
+
+ for($i=0; $i<$num; $i++) {
+ if ($ins[$i][0] == 'header') {
+
+ // found the right header
+ if (sectionID($ins[$i][1][0], $check) == $sect) {
+ $offset = $i;
+ $lvl = $ins[$i][1][1];
+ } elseif ($offset && $lvl && ($ins[$i][1][1] <= $lvl)) {
+ $end = $i - $offset;
+ $endpos = $ins[$i][1][2]; // the position directly after the found section, needed for the section edit button
+ break;
+ }
+ }
+ }
+ $offset = $offset ? $offset : 0;
+ $end = $end ? $end : ($num - 1);
+ if(is_array($ins)) {
+ $ins = array_slice($ins, $offset, $end);
+ // store the end position in the include_closelastsecedit instruction so it can generate a matching button
+ $ins[] = array('plugin', array('include_closelastsecedit', array($endpos)));
+ }
+ }
+
+ /**
+ * Only display the first section of a page and a readmore link
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _get_firstsec(&$ins, $page, $flags) {
+ $num = count($ins);
+ $first_sect = false;
+ $endpos = null; // end position in the input text
+ for($i=0; $i<$num; $i++) {
+ if($ins[$i][0] == 'section_close') {
+ $first_sect = $i;
+ }
+ if ($ins[$i][0] == 'header') {
+ /*
+ * Store the position of the last header that is encountered. As section_close/open-instruction are
+ * always (unless some plugin modifies this) around a header instruction this means that the last
+ * position that is stored here is exactly the position of the section_close/open at which the content
+ * is truncated.
+ */
+ $endpos = $ins[$i][1][2];
+ }
+ // only truncate the content and add the read more link when there is really
+ // more than that first section
+ if(($first_sect) && ($ins[$i][0] == 'section_open')) {
+ $ins = array_slice($ins, 0, $first_sect);
+ if ($flags['readmore']) {
+ $ins[] = array('plugin', array('include_readmore', array($page)));
+ }
+ $ins[] = array('section_close', array());
+ // store the end position in the include_closelastsecedit instruction so it can generate a matching button
+ $ins[] = array('plugin', array('include_closelastsecedit', array($endpos)));
+ return;
+ }
+ }
+ }
+
+ /**
+ * Gives a list of pages for a given include statement
+ *
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function _get_included_pages($mode, $page, $sect, $parent_id, $flags) {
+ global $conf;
+ $pages = array();
+ switch($mode) {
+ case 'namespace':
+ $page = cleanID($page);
+ $ns = utf8_encodeFN(str_replace(':', '/', $page));
+ // depth is absolute depth, not relative depth, but 0 has a special meaning.
+ $depth = $flags['depth'] ? $flags['depth'] + substr_count($page, ':') + ($page ? 1 : 0) : 0;
+ search($pagearrays, $conf['datadir'], 'search_allpages', array('depth' => $depth, 'skipacl' => false), $ns);
+ if (is_array($pagearrays)) {
+ foreach ($pagearrays as $pagearray) {
+ if (!isHiddenPage($pagearray['id'])) // skip hidden pages
+ $pages[] = $pagearray['id'];
+ }
+ }
+ break;
+ case 'tagtopic':
+ if (!$this->taghelper)
+ $this->taghelper = plugin_load('helper', 'tag');
+ if(!$this->taghelper) {
+ msg('You have to install the tag plugin to use this functionality!', -1);
+ return array();
+ }
+ $tag = $page;
+ $sect = '';
+ $pagearrays = $this->taghelper->getTopic('', null, $tag);
+ foreach ($pagearrays as $pagearray) {
+ $pages[] = $pagearray['id'];
+ }
+ break;
+ default:
+ $page = $this->_apply_macro($page, $parent_id);
+ resolve_pageid(getNS($parent_id), $page, $exists); // resolve shortcuts and clean ID
+ if (auth_quickaclcheck($page) >= AUTH_READ)
+ $pages[] = $page;
+ }
+
+ if (isset($flags['exclude']))
+ $pages = array_filter($pages, function ($page) use ($flags) {
+ if (@preg_match($flags['exclude'], $page))
+ return FALSE;
+ return TRUE;
+ });
+
+ if (count($pages) > 1) {
+ if ($flags['order'] === 'id') {
+ if ($flags['rsort']) {
+ usort($pages, array($this, '_r_strnatcasecmp'));
+ } else {
+ natcasesort($pages);
+ }
+ } else {
+ $ordered_pages = array();
+ foreach ($pages as $page) {
+ $key = '';
+ switch ($flags['order']) {
+ case 'title':
+ $key = p_get_first_heading($page);
+ break;
+ case 'created':
+ $key = p_get_metadata($page, 'date created', METADATA_DONT_RENDER);
+ break;
+ case 'modified':
+ $key = p_get_metadata($page, 'date modified', METADATA_DONT_RENDER);
+ break;
+ case 'indexmenu':
+ $key = p_get_metadata($page, 'indexmenu_n', METADATA_RENDER_USING_SIMPLE_CACHE);
+ if ($key === null)
+ $key = '';
+ break;
+ case 'custom':
+ $key = p_get_metadata($page, 'include_n', METADATA_RENDER_USING_SIMPLE_CACHE);
+ if ($key === null)
+ $key = '';
+ break;
+ }
+ $key .= '_'.$page;
+ $ordered_pages[$key] = $page;
+ }
+ if ($flags['rsort']) {
+ uksort($ordered_pages, array($this, '_r_strnatcasecmp'));
+ } else {
+ uksort($ordered_pages, 'strnatcasecmp');
+ }
+ $pages = $ordered_pages;
+ }
+ }
+
+ $result = array();
+ foreach ($pages as $page) {
+ $exists = page_exists($page);
+ $result[] = array('id' => $page, 'exists' => $exists, 'parent_id' => $parent_id);
+ }
+ return $result;
+ }
+
+ /**
+ * String comparisons using a "natural order" algorithm in reverse order
+ *
+ * @link http://php.net/manual/en/function.strnatcmp.php
+ * @param string $a First string
+ * @param string $b Second string
+ * @return int Similar to other string comparison functions, this one returns &lt; 0 if
+ * str1 is greater than str2; &gt;
+ * 0 if str1 is lesser than
+ * str2, and 0 if they are equal.
+ */
+ function _r_strnatcasecmp($a, $b) {
+ return strnatcasecmp($b, $a);
+ }
+
+ /**
+ * This function generates the list of all included pages from a list of metadata
+ * instructions.
+ */
+ function _get_included_pages_from_meta_instructions($instructions) {
+ $pages = array();
+ foreach ($instructions as $instruction) {
+ $mode = $instruction['mode'];
+ $page = $instruction['page'];
+ $sect = $instruction['sect'];
+ $parent_id = $instruction['parent_id'];
+ $flags = $instruction['flags'];
+ $pages = array_merge($pages, $this->_get_included_pages($mode, $page, $sect, $parent_id, $flags));
+ }
+ return $pages;
+ }
+
+ /**
+ * Get wiki language from "HTTP_ACCEPT_LANGUAGE"
+ * We allow the pattern e.g. "ja,en-US;q=0.7,en;q=0.3"
+ */
+ function _get_language_of_wiki($id, $parent_id) {
+ global $conf;
+ $result = $conf['lang'];
+ if(strpos($id, '@BROWSER_LANG@') !== false){
+ $brlangp = "/([a-zA-Z]{1,8}(-[a-zA-Z]{1,8})*|\*)(;q=(0(.[0-9]{0,3})?|1(.0{0,3})?))?/";
+ if(preg_match_all(
+ $brlangp, $_SERVER["HTTP_ACCEPT_LANGUAGE"],
+ $matches, PREG_SET_ORDER
+ )){
+ $langs = array();
+ foreach($matches as $match){
+ $langname = $match[1] == '*' ? $conf['lang'] : $match[1];
+ $qvalue = $match[4] == '' ? 1.0 : $match[4];
+ $langs[$langname] = $qvalue;
+ }
+ arsort($langs);
+ foreach($langs as $lang => $langq){
+ $testpage = $this->_apply_macro(str_replace('@BROWSER_LANG@', $lang, $id), $parent_id);
+ resolve_pageid(getNS($parent_id), $testpage, $exists);
+ if($exists){
+ $result = $lang;
+ break;
+ }
+ }
+ }
+ }
+ return cleanID($result);
+ }
+
+ /**
+ * Makes user or date dependent includes possible
+ */
+ function _apply_macro($id, $parent_id) {
+ global $USERINFO;
+ /* @var Input $INPUT */
+ global $INPUT;
+
+ // The following is basicaly copied from basicinfo() because
+ // this function can be called from within pageinfo() in
+ // p_get_metadata and thus we cannot rely on $INFO being set
+ if($INPUT->server->has('REMOTE_USER')) {
+ $user = $INPUT->server->str('REMOTE_USER');
+ } else {
+ // no registered user - use IP
+ $user = clientIP(true);
+ }
+
+ // Take user's name if possible, login name otherwise
+ if (!empty($USERINFO['name'])) {
+ $name = $USERINFO['name'];
+ } else {
+ $name = $user;
+ }
+
+ // Take first group if possible
+ if (!empty($USERINFO['grps'])) {
+ $group = $USERINFO['grps'][0];
+ } else {
+ $group = 'ALL';
+ }
+
+ $time_stamp = time();
+ if(preg_match('/@DATE(\w+)@/',$id,$matches)) {
+ switch($matches[1]) {
+ case 'PMONTH':
+ $time_stamp = strtotime("-1 month");
+ break;
+ case 'NMONTH':
+ $time_stamp = strtotime("+1 month");
+ break;
+ case 'NWEEK':
+ $time_stamp = strtotime("+1 week");
+ break;
+ case 'PWEEK':
+ $time_stamp = strtotime("-1 week");
+ break;
+ case 'TOMORROW':
+ $time_stamp = strtotime("+1 day");
+ break;
+ case 'YESTERDAY':
+ $time_stamp = strtotime("-1 day");
+ break;
+ case 'NYEAR':
+ $time_stamp = strtotime("+1 year");
+ break;
+ case 'PYEAR':
+ $time_stamp = strtotime("-1 year");
+ break;
+ }
+ $id = preg_replace('/@DATE(\w+)@/','', $id);
+ }
+
+ $replace = array(
+ '@USER@' => cleanID($user),
+ '@NAME@' => cleanID($name),
+ '@GROUP@' => cleanID($group),
+ '@BROWSER_LANG@' => $this->_get_language_of_wiki($id, $parent_id),
+ '@YEAR@' => date('Y',$time_stamp),
+ '@MONTH@' => date('m',$time_stamp),
+ '@WEEK@' => date('W',$time_stamp),
+ '@DAY@' => date('d',$time_stamp),
+ '@YEARPMONTH@' => date('Ym',strtotime("-1 month")),
+ '@PMONTH@' => date('m',strtotime("-1 month")),
+ '@NMONTH@' => date('m',strtotime("+1 month")),
+ '@YEARNMONTH@' => date('Ym',strtotime("+1 month")),
+ '@YEARPWEEK@' => date('YW',strtotime("-1 week")),
+ '@PWEEK@' => date('W',strtotime("-1 week")),
+ '@NWEEK@' => date('W',strtotime("+1 week")),
+ '@YEARNWEEK@' => date('YW',strtotime("+1 week")),
+ );
+ return str_replace(array_keys($replace), array_values($replace), $id);
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/images/comment.gif b/platform/www/lib/plugins/include/images/comment.gif
new file mode 100644
index 0000000..735543c
--- /dev/null
+++ b/platform/www/lib/plugins/include/images/comment.gif
Binary files differ
diff --git a/platform/www/lib/plugins/include/images/date.gif b/platform/www/lib/plugins/include/images/date.gif
new file mode 100644
index 0000000..da61dda
--- /dev/null
+++ b/platform/www/lib/plugins/include/images/date.gif
Binary files differ
diff --git a/platform/www/lib/plugins/include/images/link.gif b/platform/www/lib/plugins/include/images/link.gif
new file mode 100644
index 0000000..ca63480
--- /dev/null
+++ b/platform/www/lib/plugins/include/images/link.gif
Binary files differ
diff --git a/platform/www/lib/plugins/include/images/user.gif b/platform/www/lib/plugins/include/images/user.gif
new file mode 100644
index 0000000..5ada7e6
--- /dev/null
+++ b/platform/www/lib/plugins/include/images/user.gif
Binary files differ
diff --git a/platform/www/lib/plugins/include/lang/ar/lang.php b/platform/www/lib/plugins/include/lang/ar/lang.php
new file mode 100644
index 0000000..2d8266e
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ar/lang.php
@@ -0,0 +1,12 @@
+<?php
+/**
+* Arabic language file
+*
+* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+* @author Muhammad Bashir Al-Noimi <bashir.storm@gmail.com>
+* http://www.hali-sy.com
+*/
+
+// custom language strings for the plugin
+$lang['readmore'] = ' ←إقرأ المزيد... ';
+
diff --git a/platform/www/lib/plugins/include/lang/ar/settings.php b/platform/www/lib/plugins/include/lang/ar/settings.php
new file mode 100644
index 0000000..f3245a9
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ar/settings.php
@@ -0,0 +1,20 @@
+<?php
+/**
+* Arabic language file
+*
+* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+* @author Muhammad Bashir Al-Noimi <bashir.storm@gmail.com>
+* http://www.hali-sy.com
+*/
+
+// for the configuration manager
+$lang['firstseconly'] = 'عرض القسم الأول من الصفحات المضمّنة';
+$lang['showtaglogos'] = 'عرض الصورة لأول قسم';
+$lang['showfooter'] = 'عرض معلومات الصفحة المضمّنة';
+$lang['showlink'] = 'عرض رابط التتبع للصفحة المضمّنة';
+$lang['showdate'] = 'عرض التاريخ للصفحة المضمّنة';
+$lang['showuser'] = 'عرض إسم المستخدم للصفحة المضمّنة';
+$lang['showcomments'] = 'عرض تعليقات الصفحة المضمّنة';
+$lang['showtags'] = 'عرض الأقسام أسف الصفحة المضمّنة';
+
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/lang/cs/lang.php b/platform/www/lib/plugins/include/lang/cs/lang.php
new file mode 100644
index 0000000..417c3ea
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/cs/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Czech language file (UTF-8 encoding)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Lukas Zapletal <lukas.zapletal at gmail dot com>
+ */
+$lang['readmore'] = '→ Číst dále...';
diff --git a/platform/www/lib/plugins/include/lang/cs/settings.php b/platform/www/lib/plugins/include/lang/cs/settings.php
new file mode 100644
index 0000000..bfeda4b
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/cs/settings.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ *
+ * Czech language file (UTF-8 encoding)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Robert Surý <rsurycz@seznam.cz>
+ * @author Lukas Zapletal <lukas.zapletal at gmail dot com>
+ * @author Roman Svoboda <svoboro1 at fel.cvut dot cz>
+ */
+$lang['noheader'] = 'Nezobrazovat první záhlaví vkládaných stránek/sekcí';
+$lang['firstseconly'] = 'Zobrazovat pouze první sekci vkládaných stránek';
+$lang['showtaglogos'] = 'Zobrazovat obrázek prvních tagů';
+$lang['showfooter'] = 'Zobrazovat dole info o vkládané stránce';
+$lang['showlink'] = 'Odkaz na první titulek vkládané stránky';
+$lang['showpermalink'] = 'Zobrazovat dole permalinky vkládané stránky';
+$lang['showdate'] = 'Zobrazovat dole datum vkládané stránky';
+$lang['showmdate'] = 'Zobrazovat dole datum modifikace vkládané stránky';
+$lang['showuser'] = 'Zobrazovat dole jméno uživatele vkládané stránky';
+$lang['showcomments'] = 'Zobrazovat dole komentáře u vkládané stránky (vyžadován Discussion plugin)';
+$lang['showlinkbacks'] = 'Zobrazovat dole zpětné odkazy vkládané stránky (vyžadován Linkback plugin)';
+$lang['showtags'] = 'Zobrazovat dole tagy vkládané stránky (vyžadován Tag plugin)';
+$lang['showeditbtn'] = 'Zobrazovat tlačítko pro editaci';
+$lang['doredirect'] = 'Přesměrovat na původní stránku po provedení editace vkládané stránky';
+$lang['linkonly'] = 'Pouze odkaz na vloženou stránku namísto zobrazení obsahu';
+$lang['title'] = 'Použijte první nadpis stránky v odkazu, i když je používání nadpisů vypnuto (ovlivňuje pouze režim "jen odkazy"))';
+$lang['pageexists'] = 'Nezobrazovat odkaz, pokud stránka neexistuje (ovlivňuje pouze režim "jen odkazy")';
+$lang['parlink'] = 'Umístěte odstavec kolem odkazu (ovlivní pouze režim "jen odkazy")';
+$lang['safeindex'] = 'Zabraňte indexaci metadat z neveřejných vložených stránek';
+$lang['order_o_id'] = 'ID stránky';
+$lang['order_o_title'] = 'titulek';
+$lang['order_o_created'] = 'datum vytvoření';
+$lang['order_o_modified'] = 'datum modifikace';
+$lang['order_o_indexmenu'] = 'Vlastní pořadí se syntaxí indexmenu';
+$lang['order_o_custom'] = 'Vlastní pořadí s vloženou syntaxí';
+$lang['rsort'] = 'Obrátit pořadí řazení vkládaných stránek';
+$lang['depth'] = 'Maximální hloubka vnoření jmenných prostorů, 0 představuje neomezenou hloubku';
+$lang['readmore'] = 'Zobrazit nebo nezobrazit odkaz \'Číst více\' pouze pro případ první sekce';
+$lang['debugoutput'] = 'Tisknout podrobnější ladící informace do dokuwiki ladícího logu, pokud je povolena globální možnost "allowdebug"';
diff --git a/platform/www/lib/plugins/include/lang/da/lang.php b/platform/www/lib/plugins/include/lang/da/lang.php
new file mode 100644
index 0000000..9ad0e43
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/da/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Soren Birk <soer9648@eucl.dk>
+ */
+$lang['readmore'] = '→ Læs mere...';
diff --git a/platform/www/lib/plugins/include/lang/da/settings.php b/platform/www/lib/plugins/include/lang/da/settings.php
new file mode 100644
index 0000000..4c83c2b
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/da/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Jacob Palm <jacobpalmdk@icloud.com>
+ * @author Soren Birk <soer9648@eucl.dk>
+ */
+$lang['noheader'] = 'Vis ikke den første header for inkluderede sider/sektioner';
+$lang['firstseconly'] = 'vis kun den første sektion for inkluderede sider';
+$lang['showtaglogos'] = 'vis billede for første tag';
+$lang['showfooter'] = 'vis info på inkluderet side nedenfor';
+$lang['showlink'] = 'link første overskrift af inkluderet side';
+$lang['showpermalink'] = 'vis permalinks nedenfor inkluderet side';
+$lang['showdate'] = 'vis datoer nedenfor inkluderet side';
+$lang['showmdate'] = 'vis redigeret datoer nedenfor inkluderet side';
+$lang['showuser'] = 'vis brugernavne nedenfor inkluderet side';
+$lang['showcomments'] = 'vis kommentarer nedenfor inkluderet side (Discussion plugin nødvendigt)';
+$lang['showlinkbacks'] = 'vis linkbacks nedenfor inkluderet side (Linkback Plugin nødvendigt)';
+$lang['showtags'] = 'vis tags nedenfor inkluderet side (Tag Plugin nødvendigt)';
+$lang['showeditbtn'] = 'vis redigér-knap';
+$lang['doredirect'] = 'henvis til original side efter redigering af den inkluderede side';
+$lang['doindent'] = 'indryk inkluderede sider relativt i forhold til siden de inkluderes i';
+$lang['linkonly'] = 'link udelukkende til den inkluderede side i stedet for at vise indholdet';
+$lang['title'] = 'benyt sidens første overskrift i link, selvom useheading er slået fra (har kun effekt på linkonly-tilstand)';
+$lang['pageexists'] = 'Vis ikke et link hvis siden ikke findes (har kun effekt på linkonly-tilstand)';
+$lang['parlink'] = 'omkreds linket i et afsnit (har kun effekt på linkonly-tilstand)';
+$lang['safeindex'] = 'undgå indeksering af metadata fra ikke-offentlige inkluderede sider';
+$lang['order'] = 'kriterier til rækkefølge for inkluderede med adskellige sider';
+$lang['order_o_id'] = 'side-ID';
+$lang['order_o_title'] = 'titel';
+$lang['order_o_created'] = 'oprettelsesdato';
+$lang['order_o_modified'] = 'dato for modifikation';
+$lang['order_o_indexmenu'] = 'brugerdefineret orden med indexmenu-syntaks';
+$lang['order_o_custom'] = 'brugerdefineret orden med inkludér-syntaks';
+$lang['rsort'] = 'vend rækkefølgen for sortering af inkluderede sider';
+$lang['depth'] = 'maksimum dybde af inkluderede navnerum, 0 for uendelig dybde';
+$lang['readmore'] = 'Vis eller skjul "Læs mere" linket hvis kun den første sektion af inkluderede sider viser';
+$lang['debugoutput'] = 'Skriv udvidet debug information til DokuWiki debugloggen, hvis den globale indstilling "allowdebug" er slået til';
diff --git a/platform/www/lib/plugins/include/lang/de-informal/lang.php b/platform/www/lib/plugins/include/lang/de-informal/lang.php
new file mode 100644
index 0000000..dc75a53
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/de-informal/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+$lang['readmore'] = '→ Weiterlesen...';
diff --git a/platform/www/lib/plugins/include/lang/de-informal/settings.php b/platform/www/lib/plugins/include/lang/de-informal/settings.php
new file mode 100644
index 0000000..5076b1b
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/de-informal/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+$lang['noheader'] = 'Erste Überschrift von eingeschlossenen Seiten/Sektionen nicht anzeigen';
+$lang['firstseconly'] = 'Nur ersten Abschnitt von eingebundenen Seiten anzeigen';
+$lang['showtaglogos'] = 'Bild für erstes Tag anzeigen';
+$lang['showfooter'] = 'Infos über eingebundene Seite darunter anzeigen';
+$lang['showlink'] = 'Erste Überschrift der eingebundenen Seite als Link anzeigen';
+$lang['showpermalink'] = 'Permalink unter eingebunderer Seite anzeigen';
+$lang['showdate'] = 'Datum unter eingebundender Seite anzeigen';
+$lang['showmdate'] = 'Änderungsdatum unter eingebundener Seite anzeigen';
+$lang['showuser'] = 'Autorenname unter eingebundener Seite anzeigen';
+$lang['showcomments'] = 'Kommentare unter eingebundener Seite anzeigen (Discussion Plugin wird benötigt)';
+$lang['showlinkbacks'] = 'Linkbacks unter eingebundener Seite anzeigen (Linkback Plugin wird benötigt)';
+$lang['showtags'] = 'Tags unter eingebundener Seite anzeigen (Tag Plugin wird benötigt)';
+$lang['showeditbtn'] = 'Bearbeiten-Button anzeigen';
+$lang['doredirect'] = 'Nach dem Bearbeiten der eingebundenen Seite zur ursprünglichen Seite weiterleiten';
+$lang['doindent'] = 'Eingebundene Seiten relativ zur Seite, in der sie eingebunden sind einrücken';
+$lang['linkonly'] = 'Nur einen Link anzeigen statt dem Inhalt der eingebundenen Seite';
+$lang['title'] = 'Erste Überschrift im Link benutzen auch wenn "useheading" ausgeschaltet ist (betrifft nur den "linkonly"-Modus)';
+$lang['pageexists'] = 'Keinen Link anzeigen, wenn die verlinkte Seite nicht existiert (betrifft nur den "linkonly"-Modus)';
+$lang['parlink'] = 'Einen Absatz um den Link herum anzeigen (betrifft nur den "linkonly"-Modus)';
+$lang['safeindex'] = 'Verhindere das Indizieren von Metadaten auf eingebundenen, nicht öffentlichen Seiten';
+$lang['order'] = 'Sortierkriterium beim Einfügen von mehreren Seiten';
+$lang['order_o_id'] = 'Seiten ID';
+$lang['order_o_title'] = 'Titel';
+$lang['order_o_created'] = 'Erstellungsdatum';
+$lang['order_o_modified'] = 'Änderungsdatum';
+$lang['order_o_indexmenu'] = 'Benutzerdefinierte Reihenfolge mit Indexmenu Syntax';
+$lang['order_o_custom'] = 'Benutzerdefinierte Reihenfolge mit Include Syntax';
+$lang['rsort'] = 'Umgekehrte Reihenfolge bei der Sortierung von eingefügten Seiten';
+$lang['depth'] = 'Maximale Tiefe von Namensräumen, 0 für alle Ebenen';
+$lang['readmore'] = '\'Weiterlesen\'-Link bei aktiviertem "firstseconly"-Modus anzeigen';
+$lang['debugoutput'] = 'Ausführliche Informationen in das Debuglog des Dokuwikis schreiben (setzt voraus, dass die globale Option "allowdebug" aktiviert ist).';
diff --git a/platform/www/lib/plugins/include/lang/de/lang.php b/platform/www/lib/plugins/include/lang/de/lang.php
new file mode 100644
index 0000000..dc75a53
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/de/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+$lang['readmore'] = '→ Weiterlesen...';
diff --git a/platform/www/lib/plugins/include/lang/de/settings.php b/platform/www/lib/plugins/include/lang/de/settings.php
new file mode 100644
index 0000000..9ed7a79
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/de/settings.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author F. Mueller-Donath <j.felix@mueller-donath.de>
+ * @author Esther Brunner <wikidesign@gmail.com>
+ * @author Dominik Eckelmann <deckelmann@gmail.com>
+ * @author Christian Paul <info@jaller.de>
+ * @author Dana <dannax3@gmx.de>
+ */
+$lang['noheader'] = 'Erste Überschrift von eingeschlossenen Seiten/Sektionen nicht anzeigen';
+$lang['firstseconly'] = 'Nur ersten Abschnitt von eingebundenen Seiten anzeigen';
+$lang['showtaglogos'] = 'Bild für erstes Tag anzeigen';
+$lang['showfooter'] = 'Infos über eingebundene Seite darunter anzeigen';
+$lang['showlink'] = 'Erste Überschrift der eingebundenen Seite als Link anzeigen';
+$lang['showpermalink'] = 'Permalink unter eingebunderer Seite anzeigen';
+$lang['showdate'] = 'Datum unter eingebunderer Seite anzeigen';
+$lang['showmdate'] = 'Änderungsdatum unter eingebundener Seite anzeigen';
+$lang['showuser'] = 'Autorenname unter eingebundener Seite anzeigen';
+$lang['showcomments'] = 'Kommentare unter eingebundener Seite anzeigen (Discussion Plugin wird benötigt)';
+$lang['showlinkbacks'] = 'Linkbacks unter eingebundener Seite anzeigen (Linkback Plugin wird benötigt)';
+$lang['showtags'] = 'Tags unter eingebundener Seite anzeigen (Tag Plugin wird benötigt)';
+$lang['showeditbtn'] = 'Bearbeiten-Button anzeigen';
+$lang['doredirect'] = 'Nach dem Bearbeiten der eingebundenen Seite zur ursprünglichen Seite weiterleiten';
+$lang['doindent'] = 'Eingebundene Seiten relativ zur Seite, in der sie eingebunden sind einrücken';
+$lang['linkonly'] = 'Nur einen Link anzeigen statt dem Inhalt der eingebundenen Seite';
+$lang['title'] = 'Erste Überschrift im Link benutzen auch wenn "useheading" ausgeschaltet ist (betrifft nur den "linkonly"-Modus)';
+$lang['pageexists'] = 'Keinen Link anzeigen, wenn die verlinkte Seite nicht existiert (betrifft nur den "linkonly"-Modus)';
+$lang['parlink'] = 'Einen Absatz um den Link herum anzeigen (betrifft nur den "linkonly"-Modus)';
+$lang['safeindex'] = 'Verhindere das Indizieren von Metadaten auf eingebundenen, nicht öffentlichen Seiten';
+$lang['order'] = 'Sortierkriterium beim Einfügen von mehreren Seiten';
+$lang['order_o_id'] = 'Seiten ID';
+$lang['order_o_title'] = 'Titel';
+$lang['order_o_created'] = 'Erstellungsdatum';
+$lang['order_o_modified'] = 'Änderungsdatum';
+$lang['order_o_indexmenu'] = 'Benutzerdefinierte Reihenfolge mit Indexmenu Syntax.';
+$lang['order_o_custom'] = 'Benutzerdefinierte Reihenfolge mit Include Syntax';
+$lang['rsort'] = 'Umgekehrte Reihenfolge bei der Sortierung von eingefügten Seiten';
+$lang['depth'] = 'Maximale Tiefe von Namensräumen, 0 für alle Ebenen';
+$lang['readmore'] = 'Zeige einen \'Weiterlesen\'-Link bei aktiviertem "firstseconly"-Modus';
+$lang['debugoutput'] = 'Ausführliche Informationen in das Debuglog des Dokuwikis schreiben (setzt voraus, dass die globale Option "allowdebug" aktiviert ist).';
diff --git a/platform/www/lib/plugins/include/lang/en/lang.php b/platform/www/lib/plugins/include/lang/en/lang.php
new file mode 100644
index 0000000..2204c39
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/en/lang.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * English language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+
+// custom language strings for the plugin
+$lang['readmore'] = '→ Read more...';
+
+//Setup VIM: ex: et ts=2 : \ No newline at end of file
diff --git a/platform/www/lib/plugins/include/lang/en/settings.php b/platform/www/lib/plugins/include/lang/en/settings.php
new file mode 100644
index 0000000..8aec307
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/en/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * English language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+
+// for the configuration manager
+$lang['noheader'] = 'Don\'t show the first header of included pages/sections';
+$lang['firstseconly'] = 'Show only the first section of included pages';
+$lang['showtaglogos'] = 'Show image for first tag';
+$lang['showfooter'] = 'Show info about included page below';
+$lang['showlink'] = 'Link first headline of included page';
+$lang['showpermalink'] = 'Show permalinks below included page';
+$lang['showdate'] = 'Show dates below included page';
+$lang['showmdate'] = 'Show modified dates below included page';
+$lang['showuser'] = 'Show usernames below included page';
+$lang['showcomments'] = 'Show comments below included page (Discussion plugin needed)';
+$lang['showlinkbacks'] = 'Show linkbacks below included page (Linkback Plugin needed)';
+$lang['showtags'] = 'Show tags below included page (Tag Plugin needed)';
+$lang['showeditbtn'] = 'Show edit button';
+$lang['doredirect'] = 'Redirect to the original page after editing the included page';
+$lang['doindent'] = 'Indent included pages relative to the page they get included in';
+$lang['linkonly'] = 'Link only to the included page instead of showing the content';
+$lang['title'] = 'Use first heading of page in link even if useheading is off (only affects linkonly mode)';
+$lang['pageexists'] = 'Do not display a link if the page does not exist (only affects linkonly mode)';
+$lang['parlink'] = 'Put a paragraph around the link (only affects linkonly mode)';
+$lang['safeindex'] = 'Prevent indexing of metadata from non-public included pages';
+$lang['order'] = 'Ordering criteria of includes with multiple pages';
+$lang['order_o_id'] = 'page ID';
+$lang['order_o_title'] = 'title';
+$lang['order_o_created'] = 'creation date';
+$lang['order_o_modified'] = 'modification date';
+$lang['order_o_indexmenu'] = 'custom order with indexmenu syntax';
+$lang['order_o_custom'] = 'custom order with include syntax';
+$lang['rsort'] = 'Reverse the sort order of the included pages';
+$lang['depth'] = 'Maximum depth of namespace includes, 0 for unlimited depth';
+$lang['readmore'] = 'Show or not the \'Read More\' link in case of firstsection only';
+$lang['debugoutput'] = 'Print verbose debug information to the dokuwiki debuglog if the global "allowdebug" option is enabled';
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/lang/eo/lang.php b/platform/www/lib/plugins/include/lang/eo/lang.php
new file mode 100644
index 0000000..e8dc40f
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/eo/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Robert Bogenschneider <bogi@uea.org>
+ */
+$lang['readmore'] = '→ Legi plu...';
diff --git a/platform/www/lib/plugins/include/lang/eo/settings.php b/platform/www/lib/plugins/include/lang/eo/settings.php
new file mode 100644
index 0000000..61ec14e
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/eo/settings.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Robert Bogenschneider <bogi@uea.org>
+ * @author Robert Bogenschneider <robog@gmx.de>
+ */
+$lang['noheader'] = 'Ne montri la unuan alineon de inkluditaj paĝoj/sekcioj';
+$lang['firstseconly'] = 'montri nur la unuan sekcion de inkluditaj paĝoj';
+$lang['showtaglogos'] = 'montri bildon por la unua etikedo';
+$lang['showfooter'] = 'montri informojn pri inkludita paĝo sube';
+$lang['showlink'] = 'ligilo al la unua kaplinio de inkludita paĝo';
+$lang['showpermalink'] = 'montri permaligilojn sub inkludita paĝo';
+$lang['showdate'] = 'montri daton sub inkludita paĝo';
+$lang['showmdate'] = 'montri modif-daton sub inkludita paĝo';
+$lang['showuser'] = 'montri uzantonomojn sub inkludita paĝo';
+$lang['showcomments'] = 'montri komentojn sub inkludita paĝo (kromaĵo discussion bezonata)';
+$lang['showlinkbacks'] = 'montri retroligilojn sub inkludita paĝo (kromaĵo linkback bezonata)';
+$lang['showtags'] = 'montri etikedojn sub inkludita paĝo (kromaĵo tag bezonata)';
+$lang['showeditbtn'] = 'montri butonon por modifi';
+$lang['doredirect'] = 'redirekti al la origina paĝo post modifado de la inkludita paĝo';
+$lang['doindent'] = 'ŝovi inkluditajn paĝojn relative al la inkludanta paĝo';
+$lang['linkonly'] = 'nur ligi, ne montri la enhavon de la inkludita paĝo';
+$lang['title'] = 'uzi la unuan titolon de paĝo en ligilo eĉ se useheading estas blokita (koncernas nur linkonly-moduson)';
+$lang['pageexists'] = 'ne montri ligilon, se la paĝo ne ekzistas (koncernas nur linkonly-moduson)';
+$lang['parlink'] = 'meti alineon ĉirkaŭ ligilon (koncernas nur linkonly-moduson)';
+$lang['safeindex'] = 'eviti indeksadon de metadatumoj de nepublikaj inkluditaj paĝoj';
+$lang['order'] = 'ordigi inkludojn de multaj paĝoj laŭ';
+$lang['order_o_id'] = 'paĝnomo';
+$lang['order_o_title'] = 'titolo';
+$lang['order_o_created'] = 'krea dato';
+$lang['order_o_modified'] = 'modifa dato';
+$lang['order_o_indexmenu'] = 'propra ordo per indexmenu-sintakso';
+$lang['order_o_custom'] = 'propra ordo per include-sintakso';
+$lang['rsort'] = 'inversigi la ordon de la inkluditaj paĝoj';
+$lang['depth'] = 'maksimuma profundeco de nomspaco-inkludoj, 0 por senlima profundeco';
+$lang['readmore'] = 'Ĉu montri la \'Legi plu\'-ligilon por la opcio unua alineo';
diff --git a/platform/www/lib/plugins/include/lang/es/lang.php b/platform/www/lib/plugins/include/lang/es/lang.php
new file mode 100644
index 0000000..c41837e
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/es/lang.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * Archivo en español
+ *
+ * @licencia GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @autor Esther Brunner <wikidesign@gmail.com>
+ *
+ */
+$lang['readmore'] = 'Leer más...';
diff --git a/platform/www/lib/plugins/include/lang/es/settings.php b/platform/www/lib/plugins/include/lang/es/settings.php
new file mode 100644
index 0000000..b18d02b
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/es/settings.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Spanish language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Luna Frax <lunafrax@gmail.com>
+ * @author Herman Fabián Sandoval Manrique <hfsandovalm@emzac.com>
+ */
+$lang['noheader'] = 'No mostrar el primer encabezado de las páginas/secciones incluidas';
+$lang['firstseconly'] = 'mostrar solamente la primera sección de las entradas al blog';
+$lang['showtaglogos'] = 'mostrar imagen para la primera etiqueta';
+$lang['showfooter'] = 'mostrar en la parte inferior información acerca de la entrada al blog';
+$lang['showlink'] = 'mostrar los enlaces a continuación de las entradas al blog';
+$lang['showpermalink'] = 'Mostrar los enlaces permanentes debajo de la página incluida';
+$lang['showdate'] = 'mostrar la fecha a continuación de las entradas al blog';
+$lang['showmdate'] = 'Mostrar las fechas modificadas debajo de la página incluida ';
+$lang['showuser'] = 'mostrar los nombres de usuarios a continuación de las entradas al blog';
+$lang['showcomments'] = 'mostrar comentarios a continuación de las entradas al blog';
+$lang['showlinkbacks'] = 'Mostrar los enlaces entrantes de la página incluida (se necesita Linkback Plugin) ';
+$lang['showtags'] = 'mostrar etiquetas a continuación de la entrada al blog';
+$lang['showeditbtn'] = 'Mostrar el botón de edición ';
+$lang['doredirect'] = 'Redirigir a la página original después de editar la página incluida ';
+$lang['doindent'] = 'Páginas incluidas en sangría relativas a la página en la que se incluyen';
+$lang['linkonly'] = 'Enlazar sólo con la página incluida en lugar de mostrar el contenido ';
+$lang['title'] = 'Usar el primer encabezado de la página en el enlace aunque el encabezado de uso esté desactivado (sólo afecta al modo de sólo enlace) ';
+$lang['pageexists'] = 'No mostrar un enlace si la página no existe (sólo afecta al modo de sólo enlace)';
+$lang['parlink'] = 'Poner un párrafo alrededor del enlace (sólo afecta al modo de sólo enlace) ';
+$lang['safeindex'] = 'Impedir la indización de metadatos de páginas incluidas no públicas';
+$lang['order'] = 'Criterios de clasificación de las entradas con varias páginas';
+$lang['order_o_id'] = 'Página de identificación';
+$lang['order_o_title'] = 'Título';
+$lang['order_o_created'] = 'Crear fecha';
+$lang['order_o_modified'] = 'Modificar fecha';
+$lang['order_o_indexmenu'] = 'orden personalizado con indexmenu syntax';
+$lang['order_o_custom'] = 'orden personalizado con el syntax incluido';
+$lang['rsort'] = 'Invertir el orden de las páginas incluidas';
+$lang['depth'] = 'El anchor máximo del espacio de nombre incluido, 0 para un anchor ilimitado';
+$lang['readmore'] = 'Mostrar o no el enlace "Leer más" sólo en caso de primera sección ';
+$lang['debugoutput'] = 'Imprimir información de depuración verbosa en el registro de depuración de DokuWiki si la opción global "allowdebug" está activada';
diff --git a/platform/www/lib/plugins/include/lang/fr/lang.php b/platform/www/lib/plugins/include/lang/fr/lang.php
new file mode 100644
index 0000000..a456138
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/fr/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Damien Raude-Morvan <drazzib@drazzib.com>
+ */
+$lang['readmore'] = 'Lire la suite...';
diff --git a/platform/www/lib/plugins/include/lang/fr/settings.php b/platform/www/lib/plugins/include/lang/fr/settings.php
new file mode 100644
index 0000000..5e3519d
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/fr/settings.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Damien Raude-Morvan <drazzib@drazzib.com>
+ * @author Stanislas Reltgen <stanislas@reltgen.net>
+ * @author bruno <bruno@ninesys.fr>
+ * @author Christian "Na_kai" Sueur <sueur.christian@gmail.com>
+ * @author Fabrice Dejaigher <fabrice@chtiland.com>
+ * @author Schplurtz le Déboulonné <schplurtz@laposte.net>
+ * @author Olivier Humbert <trebmuh@tuxfamily.org>
+ */
+$lang['noheader'] = 'Ne pas afficher la première en-tête de pages / sections incluse';
+$lang['firstseconly'] = 'Afficher uniquement la première section des billets';
+$lang['showtaglogos'] = 'Afficher l\'image de la première balise';
+$lang['showfooter'] = 'Montrer les infos sur la page incluse en dessous';
+$lang['showlink'] = 'Utiliser la première en-tête comme un lien vers la page incluse';
+$lang['showpermalink'] = 'Afficher les permaliens sous la page incluse';
+$lang['showdate'] = 'Afficher les dates sous la page incluse';
+$lang['showmdate'] = 'Afficher les dates de modification sous la page incluse';
+$lang['showuser'] = 'Afficher le nom de l\'utilisateur sous la page incluse';
+$lang['showcomments'] = 'Afficher les commentaires sous la page incluse (greffon Discussion requis)';
+$lang['showlinkbacks'] = 'Afficher les liens pointants vers la page sous la page incluse (greffon Linkback requis)';
+$lang['showtags'] = 'Afficher les étiquettes (tags) sous la page incluse (greffon Tag requis)';
+$lang['showeditbtn'] = 'Afficher le bouton d\'édition';
+$lang['doredirect'] = 'Rediriger vers la page d\'origine après l\'édition de la page incluse';
+$lang['doindent'] = 'Indenter les pages incluses par rapport à la page où elles sont incluses';
+$lang['linkonly'] = 'Faire un lien vers la page incluse plutôt que d\'afficher son contenu';
+$lang['title'] = 'Utiliser la première en-tête de la page pour le lien même si l\'option \'useheading\' n\'est pas activée (ne concerne que le mode \'lien seul\')';
+$lang['pageexists'] = 'Ne pas afficher un lien si la page n\'existe pas (ne concerne que le mode \'lien seul\')';
+$lang['parlink'] = 'Mettre le lien dans un paragraphe (ne concerne que le mode \'lien seul\')';
+$lang['safeindex'] = 'Empêcher l\'indexation des métadonnées à partir de pages incluses non-publiques';
+$lang['order'] = 'Critère de tri des inclusions multi-pages';
+$lang['order_o_id'] = 'Page ID';
+$lang['order_o_title'] = 'Titre';
+$lang['order_o_created'] = 'Date de création';
+$lang['order_o_modified'] = 'Date de modification';
+$lang['order_o_indexmenu'] = 'Ordre personnalisé avec la syntaxe de menu d\'index';
+$lang['order_o_custom'] = 'Ordre personnalisé avec la syntaxe inclure';
+$lang['rsort'] = 'Inverser l\'ordre de tri des pages incluses';
+$lang['depth'] = 'Profondeur maximale d\'inclusion de l\'espace de nom (namespace), 0 pour une profondeur illimitée';
+$lang['readmore'] = 'Affiche - ou pas - le lien \'Lire la suite\' dans le cas de l\'affichage de la première section seule';
+$lang['debugoutput'] = 'Afficher des informations de débogage verbeuses dans le journal de débogage de DokuWiki lorsque l\'option globale "allowdebug" est activée.';
diff --git a/platform/www/lib/plugins/include/lang/hr/lang.php b/platform/www/lib/plugins/include/lang/hr/lang.php
new file mode 100644
index 0000000..fad0fe3
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/hr/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Davor Turkalj <turki.bsc@gmail.com>
+ */
+$lang['readmore'] = '--> Pročitaj više...';
diff --git a/platform/www/lib/plugins/include/lang/hr/settings.php b/platform/www/lib/plugins/include/lang/hr/settings.php
new file mode 100644
index 0000000..12d6fa5
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/hr/settings.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Davor Turkalj <turki.bsc@gmail.com>
+ */
+$lang['noheader'] = 'Ne prikazuj prvi naslov uključene stranice/odjeljka';
+$lang['firstseconly'] = 'Prikaži samo prvi odjeljak uključenih stranica';
+$lang['showtaglogos'] = 'Prikaži sliku za prvu oznaku';
+$lang['showfooter'] = 'Prikaži na kraju info o uključenoj stranici';
+$lang['showlink'] = 'Poveži prvi naslov uključenih stranica';
+$lang['showpermalink'] = 'Prikaži stalne veze ispod uključene stranice';
+$lang['showdate'] = 'Prikaži datume ispod uključene stranice';
+$lang['showmdate'] = 'Prikaži datume izmjene ispod uključene stranice';
+$lang['showuser'] = 'Prikaži korisnička imena ispod uključene stranice';
+$lang['showcomments'] = 'Prikaži komentare ispod uključene stranice (potreban dodatak Discussion)';
+$lang['showlinkbacks'] = 'Prikaži povratne linkove ispod uključene stranice (potreban dodatak Linkback)';
+$lang['showtags'] = 'Prikaži oznake ispod uključene stranice (potreban dodatak Tag)';
+$lang['showeditbtn'] = 'Prikaži dugme za izmjenu';
+$lang['doredirect'] = 'Preusmjeri na originalnu stranicu nakon uređivanja uključene stranice';
+$lang['doindent'] = 'Uvuci uključenu stranicu relativno prema stranici na kojoj je uključena';
+$lang['linkonly'] = 'Prikaži poveznicu na uključenu stranicu umjesto njenog sadržaja';
+$lang['title'] = 'Koristi prvi naslov na stranici u poveznici čak i kada je "useheading" isključen (utječe samo na linkonly mod)';
+$lang['pageexists'] = 'Ne prikazuj link ako stranica ne postoji (utječe samo na linkonly mod)';
+$lang['parlink'] = 'Postavi paragraf oko poveznice (utječe samo na linkonly mod)';
+$lang['safeindex'] = 'Spriječi indeksiranje meta-podataka od uključenih stranica koje nisu javne';
+$lang['order'] = 'Uvjeti redosljeda pri uključenju više stranica';
+$lang['order_o_id'] = 'ID stranice';
+$lang['order_o_title'] = 'naslov';
+$lang['order_o_created'] = 'datum kreiranja';
+$lang['order_o_modified'] = 'datum modificiranja';
+$lang['order_o_indexmenu'] = 'poseban redoslijed prema "indexmenu" sintaksi';
+$lang['order_o_custom'] = 'poseban redoslijed prema "include" sintaksi';
+$lang['rsort'] = 'Obrnuti redoslijed uključenih stranica';
+$lang['depth'] = 'Maksimalna dubina uključenog imenskog prostora, 0 za neograničenu dubinu';
+$lang['readmore'] = 'Prikazati ili ne \'Pročitaj više\' u slučaju prikaza samo prvog odjeljka';
+$lang['debugoutput'] = 'Ispisuj dodatne informacije u debug logu dokuwiki-a, ako je omogućena globalna opcija "allowdebug"';
diff --git a/platform/www/lib/plugins/include/lang/hu/lang.php b/platform/www/lib/plugins/include/lang/hu/lang.php
new file mode 100644
index 0000000..6ef1001
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/hu/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Norbert Csík <norbert.csik@gmail.com>
+ * @author DelD <deldadam@gmail.com>
+ */
+$lang['readmore'] = 'Tovább...';
diff --git a/platform/www/lib/plugins/include/lang/hu/settings.php b/platform/www/lib/plugins/include/lang/hu/settings.php
new file mode 100644
index 0000000..352cfbe
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/hu/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Norbert Csík <norbert.csik@gmail.com>
+ * @author DelD <deldadam@gmail.com>
+ */
+$lang['noheader'] = 'Csatolt oldal/szakasz első címsorának elrejtése';
+$lang['firstseconly'] = 'Csak a csatolt oldal első bekezdésének megjelenítése';
+$lang['showtaglogos'] = 'Első címke képének megjelenítése';
+$lang['showfooter'] = 'Csatolt oldal adatainak megjelenítése lent';
+$lang['showlink'] = 'Csatolt oldal első címsora hivatkozásként';
+$lang['showpermalink'] = 'Állandó hivatkozások megjelenítése csatolt oldal alatt';
+$lang['showdate'] = 'Dátumok megjelenítése csatolt oldal alatt';
+$lang['showmdate'] = 'Módosítási dátum megjelenítése csatolt oldal alatt';
+$lang['showuser'] = 'Felhasználónevek megjelenítése csatolt oldal alatt';
+$lang['showcomments'] = 'Hozzászólások megjelenítése csatolt oldal alatt (a \'Discussion\' bővítmény szükséges hozzá)';
+$lang['showlinkbacks'] = 'Visszamutató hivatkozások megjelenítése csatolt oldal alatt (a \'Linkback\' bővítmény szükséges hozzá)';
+$lang['showtags'] = 'Címkék megjelenítése a csatolt oldal alatt (a \'Tag\' bővítmény szükséges hozzá)';
+$lang['showeditbtn'] = '\'Oldal szerkesztése\' gomb megjelenítése';
+$lang['doredirect'] = 'Átirányítás az eredeti oldalra a csatolt oldal szerkesztése után';
+$lang['usernamespace'] = 'Felhasználói oldalak névtere';
+$lang['doindent'] = 'Csatolt oldal behúzása relatíve ahhoz az oldalhoz, amelyhez csatolták';
+$lang['linkonly'] = 'Csak a csatolt oldalra mutató hivatkozás megjelenítése a teljes oldal tartalma helyett';
+$lang['title'] = 'Oldal első címsorának használat a hivatkozásban akkor is, ha a \'useheadin\' beállítás tiltott (csak akkor van hatása, ha csatolt oldal tartalma helyett hivatkozás jelenik meg)';
+$lang['pageexists'] = 'Csatolt oldal hivatkozásának elrejtése, ha az oldal még nem létezik (csak akkor van hatása, ha csatolt oldal tartalma helyett hivatkozás jelenik meg)';
+$lang['parlink'] = 'Hivatkozás elhelyezése bekezdéscímkék (<p>) között (csak akkor van hatása, ha csatolt oldal tartalma helyett hivatkozás jelenik meg)';
+$lang['safeindex'] = 'Nem nyilvános, csatolt oldalak metaadai indexelésének tiltása';
+$lang['order'] = 'Rendezési feltételek több oldal csatolása esetén';
+$lang['order_o_id'] = 'Oldalazonosító (ID)';
+$lang['order_o_title'] = 'Cím';
+$lang['order_o_created'] = 'Létrehozás dátuma';
+$lang['order_o_modified'] = 'Módosítás dátuma';
+$lang['order_o_indexmenu'] = 'Tetszőleges sorrend indexmenü szintaxisával';
+$lang['order_o_custom'] = 'Tetszőleges sorrend csatoló (include) szintaxisával';
+$lang['rsort'] = 'Csatolt oldalak sorrendjének megfordítása';
+$lang['depth'] = 'Csatolások névtereinek max. mélysége (0=végtelen)';
+$lang['readmore'] = '\'Tovább...\' hivatkozás megjelenítése, ha a csatolt oldalnak csak az első bekezdése látszik';
diff --git a/platform/www/lib/plugins/include/lang/it/lang.php b/platform/www/lib/plugins/include/lang/it/lang.php
new file mode 100644
index 0000000..c7c7401
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/it/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Italian language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Niccolo Rigacci <niccolo@rigacci.org>
+ */
+$lang['readmore'] = '→ Leggi tutto...';
diff --git a/platform/www/lib/plugins/include/lang/it/settings.php b/platform/www/lib/plugins/include/lang/it/settings.php
new file mode 100644
index 0000000..2f5ec5a
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/it/settings.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Italian language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Riccardo <riccardo.furlato@gmail.com>
+ * @author Niccolo Rigacci <niccolo@rigacci.org>
+ */
+$lang['noheader'] = 'Non mostrare la prima intestazione di pagine o sezioni incluse';
+$lang['firstseconly'] = 'Mostra nel blog solo la prima sezione degli articoli';
+$lang['showtaglogos'] = 'Mostra l\'immagine per il primo tag';
+$lang['showfooter'] = 'Mostra sotto informazioni sulla pagina inclusa';
+$lang['showlink'] = 'Mostra un link all\'articolo sotto le voci del blog';
+$lang['showpermalink'] = 'Mostra i permalinks sotto alla pagina inclusa';
+$lang['showdate'] = 'Mostra la data sotto le voci del blog';
+$lang['showmdate'] = 'Mostra i dati modificati sotto alla pagina inclusa';
+$lang['showuser'] = 'Mostra il nome dell\'autore sotto le voci del blog';
+$lang['showcomments'] = 'Mostra i commenti sotto alla pagina inclusa (serve il plugin Discussion)';
+$lang['showeditbtn'] = 'Mostra il pulsante modifica';
+$lang['doredirect'] = 'Torna alla pagina originale dopo aver editato la pagina inclusa';
+$lang['doindent'] = 'Indenta le pagine incluse relativamente alla pagina dove sono state incluse';
+$lang['linkonly'] = 'Mostra solo il link alla pagina inclusa invece di mostrarne il contenuto';
+$lang['order_o_id'] = 'ID della pagina';
+$lang['order_o_title'] = 'titolo';
+$lang['order_o_created'] = 'data di creazione';
+$lang['order_o_modified'] = 'data di modifica';
+$lang['rsort'] = 'Inverti l\'ordine delle pagine incluse';
diff --git a/platform/www/lib/plugins/include/lang/ja/lang.php b/platform/www/lib/plugins/include/lang/ja/lang.php
new file mode 100644
index 0000000..87db665
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ja/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ */
+$lang['readmore'] = '→ 続き...';
diff --git a/platform/www/lib/plugins/include/lang/ja/settings.php b/platform/www/lib/plugins/include/lang/ja/settings.php
new file mode 100644
index 0000000..1231338
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ja/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ * @author Hideaki SAWADA <chuno@live.jp>
+ */
+$lang['noheader'] = 'インクルードするページまたはセクションの最初の見だしを表示しない';
+$lang['firstseconly'] = 'インクルードするページの最初のセクションだけを表示する';
+$lang['showtaglogos'] = '(タグが設定されている場合) タグ先頭の画像を表示する';
+$lang['showfooter'] = 'インクルード部の下にフッター情報を表示する';
+$lang['showlink'] = 'インクルード部の最初の見出しをインクルード先のページまたはセクションへのリンクとする';
+$lang['showpermalink'] = 'フッター情報: ページの permalink を表示';
+$lang['showdate'] = 'フッター情報: ページ作成日付(date) を表示';
+$lang['showmdate'] = 'フッター情報: ページ修正日付(modified date) を表示';
+$lang['showuser'] = 'フッター情報: ユーザ名(username) を表示';
+$lang['showcomments'] = 'フッター情報: コメントを表示する (Discussion plugin が必要)';
+$lang['showlinkbacks'] = 'フッター情報: バックリンク(linkback) を表示 (Linkback Plugin が必要)';
+$lang['showtags'] = 'フッター情報: タグ(tag) を表示 (Tag Plugin が必要)';
+$lang['showeditbtn'] = 'インクルード先を編集するボタンを表示';
+$lang['doredirect'] = 'インクルード先の編集後、元のページにリダイレクトして戻る';
+$lang['doindent'] = 'インクルード部を元ページの当該位置での見出しレベルより1段階下げる';
+$lang['linkonly'] = 'linkonly モードをデフォルトにする: インクルードせず、指定ページまたはセクションへのリンクだけを表示';
+$lang['title'] = '(linkonly モード時): リンクタイトルに最初の見出しを使う(useheading の指定によらず適用)';
+$lang['pageexists'] = '(linkonly モード時): インクルードするページが存在しない場合は何も表示しない ';
+$lang['parlink'] = '(linkonly モード時): リンクを「段落」とする (インラインリストにする場合は無効にしてください)';
+$lang['safeindex'] = '非公開のインクルードページのメタデータをインデックス化しない';
+$lang['order'] = '(名前空間インクルード時) ページソートに使う項目';
+$lang['order_o_id'] = 'ページ ID';
+$lang['order_o_title'] = 'タイトル';
+$lang['order_o_created'] = '作成日時';
+$lang['order_o_modified'] = '修正日時';
+$lang['order_o_indexmenu'] = 'indexmenu プラグイン互換のソート方法';
+$lang['order_o_custom'] = 'include プラグイン互換のソート方法';
+$lang['rsort'] = '(名前空間インクルード時) ページソートを逆順にする';
+$lang['depth'] = '(名前空間インクルード時) インクルード対象とする名前空間の最大深さ (0:制限なし)';
+$lang['readmore'] = '最初のセクションだけの場合、「→ 続き...」リンクを表示する';
+$lang['debugoutput'] = '"allowdebug" オプションが有効な場合、DokuWiki の DEBUGLOG に詳細なデバッグ情報を出力する';
diff --git a/platform/www/lib/plugins/include/lang/ko/lang.php b/platform/www/lib/plugins/include/lang/ko/lang.php
new file mode 100644
index 0000000..e381131
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ko/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ */
+$lang['readmore'] = '→ 더 읽기...';
diff --git a/platform/www/lib/plugins/include/lang/ko/settings.php b/platform/www/lib/plugins/include/lang/ko/settings.php
new file mode 100644
index 0000000..5e6a18e
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ko/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ * @author Erial <erial2@gmail.com>
+ */
+$lang['noheader'] = '포함된 문서/문단의 첫 문단 제목을 보이지 않기';
+$lang['firstseconly'] = '포함된 문서의 첫 문단만 보이기';
+$lang['showtaglogos'] = '첫 태그에 대한 그림 보이기';
+$lang['showfooter'] = '아래에 포함된 문서 대한 정보 보이기';
+$lang['showlink'] = '포함된 문서의 첫 문단 제목에 링크';
+$lang['showpermalink'] = '포함된 문서 아래에 고유링크 보이기';
+$lang['showdate'] = '포함된 문서 아래에 날짜 보이기';
+$lang['showmdate'] = '포함된 문서 아래에 수정된 날짜 보이기';
+$lang['showuser'] = '포함된 문서 아래에 사용자 이름 보이기';
+$lang['showcomments'] = '포함된 문서 아래에 댓글 보이기 (Discussion 플러그인 필요)';
+$lang['showlinkbacks'] = '포함된 문서 아래에 링크백 보이기 (Linkback 플러그인 필요)';
+$lang['showtags'] = '포함된 문서 아래에 태그 보이기 (Tag 플러그인 필요)';
+$lang['showeditbtn'] = '편집 버튼 보이기';
+$lang['doredirect'] = '포함된 문서를 편집하고 나서 원래 문서로 넘겨주기';
+$lang['doindent'] = '원래 문서의 해당 위치에서 포함된 문서를 들여쓰기';
+$lang['linkonly'] = '내용을 보여주는 대신 포함된 문서에만 링크';
+$lang['title'] = 'useheading이 꺼져 있어도 링크에서 문서의 첫 문단 제목을 사용 (linkonly 모드만 영향을 줍니다)';
+$lang['pageexists'] = '문서가 존재하지 않을 때 링크를 표시하지 않기 (linkonly 모드만 영향을 줍니다)';
+$lang['parlink'] = '링크 주위에 문단 넣기 (linkonly 모드만 영향을 줍니다)';
+$lang['safeindex'] = '공개되지 않은 포함된 문서에서 메타데이터의 색인을 방지';
+$lang['order'] = '여러 문서로 포함의 조건 정렬';
+$lang['order_o_id'] = '문서 ID';
+$lang['order_o_title'] = '제목';
+$lang['order_o_created'] = '만든 날짜';
+$lang['order_o_modified'] = '수정한 날짜';
+$lang['order_o_indexmenu'] = 'indexmenu 문법 사용자 지정 정렬';
+$lang['order_o_custom'] = 'include 문법 사용자 지정 정렬';
+$lang['rsort'] = '포함된 문서의 정렬 순서를 반대로';
+$lang['depth'] = '이름공간 포함의 최대 깊이, 제한 없는 깊이는 0';
+$lang['readmore'] = '첫문단일 경우에만 \'더 읽기\' 링크를 보이거나 보이지 않기';
+$lang['debugoutput'] = '전역 "allowdebug" 옵션이 활성화되어 있는 경우 도쿠위키 디버그로그에 상세한 디버그 정보를 출력';
diff --git a/platform/www/lib/plugins/include/lang/nl/lang.php b/platform/www/lib/plugins/include/lang/nl/lang.php
new file mode 100644
index 0000000..3d9ac2f
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/nl/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Gijs H. van Gemert <g.v.gemert@inter.nl.net>
+ */
+$lang['readmore'] = '→ Lees verder...';
diff --git a/platform/www/lib/plugins/include/lang/nl/settings.php b/platform/www/lib/plugins/include/lang/nl/settings.php
new file mode 100644
index 0000000..e2eb526
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/nl/settings.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Mark Prins <mprins@users.sf.net>
+ * @author Johan Wijnker <johan@wijnker.eu>
+ * @author Gerrit Uitslag <klapinklapin@gmail.com>
+ */
+$lang['noheader'] = 'toon de eerste kop van de ingesloten pagina/sectie niet';
+$lang['firstseconly'] = 'toon alleen de eerste sectie van de ingesloten pagina\'s';
+$lang['showtaglogos'] = 'toon afbeelding voor het eerste label';
+$lang['showfooter'] = 'toon informatie over de pagina onder de ingesloten pagina';
+$lang['showlink'] = 'link de eerste kop van de ingesloten pagina';
+$lang['showpermalink'] = 'toon permanente link onder de ingesloten pagina';
+$lang['showdate'] = 'toon data onder de ingesloten pagina';
+$lang['showmdate'] = 'toon aanpassingsdatum onder de ingesloten pagina';
+$lang['showuser'] = 'toon gebruikersnamen onder de ingesloten pagina';
+$lang['showcomments'] = 'toon commentaar onder de ingesloten pagina (Discussion plugin vereist)';
+$lang['showlinkbacks'] = 'toon linkbacks onder de ingesloten pagina (Linkback plugin vereist)';
+$lang['showtags'] = 'toon labels onder de ingesloten pagina (Tag plugin vereist)';
+$lang['showeditbtn'] = 'toon aanpassen knop';
+$lang['doredirect'] = 'verwijs naar de originele pagina na aanpassen van de ingesloten pagina';
+$lang['doindent'] = 'spring ingesloten pagina\'s in relatief aan de pagina waarin ze ingesloten worden';
+$lang['linkonly'] = 'alleen een link naar de ingesloten pagina opnemen en niet de inhoud';
+$lang['title'] = 'gebruik de eerste kop als link ook al staat useheading uit (alleen van toepassing op linkonly modus)';
+$lang['pageexists'] = 'toon geen link als de pagina niet bestaat (alleen van toepassing op linkonly modus)';
+$lang['parlink'] = 'plaats een alinea om de link (alleen van toepassing op linkonly modus)';
+$lang['safeindex'] = 'voorkom indexering van metadata van niet-publieke ingesloten pagina\'s';
+$lang['order'] = 'volgorde criteria van insluitingen bij meerdere pagina\'s';
+$lang['order_o_id'] = 'pagina ID';
+$lang['order_o_title'] = 'titel';
+$lang['order_o_created'] = 'aanmaak datum';
+$lang['order_o_modified'] = 'aanpassingsdatum';
+$lang['order_o_indexmenu'] = 'aangepaste volgorde met indexmenu syntax';
+$lang['order_o_custom'] = 'aangepaste volgorde met include syntax';
+$lang['rsort'] = 'draai de sorteervolgorde van de ingesloten pagina\'s om';
+$lang['depth'] = 'maximum diepte van de naamruimte insluitingen, 0 voor onbeperkt';
+$lang['readmore'] = 'Toon de \'Lees verder\' link als er alleen een eerste deel is of niet';
+$lang['debugoutput'] = 'Schrijf uitgebreide debug informatie naar de DokuWiki debuglog als de globale "allowdebug" configuratieoptie is ingeschakeld';
diff --git a/platform/www/lib/plugins/include/lang/pl/lang.php b/platform/www/lib/plugins/include/lang/pl/lang.php
new file mode 100644
index 0000000..9e2eaf9
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/pl/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Bartek S <sadupl@gmail.com>
+ */
+$lang['readmore'] = '→Czytaj więcej...';
diff --git a/platform/www/lib/plugins/include/lang/pl/settings.php b/platform/www/lib/plugins/include/lang/pl/settings.php
new file mode 100644
index 0000000..35d89a6
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/pl/settings.php
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Bartek S <sadupl@gmail.com>
+ */
+$lang['showtaglogos'] = 'Pokaż obrazek dla pierwszego tagu';
+$lang['showeditbtn'] = 'Pokaż przycisk edycji';
+$lang['order_o_id'] = 'ID strony';
+$lang['order_o_title'] = 'tytuł';
+$lang['order_o_created'] = 'data utworzenia';
+$lang['order_o_modified'] = 'data modyfikacji';
diff --git a/platform/www/lib/plugins/include/lang/pt-br/lang.php b/platform/www/lib/plugins/include/lang/pt-br/lang.php
new file mode 100644
index 0000000..883c19b
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/pt-br/lang.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Portuguese language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Flávio Roberto Santos <flavio.barata@gmail.com>
+ */
+
+// custom language strings for the plugin
+$lang['readmore'] = '→ leia mais...';
+
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/lang/pt-br/settings.php b/platform/www/lib/plugins/include/lang/pt-br/settings.php
new file mode 100644
index 0000000..11cf604
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/pt-br/settings.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Portuguese language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Flávio Roberto Santos <flavio.barata@gmail.com>
+ */
+
+// for the configuration manager
+$lang['firstseconly'] = 'mostrar apenas primeira seção de registros do blog';
+$lang['showdate'] = 'mostrar datas abaixo dos registros do blog';
+$lang['showuser'] = 'mostrar usernames abaixo dos registros do blog';
+
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/lang/pt/lang.php b/platform/www/lib/plugins/include/lang/pt/lang.php
new file mode 100644
index 0000000..0de02df
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/pt/lang.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Portuguese language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ * @author Fernando Ribeiro <pinguim.ribeiro@gmail.com>
+ */
+
+// custom language strings for the plugin
+$lang['readmore'] = '→ Ler mais...';
+
+//Setup VIM: ex: et ts=2 :
diff --git a/platform/www/lib/plugins/include/lang/ru/lang.php b/platform/www/lib/plugins/include/lang/ru/lang.php
new file mode 100644
index 0000000..f8b1399
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ru/lang.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Spike <Spike@Foobar2000.Ru>
+ * @author Aleksandr Selivanov <alexgearbox@gmail.com>
+ * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
+ */
+$lang['readmore'] = 'Читать дальше...';
diff --git a/platform/www/lib/plugins/include/lang/ru/settings.php b/platform/www/lib/plugins/include/lang/ru/settings.php
new file mode 100644
index 0000000..f71c3af
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/ru/settings.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Spike <Spike@Foobar2000.Ru>
+ * @author Aleksandr Selivanov <alexgearbox@gmail.com>
+ * @author Aleksandr Selivanov <alexgearbox@yandex.ru>
+ * @author RainbowSpike <1@2.ru>
+ * @author Paulo <mragvlik@gmail.com>
+ */
+$lang['noheader'] = 'Не показывать первый заголовок внедряемых страниц, секций';
+$lang['firstseconly'] = 'Показывать только первую секцию внедряемой страницы';
+$lang['showtaglogos'] = 'Показывать изображение для первого тега';
+$lang['showfooter'] = 'Снизу показывать информацию о внедряемой странице';
+$lang['showlink'] = 'Снизу показывать статичную ссылку на внедряемую страницу';
+$lang['showpermalink'] = 'Снизу показывать пермассылку на внедряемую страницу';
+$lang['showdate'] = 'Снизу показывать дату создания внедряемой страницы';
+$lang['showmdate'] = 'Снизу показывать дату изменения внедряемой страницы';
+$lang['showuser'] = 'Снизу показывать имя пользователя';
+$lang['showcomments'] = 'Показывать комментарии ниже внедряемой страницы (требуется плагин Discussion)';
+$lang['showlinkbacks'] = 'Показывать обратные ссылки ниже внедряемой страницы (требуется плагин Linkback)';
+$lang['showtags'] = 'Показывать теги ниже внедряемой страницы (требуется плагин Tag)';
+$lang['showeditbtn'] = 'Показывать кнопку «Править»';
+$lang['doredirect'] = 'Переходить на оригинальную страницу после редактирования внедрённой страницы';
+$lang['doindent'] = 'Создавать отступ для внедряемой страницы относительно основной страницы';
+$lang['linkonly'] = 'Вместо содержимого внедряемой страницы показывать ссылку на неё';
+$lang['title'] = 'Использовать для ссылки внедряемой страницы её первый заголовок, даже если обычно они не применяются (только для режима linkonly)';
+$lang['pageexists'] = 'Не показывать ссылку внедряемой страницы, если сама она не существует (только для режима linkonly)';
+$lang['parlink'] = 'Поместить ссылку внедряемой страницы в параграф (только для режима linkonly)';
+$lang['safeindex'] = 'Закрыть индексирование метаданных от непубличных внедряемых страниц';
+$lang['order'] = 'Сортировать внедряемые страницы по';
+$lang['order_o_id'] = 'ID страницы';
+$lang['order_o_title'] = 'заголовку';
+$lang['order_o_created'] = 'дате создания';
+$lang['order_o_modified'] = 'дате изменения';
+$lang['order_o_indexmenu'] = 'настраиваемый порядок с синтаксисом Indexmenu';
+$lang['order_o_custom'] = 'настраиваемый порядок с синтаксисом Include';
+$lang['rsort'] = 'Обратить порядок сортировки внедряемых страниц';
+$lang['depth'] = 'Максимальная глубина вложений пространств имён. Укажите 0 для снятия ограничений.';
+$lang['readmore'] = 'Показывать ссылку «Читать дальше...», если выбран показ первой секции?';
+$lang['debugoutput'] = 'Выводить подробную информации об отладке в журнал отладки «Докувики» при включённой глобальной опции allowdebug';
diff --git a/platform/www/lib/plugins/include/lang/sk/lang.php b/platform/www/lib/plugins/include/lang/sk/lang.php
new file mode 100644
index 0000000..fe6464d
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sk/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Igor <korcek.igor@gmail.com>
+ */
+$lang['readmore'] = '→ čítatať viac...';
diff --git a/platform/www/lib/plugins/include/lang/sk/settings.php b/platform/www/lib/plugins/include/lang/sk/settings.php
new file mode 100644
index 0000000..4492423
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sk/settings.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Igor <korcek.igor@gmail.com>
+ */
+$lang['noheader'] = 'Nezobrazovať prvý nadpis zahrnutej stránky/sekcie';
+$lang['firstseconly'] = 'Zobraziť len prvú sekciu zahrnutej stránky';
+$lang['showtaglogos'] = 'Zobraziť obrázok pre prvý tag';
+$lang['showfooter'] = 'Zobraziť informáciu o zahrnutej stránke nižšie';
+$lang['showlink'] = 'Prepoj prvý nadpis zahrnutej stránky';
+$lang['showpermalink'] = 'Zobraziť trvalé odkazy pod zahrnutou stránkou';
+$lang['showdate'] = 'Zobraziť dátum pod zahrnutou stránkou';
+$lang['showmdate'] = 'Zobraziť dátum úpravy pod zahrnutou stránkou';
+$lang['showuser'] = 'Zobraziť užívateľov pod zahrnutou stránkou';
+$lang['showcomments'] = 'Zobraziť komentáre pod zahrnutou stránkou (potrebný Discussion plugin)';
+$lang['showlinkbacks'] = 'Zobraziť spätné odkazy pod zahrnutou stránkou (potrebný Linkback plugin)';
+$lang['showtags'] = 'Zobraziť tagy pod zahrnutou stránkou (potrebný Tag plugin)';
+$lang['showeditbtn'] = 'Zobraziť tlačítko upraviť';
+$lang['doredirect'] = 'Po úprave zahrnutej stránky presmerovať na pôvodnú stránku';
+$lang['doindent'] = 'Odsadiť zahrnuté stránky relatívne k stránke na ktorej budú zahrnuté';
+$lang['linkonly'] = 'Len odkazy bez zobrazenia obsahu';
+$lang['title'] = 'Používaj prvý nadpis stránky v odkazoch aj keď je používanie nadpisov vypnuté (ovplyvní len linkonly mód)';
+$lang['pageexists'] = 'Nezobrazovať odkaz ak stránka neexistuje (ovplyvňuje len linkonly mód)';
+$lang['parlink'] = 'Vlož odstavec k odkazu (ovplyvňuje iba mód linkonly)';
+$lang['safeindex'] = 'Zabrániť indexovaniu meta údajov z neverejných zahrnutých stránok';
+$lang['order'] = 'Kritéria radenia zahrnutých stránok pri viacerých stránkach';
+$lang['order_o_id'] = 'ID stránky';
+$lang['order_o_title'] = 'Názov';
+$lang['order_o_created'] = 'dátum vytvorenia';
+$lang['order_o_modified'] = 'dátum úpravy';
+$lang['order_o_indexmenu'] = 'vlastné poradie pomocou syntaxe indexmenu';
+$lang['order_o_custom'] = 'vlastné poradie pomocou syntaxe include';
+$lang['rsort'] = 'Prevrátiť poradie zahrnutých stránok';
+$lang['depth'] = 'Maximálna hĺbka zahrnutých menných priestorov (namespaces), 0 pre neobmedzenú hĺbku';
+$lang['readmore'] = 'Zobraziť odkaz \'Čítať viac\' iba v prípade prvej sekcie';
diff --git a/platform/www/lib/plugins/include/lang/sl/lang.php b/platform/www/lib/plugins/include/lang/sl/lang.php
new file mode 100644
index 0000000..9a9e24c
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sl/lang.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Slovenian language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Blaž Mertelj <Blaz.Mertelj@atol.si>
+ */
+
+// custom language strings for the plugin
+$lang['readmore'] = '→ Preberi več...';
+
+//Setup VIM: ex: et ts=2 : \ No newline at end of file
diff --git a/platform/www/lib/plugins/include/lang/sl/settings.php b/platform/www/lib/plugins/include/lang/sl/settings.php
new file mode 100644
index 0000000..7e9ed41
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sl/settings.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Slovenian language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Blaž Mertelj <Blaz.Mertelj@atol.si>
+ */
+
+// for the configuration manager
+$lang['firstseconly'] = 'prikaži samo prvo sekcijo blog vnosov';
+
+$lang['showlink'] = 'prikaži permalinke pod blog vnosi';
+$lang['showdate'] = 'prikaži datume pod blog vnosi';
+$lang['showuser'] = 'prikaži uporabniška imena pod blog vnosi';
+
+//Setup VIM: ex: et ts=2 : \ No newline at end of file
diff --git a/platform/www/lib/plugins/include/lang/sv/lang.php b/platform/www/lib/plugins/include/lang/sv/lang.php
new file mode 100644
index 0000000..cc8b57a
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sv/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Christer Nygren <wiki@fronet.fro.se>
+ */
+$lang['readmore'] = '→ Läs mer...';
diff --git a/platform/www/lib/plugins/include/lang/sv/settings.php b/platform/www/lib/plugins/include/lang/sv/settings.php
new file mode 100644
index 0000000..3e966d0
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/sv/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Christer Nygren <wiki@fronet.fro.se>
+ * @author Tor Härnqvist <tor@harnqvist.se>
+ */
+$lang['noheader'] = 'Visa inte första rubriken från inkluderade sidor/sektioner';
+$lang['firstseconly'] = 'visa endast första delen av inkluderad sida';
+$lang['showtaglogos'] = 'Visa bild för första tagg';
+$lang['showfooter'] = 'Visa information om inkluderad sidan nedanför';
+$lang['showlink'] = 'visa permalinks under inkluderad sida';
+$lang['showpermalink'] = 'Visa permalänk nedanför inkluderad sida';
+$lang['showdate'] = 'visa datum under inkluderad sida';
+$lang['showmdate'] = 'Visa ändringsdatum nedanför inkluderad sida';
+$lang['showuser'] = 'visa användarnamn under inkluderad sida';
+$lang['showcomments'] = 'Visa kommentarer nedanför inkluderad sida (Discussion-plugin krävs)';
+$lang['showlinkbacks'] = 'Visa tillbakalänkingar nedanför inkluderad sida (Linkback-plugin krävs)';
+$lang['showtags'] = 'Visa taggar nedanför inkluderad sida (tagg-plugin krävs)';
+$lang['showeditbtn'] = 'Visa redigera-knapp';
+$lang['doredirect'] = 'Omdirigera till originalsidan efter redigering av den inkluderade sidan';
+$lang['doindent'] = 'Gör indrag för inkluderande sidor relativt den sida som de är inkluderad på';
+$lang['linkonly'] = 'Länka enbart till den inkluderade sidan, istället för att visa dess innehåll';
+$lang['title'] = 'Visa första rubriken på sidan som länk även om rubrikvisning är inaktiverat (påverkar enbart endast länkingsinställning)';
+$lang['pageexists'] = 'Visa inte en länk om sidan inte existerar (påverkar enbart endast länkingsinställning)';
+$lang['parlink'] = 'Placera ett stycke kring länken (påverkar enbart endast länkingsinställning)';
+$lang['safeindex'] = 'Förhindra metadataindexering från icke-publika sidor';
+$lang['order'] = 'Kriterier för sortering vid inkludering av multipla sidor ';
+$lang['order_o_id'] = 'sid-ID';
+$lang['order_o_title'] = 'rubrik';
+$lang['order_o_created'] = 'skapandedatum';
+$lang['order_o_modified'] = 'ändringsdatum';
+$lang['order_o_indexmenu'] = 'användardefinierad ordning med indexmeny-syntax';
+$lang['order_o_custom'] = 'användardefinierad ordning med include-syntax';
+$lang['rsort'] = 'Omvänd sortering på inkluderade sidor';
+$lang['depth'] = 'Maximalt djup på namnrymder att inkludera, 0 för obegränsat djup';
+$lang['readmore'] = 'Visa eller gör \'Läs mer\'-länk i fall bara förstasektionen';
+$lang['debugoutput'] = 'Skriv ut mer omfattande avlusningsinformation till DokuWiki-avlusningsloggen om det globala "allowdebug"-alternativet är aktiverat';
diff --git a/platform/www/lib/plugins/include/lang/tr/lang.php b/platform/www/lib/plugins/include/lang/tr/lang.php
new file mode 100644
index 0000000..5818552
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/tr/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author İlker R. Kapaç <irifat@gmail.com>
+ */
+$lang['readmore'] = '→ Devamını oku..';
diff --git a/platform/www/lib/plugins/include/lang/tr/settings.php b/platform/www/lib/plugins/include/lang/tr/settings.php
new file mode 100644
index 0000000..7e3bffc
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/tr/settings.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author İlker R. Kapaç <irifat@gmail.com>
+ */
+$lang['noheader'] = 'Eklenen sayfaların/bölümlerin ilk başlığını gösterme';
+$lang['firstseconly'] = 'eklenen sayfaların sadece ilk bölümünü göster';
+$lang['showtaglogos'] = 'ilk etiket için resim göster';
+$lang['showfooter'] = 'alt tarafta, eklenen sayfa için bilgi göster';
+$lang['showlink'] = 'eklenen sayfanın ilk başlığını bağlantı haline getir';
+$lang['showpermalink'] = 'eklenen sayfanın altında kalıcı bağlantılar göster';
+$lang['showdate'] = 'eklenen sayfanın altında tarihleri göster';
+$lang['showmdate'] = 'eklenen sayfanın altında değiştirilme tarihlerini göster';
+$lang['showuser'] = 'eklenen sayfanın altında kullanıcı isimlerini göster';
+$lang['showcomments'] = 'eklenen sayfanın altında tartışmaları görüntüle (Bunun için Discussion eklentisi gereklidir)';
+$lang['showlinkbacks'] = 'eklenen sayfanın altında geri bağlantıları göster (Bunun için Linkback eklentisi gereklidir)';
+$lang['showtags'] = 'eklenen sayfanın altında etiketleri göster (Bunun için Tag eklentisi gereklidir)';
+$lang['showeditbtn'] = 'düzenle düğmesini göster';
+$lang['doredirect'] = 'eklenen sayfayı düzenledikten sonra orjinal sayfaya yönlendir';
+$lang['doindent'] = 'eklenen sayfaları dahil edildikleri sayfaya göre girintili yap';
+$lang['linkonly'] = 'içeriği göstermek yerine, sadece eklenen sayfaya bağlantı göster';
+$lang['title'] = 'sayfa başlığını kullanma kapalı bile olsa, sayfanın ilk başlığını bağlantıda kullan (yalnızca bağlantı göster seceneği etkinken çalışır)';
+$lang['pageexists'] = 'sayfa mevcut değilse bağlantı gösterme (yalnızca bağlantı göster seceneği etkinken çalışır)';
+$lang['parlink'] = 'bağlantıya bir paragraf ekle (yalnızca bağlantı göster seceneği etkinken çalışır)';
+$lang['safeindex'] = 'eklenmiş kamuya kapalı (non-public) sayfadan üstverinin (metadata) dizine alınmasına izin verme';
+$lang['order'] = 'çok sayfalı eklemeler için sıralama ölçütü';
+$lang['order_o_id'] = 'sayfa kimliği (ID)';
+$lang['order_o_title'] = 'başlık';
+$lang['order_o_created'] = 'oluşturma tarihi';
+$lang['order_o_modified'] = 'değiştirilme tarihi';
+$lang['order_o_indexmenu'] = 'indexmenu sözdizimi ile rasgele sıralı';
+$lang['order_o_custom'] = 'include sözdizimi ile rasgele sıralı';
+$lang['rsort'] = 'eklenen sayfaların sıralamasını ters çevir';
+$lang['depth'] = 'dahil edilecek en fazla isimalanı derinliği, sınırsız derinlik için 0';
diff --git a/platform/www/lib/plugins/include/lang/vi/lang.php b/platform/www/lib/plugins/include/lang/vi/lang.php
new file mode 100644
index 0000000..24b7703
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/vi/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Thien Hau <thienhau.9a14@gmail.com>
+ */
+$lang['readmore'] = '→ Đọc thêm...';
diff --git a/platform/www/lib/plugins/include/lang/vi/settings.php b/platform/www/lib/plugins/include/lang/vi/settings.php
new file mode 100644
index 0000000..db280b9
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/vi/settings.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author Thien Hau <thienhau.9a14@gmail.com>
+ */
+$lang['noheader'] = 'Không hiển thị đầu đề đầu tiên của các trang/phần được bao gồm';
+$lang['firstseconly'] = 'Chỉ hiển thị phần đầu tiên của các trang được bao gồm';
+$lang['showtaglogos'] = 'Hiển thị hình ảnh cho thẻ đầu tiên';
+$lang['showfooter'] = 'Hiển thị thông tin về trang được bao gồm bên dưới';
+$lang['showlink'] = 'Liên kết đầu đề đầu tiên của trang được bao gồm';
+$lang['showpermalink'] = 'Hiển thị liên kết cố định bên dưới trang được bao gồm';
+$lang['showdate'] = 'Hiển thị ngày bên dưới trang được bao gồm';
+$lang['showmdate'] = 'Hiển thị ngày sửa đổi bên dưới trang được bao gồm';
+$lang['showuser'] = 'Hiển thị tên thành viên bên dưới trang bao gồm';
+$lang['showcomments'] = 'Hiển thị nhận xét bên dưới trang được bao gồm (Cần có plugin Discussion)';
+$lang['showlinkbacks'] = 'Hiển thị linkbacks bên dưới trang được bao gồm (Cần có Plugin Linkback)';
+$lang['showtags'] = 'Hiển thị các thẻ bên dưới trang được bao gồm (Cần có Plugin Tag)';
+$lang['showeditbtn'] = 'Hiển thị nút sửa đổi';
+$lang['doredirect'] = 'Đổi hướng đến trang gốc sau khi sửa đổi trang được bao gồm';
+$lang['doindent'] = 'Thụt lề các trang được bao gồm liên quan đến trang mà chúng được đưa vào';
+$lang['linkonly'] = 'Chỉ liên kết đến trang được bao gồm thay vì hiển thị nội dung';
+$lang['title'] = 'Sử dụng đầu đề đầu tiên của trang trong liên kết ngay cả khi useheading bị tắt (chỉ ảnh hưởng đến chế độ chỉ liên kết (linkonly))';
+$lang['pageexists'] = 'Không hiển thị liên kết nếu trang không tồn tại (chỉ ảnh hưởng đến chế độ chỉ liên kết)';
+$lang['parlink'] = 'Đặt một đoạn quanh liên kết (chỉ ảnh hưởng đến chế độ chỉ liên kết)';
+$lang['safeindex'] = 'Ngăn lập chỉ mục siêu dữ liệu từ các trang được bao gồm không công khai';
+$lang['order'] = 'Xếp tiêu chí của bao gồm với nhiều trang';
+$lang['order_o_id'] = 'ID trang';
+$lang['order_o_title'] = 'tiêu đề';
+$lang['order_o_created'] = 'ngày khởi tạo';
+$lang['order_o_modified'] = 'ngày sửa đổi';
+$lang['order_o_indexmenu'] = 'Xếp tùy chỉnh với cú pháp indexmenu';
+$lang['order_o_custom'] = 'Xếp tùy chỉnh với cú pháp bao gồm';
+$lang['rsort'] = 'Đảo ngược thứ tự sắp xếp của các trang được bao gồm';
+$lang['depth'] = 'Độ sâu tối đa của không gian tên bao gồm, 0 cho không giới hạn độ sâu';
+$lang['readmore'] = 'Hiển thị hay không liên kết \'Đọc thêm\' chỉ trong trường hợp phần đầu tiên';
+$lang['debugoutput'] = 'In thông tin gỡ lỗi dài dòng vào nhật ký gỡ lỗi dokuwiki nếu tùy chọn toàn cục "allowdebug" được bật';
diff --git a/platform/www/lib/plugins/include/lang/zh/lang.php b/platform/www/lib/plugins/include/lang/zh/lang.php
new file mode 100644
index 0000000..02e49b3
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/zh/lang.php
@@ -0,0 +1,8 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['readmore'] = '→ 阅读更多...';
diff --git a/platform/www/lib/plugins/include/lang/zh/settings.php b/platform/www/lib/plugins/include/lang/zh/settings.php
new file mode 100644
index 0000000..9cc6339
--- /dev/null
+++ b/platform/www/lib/plugins/include/lang/zh/settings.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ *
+ * @author lainme <lainme993@gmail.com>
+ * @author Test2g <zccnexus@gmail.com>
+ */
+$lang['noheader'] = '不要显示所包含的页面/章节中的第一个标题';
+$lang['firstseconly'] = '仅显示所包含页面的第一个章节';
+$lang['showtaglogos'] = '对第一个标签显示图片';
+$lang['showfooter'] = '在下方显示所包含页面的信息';
+$lang['showlink'] = '对所包含页面的第一个标题加超链接';
+$lang['showpermalink'] = '在下方显示所包含页面的永久链接';
+$lang['showdate'] = '在下方显示所包含页面的日期';
+$lang['showmdate'] = '在下方显示所包含页面的修改日期';
+$lang['showuser'] = '在下方显示所包含页面的用户名';
+$lang['showcomments'] = '在下方显示所包含页面的评论数';
+$lang['showlinkbacks'] = '在下方显示所包含页面的 linkback';
+$lang['showtags'] = '在下方显示所包含页面的标签';
+$lang['showeditbtn'] = '显示编辑按钮';
+$lang['doredirect'] = '编辑所包含的页面后转向到原始页面';
+$lang['doindent'] = '相对所在页面对包含的页面进行缩进';
+$lang['linkonly'] = '仅显示到所包含页面的链接而不显示内容';
+$lang['title'] = '即使 useheading 选项关闭也使用页面的第一个标题进行超链接 (仅影响 linkonly 模式)';
+$lang['pageexists'] = '不要显示不存在的页面的链接 (仅影响 linkonly 模式)';
+$lang['parlink'] = '将一个段落环绕显示在链接旁(仅对linkonly模式有效)';
+$lang['order_o_id'] = '页面 ID';
+$lang['order_o_title'] = '标题';
+$lang['order_o_created'] = '创建日期';
+$lang['order_o_modified'] = '修改日期';
+$lang['rsort'] = '对包含的页面进行反向排序';
+$lang['depth'] = '包含命名空间的最大深度,0表示不限制';
diff --git a/platform/www/lib/plugins/include/plugin.info.txt b/platform/www/lib/plugins/include/plugin.info.txt
new file mode 100644
index 0000000..5ed4a1d
--- /dev/null
+++ b/platform/www/lib/plugins/include/plugin.info.txt
@@ -0,0 +1,7 @@
+base include
+author Michael Hamann, Gina Häussge, Christopher Smith, Michael Klier, Esther Brunner
+email michael@content-space.de
+date 2022-01-23
+name include plugin
+desc Functions to include another page in a wiki page
+url http://dokuwiki.org/plugin:include
diff --git a/platform/www/lib/plugins/include/requirements.txt b/platform/www/lib/plugins/include/requirements.txt
new file mode 100644
index 0000000..b01bbd9
--- /dev/null
+++ b/platform/www/lib/plugins/include/requirements.txt
@@ -0,0 +1,2 @@
+# requirements for testing
+https://github.com/michitux/dokuwiki-plugin-move.git lib/plugins/move
diff --git a/platform/www/lib/plugins/include/script.js b/platform/www/lib/plugins/include/script.js
new file mode 100644
index 0000000..8c1edbb
--- /dev/null
+++ b/platform/www/lib/plugins/include/script.js
@@ -0,0 +1,22 @@
+/**
+ * Javascript functionality for the include plugin
+ */
+
+/**
+ * Highlight the included section when hovering over the appropriate include edit button
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Michael Klier <chi@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+jQuery(function() {
+ jQuery('.btn_incledit')
+ .mouseover(function () {
+ jQuery(this).closest('.plugin_include_content').addClass('section_highlight');
+ })
+ .mouseout(function () {
+ jQuery('.section_highlight').removeClass('section_highlight');
+ });
+});
+
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/style.css b/platform/www/lib/plugins/include/style.css
new file mode 100644
index 0000000..63aa35a
--- /dev/null
+++ b/platform/www/lib/plugins/include/style.css
@@ -0,0 +1,53 @@
+div.dokuwiki div.plugin_include_content div.secedit {
+ float: right;
+ margin-left: 1em;
+ margin-top: 0;
+}
+
+div.dokuwiki div.inclmeta {
+ border-top: 1px dotted __border__;
+ padding-top: 0.2em;
+ color: __text_neu__;
+ font-size: 80%;
+ line-height: 1.25;
+ /*margin-top: 0.5em;*/
+ margin-bottom: 2em;
+}
+
+div.dokuwiki div.inclmeta a.permalink {
+ background: transparent url(images/link.gif) 0px 1px no-repeat;
+ padding: 1px 0px 1px 16px;
+}
+
+div.dokuwiki div.inclmeta abbr.published {
+ background: transparent url(images/date.gif) 0px 1px no-repeat;
+ padding: 1px 0px 1px 16px;
+ border-bottom: 0;
+}
+
+div.dokuwiki div.inclmeta span.author {
+ background: transparent url(images/user.gif) 0px 1px no-repeat;
+ padding: 1px 0px 1px 16px;
+}
+
+/* Disable the default interwiki icon for the user link (if there is any) */
+div.dokuwiki div.inclmeta span.author a.interwiki {
+ background: none;
+ padding: 0;
+}
+
+div.dokuwiki div.inclmeta span.comment {
+ background: transparent url(images/comment.gif) 0px 1px no-repeat;
+ padding: 1px 0px 1px 16px;
+}
+
+div.dokuwiki div.inclmeta div.tags {
+ border-top: 0;
+ font-size: 100%;
+ float: right;
+ clear: none;
+}
+
+div.dokuwiki p.include_readmore {
+ text-align: right;
+}
diff --git a/platform/www/lib/plugins/include/syntax/closelastsecedit.php b/platform/www/lib/plugins/include/syntax/closelastsecedit.php
new file mode 100644
index 0000000..a5741c8
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/closelastsecedit.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Include plugin (close last section edit)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Hamann <michael@content-space.de>
+ */
+
+class syntax_plugin_include_closelastsecedit extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Finishes the last open section edit
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+ if ($mode == 'xhtml') {
+ /** @var Doku_Renderer_xhtml $renderer */
+ list($endpos) = $data;
+ $renderer->finishSectionEdit($endpos);
+ return true;
+ }
+ return false;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/editbtn.php b/platform/www/lib/plugins/include/syntax/editbtn.php
new file mode 100644
index 0000000..4d9367f
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/editbtn.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Include plugin (editbtn header component)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Klier <chi@chimeric.de>
+ */
+
+class syntax_plugin_include_editbtn extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Renders an include edit button
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+ list($title, $hid) = $data;
+ if ($mode == 'xhtml') {
+ if (defined('SEC_EDIT_PATTERN')) { // for DokuWiki Greebo and more recent versions
+ $renderer->startSectionEdit(0, array('target' => 'plugin_include_editbtn', 'name' => $title, 'hid' => $hid));
+ } else {
+ $renderer->startSectionEdit(0, 'plugin_include_editbtn', $title);
+ }
+
+ $renderer->finishSectionEdit();
+ return true;
+ }
+ return false;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/footer.php b/platform/www/lib/plugins/include/syntax/footer.php
new file mode 100644
index 0000000..4be5ac4
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/footer.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Include plugin (footer component)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Klier <chi@chimeric.de>
+ */
+
+class syntax_plugin_include_footer extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 300;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Renders a permalink header.
+ *
+ * Code heavily copied from the header renderer from inc/parser/xhtml.php, just
+ * added an href parameter to the anchor tag linking to the wikilink.
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+
+ list($page, $sect, $sect_title, $flags, $redirect_id, $footer_lvl) = $data;
+
+ if ($mode == 'xhtml') {
+ $renderer->doc .= $this->html_footer($page, $sect, $sect_title, $flags, $footer_lvl, $renderer);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the meta line below the included page
+ * @param $renderer Doku_Renderer_xhtml The (xhtml) renderer
+ * @return string The HTML code of the footer
+ */
+ function html_footer($page, $sect, $sect_title, $flags, $footer_lvl, &$renderer) {
+ global $conf, $ID;
+
+ if(!$flags['footer']) return '';
+
+ $meta = p_get_metadata($page);
+ $exists = page_exists($page);
+ $xhtml = array();
+ // permalink
+ if ($flags['permalink']) {
+ $class = ($exists ? 'wikilink1' : 'wikilink2');
+ $url = ($sect) ? wl($page) . '#' . $sect : wl($page);
+ $name = ($sect) ? $sect_title : $page;
+ $title = ($sect) ? $page . '#' . $sect : $page;
+ if (!$title) $title = str_replace('_', ' ', noNS($page));
+ $link = array(
+ 'url' => $url,
+ 'title' => $title,
+ 'name' => $name,
+ 'target' => $conf['target']['wiki'],
+ 'class' => $class . ' permalink',
+ 'more' => 'rel="bookmark"',
+ );
+ $xhtml[] = $renderer->_formatLink($link);
+ }
+
+ // date
+ if ($flags['date'] && $exists) {
+ $date = $meta['date']['created'];
+ if ($date) {
+ $xhtml[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $date).'">'
+ . strftime($conf['dformat'], $date)
+ . '</abbr>';
+ }
+ }
+
+ // modified date
+ if ($flags['mdate'] && $exists) {
+ $mdate = $meta['date']['modified'];
+ if ($mdate) {
+ $xhtml[] = '<abbr class="published" title="'.strftime('%Y-%m-%dT%H:%M:%SZ', $mdate).'">'
+ . strftime($conf['dformat'], $mdate)
+ . '</abbr>';
+ }
+ }
+
+ // author
+ if ($flags['user'] && $exists) {
+ $author = $meta['user'];
+ if ($author) {
+ if (function_exists('userlink')) {
+ $xhtml[] = '<span class="vcard author">' . userlink($author) . '</span>';
+ } else { // DokuWiki versions < 2014-05-05 doesn't have userlink support, fall back to not providing a link
+ $xhtml[] = '<span class="vcard author">' . editorinfo($author) . '</span>';
+ }
+ }
+ }
+
+ // comments - let Discussion Plugin do the work for us
+ if (empty($sect) && $flags['comments'] && (!plugin_isdisabled('discussion')) && ($discussion = plugin_load('helper', 'discussion'))) {
+ $disc = $discussion->td($page);
+ if ($disc) $xhtml[] = '<span class="comment">' . $disc . '</span>';
+ }
+
+ // linkbacks - let Linkback Plugin do the work for us
+ if (empty($sect) && $flags['linkbacks'] && (!plugin_isdisabled('linkback')) && ($linkback = plugin_load('helper', 'linkback'))) {
+ $link = $linkback->td($page);
+ if ($link) $xhtml[] = '<span class="linkback">' . $link . '</span>';
+ }
+
+ $xhtml = implode(DOKU_LF . DOKU_TAB . '&middot; ', $xhtml);
+
+ // tags - let Tag Plugin do the work for us
+ if (empty($sect) && $flags['tags'] && (!plugin_isdisabled('tag')) && ($tag = plugin_load('helper', 'tag'))) {
+ $tags = $tag->td($page);
+ if($tags) {
+ $xhtml .= '<div class="tags"><span>' . DOKU_LF
+ . DOKU_TAB . $tags . DOKU_LF
+ . DOKU_TAB . '</span></div>' . DOKU_LF;
+ }
+ }
+
+ if (!$xhtml) $xhtml = '&nbsp;';
+ $class = 'inclmeta';
+ $class .= ' level' . $footer_lvl;
+ return '<div class="' . $class . '">' . DOKU_LF . DOKU_TAB . $xhtml . DOKU_LF . '</div>' . DOKU_LF;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/header.php b/platform/www/lib/plugins/include/syntax/header.php
new file mode 100644
index 0000000..3f14dcb
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/header.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Include plugin (permalink header component)
+ *
+ * Provides a header instruction which renders a permalink to the included page
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Gina Haeussge <osd@foosel.net>
+ * @author Michael Klier <chi@chimeric.de>
+ */
+
+class syntax_plugin_include_header extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Renders a permalink header.
+ *
+ * Code heavily copied from the header renderer from inc/parser/xhtml.php, just
+ * added an href parameter to the anchor tag linking to the wikilink.
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+ global $conf;
+
+ list($headline, $lvl, $pos, $page, $sect, $flags) = $data;
+
+ if ($mode == 'xhtml') {
+ /** @var Doku_Renderer_xhtml $renderer */
+ $hid = $renderer->_headerToLink($headline, true);
+ $renderer->toc_additem($hid, $headline, $lvl);
+ $url = ($sect) ? wl($page) . '#' . $sect : wl($page);
+ $renderer->doc .= DOKU_LF.'<h' . $lvl;
+ $classes = array();
+ if($flags['taglogos']) {
+ $tag = $this->_get_firsttag($page);
+ if($tag) {
+ $classes[] = 'include_firsttag__' . $tag;
+ }
+ }
+ // the include header instruction is always at the beginning of the first section edit inside the include
+ // wrap so there is no need to close a previous section edit.
+ if ($lvl <= $conf['maxseclevel']) {
+ if (defined('SEC_EDIT_PATTERN')) { // for DokuWiki Greebo and more recent versions
+ $classes[] = $renderer->startSectionEdit($pos, array('target' => 'section', 'name' => $headline, 'hid' => $hid));
+ } else {
+ $classes[] = $renderer->startSectionEdit($pos, 'section', $headline);
+ }
+ }
+ if ($classes) {
+ $renderer->doc .= ' class="'. implode(' ', $classes) . '"';
+ }
+ $headline = $renderer->_xmlEntities($headline);
+ $renderer->doc .= ' id="'.$hid.'"><a href="' . $url . '" title="' . $headline . '">';
+ $renderer->doc .= $headline;
+ $renderer->doc .= '</a></h' . $lvl . '>' . DOKU_LF;
+ return true;
+ } else {
+ $renderer->header($headline, $lvl, $pos);
+ }
+ return false;
+ }
+
+ /**
+ * Optionally add a CSS class for the first tag
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+ function _get_firsttag($page) {
+ if(plugin_isdisabled('tag') || (!plugin_load('helper', 'tag'))) {
+ return false;
+ }
+ $subject = p_get_metadata($page, 'subject');
+ if (is_array($subject)) {
+ $tag = $subject[0];
+ } else {
+ list($tag, $rest) = explode(' ', $subject, 2);
+ }
+ if($tag) {
+ return $tag;
+ } else {
+ return false;
+ }
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/include.php b/platform/www/lib/plugins/include/syntax/include.php
new file mode 100644
index 0000000..44b803a
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/include.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Include Plugin: displays a wiki page within another
+ * Usage:
+ * {{page>page}} for "page" in same namespace
+ * {{page>:page}} for "page" in top namespace
+ * {{page>namespace:page}} for "page" in namespace "namespace"
+ * {{page>.namespace:page}} for "page" in subnamespace "namespace"
+ * {{page>page#section}} for a section of "page"
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @author Gina Häußge, Michael Klier <dokuwiki@chimeric.de>
+ */
+
+/**
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ */
+class syntax_plugin_include_include extends DokuWiki_Syntax_Plugin {
+
+ /** @var $helper helper_plugin_include */
+ var $helper = null;
+
+ /**
+ * Get syntax plugin type.
+ *
+ * @return string The plugin type.
+ */
+ function getType() { return 'substition'; }
+
+ /**
+ * Get sort order of syntax plugin.
+ *
+ * @return int The sort order.
+ */
+ function getSort() { return 303; }
+
+ /**
+ * Get paragraph type.
+ *
+ * @return string The paragraph type.
+ */
+ function getPType() { return 'block'; }
+
+ /**
+ * Connect patterns/modes
+ *
+ * @param $mode mixed The current mode
+ */
+ function connectTo($mode) {
+ $this->Lexer->addSpecialPattern("{{page>.+?}}", $mode, 'plugin_include_include');
+ $this->Lexer->addSpecialPattern("{{section>.+?}}", $mode, 'plugin_include_include');
+ $this->Lexer->addSpecialPattern("{{namespace>.+?}}", $mode, 'plugin_include_include');
+ $this->Lexer->addSpecialPattern("{{tagtopic>.+?}}", $mode, 'plugin_include_include');
+ }
+
+ /**
+ * Handle syntax matches
+ *
+ * @param string $match The current match
+ * @param int $state The match state
+ * @param int $pos The position of the match
+ * @param Doku_Handler $handler The hanlder object
+ * @return array The instructions of the plugin
+ */
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+
+ $match = substr($match, 2, -2); // strip markup
+ list($match, $flags) = array_pad(explode('&', $match, 2), 2, '');
+
+ // break the pattern up into its parts
+ list($mode, $page, $sect) = array_pad(preg_split('/>|#/u', $match, 3), 3, null);
+ $check = false;
+ if (isset($sect)) $sect = sectionID($sect, $check);
+ $level = NULL;
+ return array($mode, $page, $sect, explode('&', $flags), $level, $pos);
+ }
+
+ /**
+ * Renders the included page(s)
+ *
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function render($format, Doku_Renderer $renderer, $data) {
+ global $ID;
+
+ // static stack that records all ancestors of the child pages
+ static $page_stack = array();
+
+ // when there is no id just assume the global $ID is the current id
+ if (empty($page_stack)) $page_stack[] = $ID;
+
+ $parent_id = $page_stack[count($page_stack)-1];
+ $root_id = $page_stack[0];
+
+ list($mode, $page, $sect, $flags, $level, $pos) = $data;
+
+ if (!$this->helper)
+ $this->helper = plugin_load('helper', 'include');
+ $flags = $this->helper->get_flags($flags);
+
+ $pages = $this->helper->_get_included_pages($mode, $page, $sect, $parent_id, $flags);
+
+ if ($format == 'metadata') {
+ /** @var Doku_Renderer_metadata $renderer */
+
+ // remove old persistent metadata of previous versions of the include plugin
+ if (isset($renderer->persistent['plugin_include'])) {
+ unset($renderer->persistent['plugin_include']);
+ unset($renderer->meta['plugin_include']);
+ }
+
+ $renderer->meta['plugin_include']['instructions'][] = compact('mode', 'page', 'sect', 'parent_id', 'flags');
+ if (!isset($renderer->meta['plugin_include']['pages']))
+ $renderer->meta['plugin_include']['pages'] = array(); // add an array for array_merge
+ $renderer->meta['plugin_include']['pages'] = array_merge($renderer->meta['plugin_include']['pages'], $pages);
+ $renderer->meta['plugin_include']['include_content'] = isset($_REQUEST['include_content']);
+ }
+
+ $secids = array();
+ if ($format == 'xhtml' || $format == 'odt') {
+ $secids = p_get_metadata($ID, 'plugin_include secids');
+ }
+
+ foreach ($pages as $page) {
+ extract($page);
+ $id = $page['id'];
+ $exists = $page['exists'];
+
+ if (in_array($id, $page_stack)) continue;
+ array_push($page_stack, $id);
+
+ // add references for backlink
+ if ($format == 'metadata') {
+ $renderer->meta['relation']['references'][$id] = $exists;
+ $renderer->meta['relation']['haspart'][$id] = $exists;
+ if (!$sect && !$flags['firstsec'] && !$flags['linkonly'] && !isset($renderer->meta['plugin_include']['secids'][$id])) {
+ $renderer->meta['plugin_include']['secids'][$id] = array('hid' => 'plugin_include__'.str_replace(':', '__', $id), 'pos' => $pos);
+ }
+ }
+
+ if (isset($secids[$id]) && $pos === $secids[$id]['pos']) {
+ $flags['include_secid'] = $secids[$id]['hid'];
+ } else {
+ unset($flags['include_secid']);
+ }
+
+ $instructions = $this->helper->_get_instructions($id, $sect, $mode, $level, $flags, $root_id, $secids);
+
+ if (!$flags['editbtn']) {
+ global $conf;
+ $maxseclevel_org = $conf['maxseclevel'];
+ $conf['maxseclevel'] = 0;
+ }
+ $renderer->nest($instructions);
+ if (isset($maxseclevel_org)) {
+ $conf['maxseclevel'] = $maxseclevel_org;
+ unset($maxseclevel_org);
+ }
+
+ array_pop($page_stack);
+ }
+
+ // When all includes have been handled remove the current id
+ // in order to allow the rendering of other pages
+ if (count($page_stack) == 1) array_pop($page_stack);
+
+ return true;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/locallink.php b/platform/www/lib/plugins/include/syntax/locallink.php
new file mode 100644
index 0000000..2a6a612
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/locallink.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Include plugin (locallink component)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Hamann <michael@content-space.de>
+ */
+
+class syntax_plugin_include_locallink extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Displays a local link to an included page
+ *
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+ global $ID;
+ if ($mode == 'xhtml') {
+ /** @var Doku_Renderer_xhtml $renderer */
+ list($hash, $name, $id) = $data;
+ // construct title in the same way it would be done for internal links
+ $default = $renderer->_simpleTitle($id);
+ $name = $renderer->_getLinkTitle($name, $default, $isImage, $id);
+ $title = $ID.' ↵';
+ $renderer->doc .= '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
+ $renderer->doc .= $name;
+ $renderer->doc .= '</a>';
+ return true;
+ }
+ return false;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/readmore.php b/platform/www/lib/plugins/include/syntax/readmore.php
new file mode 100644
index 0000000..689e11d
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/readmore.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Include plugin (editbtn header component)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Hamann <michael@content-space.de>
+ */
+
+class syntax_plugin_include_readmore extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ function render($mode, Doku_Renderer $renderer, $data) {
+ list($page) = $data;
+
+ if ($mode == 'xhtml') {
+ $renderer->doc .= DOKU_LF.'<p class="include_readmore">'.DOKU_LF;
+ } else {
+ $renderer->p_open();
+ }
+
+ $renderer->internallink($page, $this->getLang('readmore'));
+
+ if ($mode == 'xhtml') {
+ $renderer->doc .= DOKU_LF.'</p>'.DOKU_LF;
+ } else {
+ $renderer->p_close();
+ }
+
+ return true;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/include/syntax/sorttag.php b/platform/www/lib/plugins/include/syntax/sorttag.php
new file mode 100644
index 0000000..c7704ba
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/sorttag.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Include plugin sort order tag, idea and parts of the code copied from the indexmenu plugin.
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Samuele Tognini <samuele@netsons.org>
+ * @author Michael Hamann <michael@content-space.de>
+ *
+ */
+class syntax_plugin_include_sorttag extends DokuWiki_Syntax_Plugin {
+
+ /**
+ * What kind of syntax are we?
+ */
+ public function getType(){
+ return 'substition';
+ }
+
+ /**
+ * The paragraph type - block, we don't need paragraph tags
+ *
+ * @return string The paragraph type
+ */
+ public function getPType() {
+ return 'block';
+ }
+
+ /**
+ * Where to sort in?
+ */
+ public function getSort(){
+ return 139;
+ }
+
+ /**
+ * Connect pattern to lexer
+ */
+ public function connectTo($mode) {
+ $this->Lexer->addSpecialPattern('{{include_n>.+?}}',$mode,'plugin_include_sorttag');
+ }
+
+ /**
+ * Handle the match
+ */
+ public function handle($match, $state, $pos, Doku_Handler $handler){
+ $match = substr($match,12,-2);
+ return array($match);
+ }
+
+ /**
+ * Render output
+ */
+ public function render($mode, Doku_Renderer $renderer, $data) {
+ if ($mode === 'metadata') {
+ /** @var Doku_Renderer_metadata $renderer */
+ $renderer->meta['include_n'] = $data[0];
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/include/syntax/wrap.php b/platform/www/lib/plugins/include/syntax/wrap.php
new file mode 100644
index 0000000..1cb630c
--- /dev/null
+++ b/platform/www/lib/plugins/include/syntax/wrap.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Include plugin (wrapper component)
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Michael Klier <chi@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+
+class syntax_plugin_include_wrap extends DokuWiki_Syntax_Plugin {
+
+ function getType() {
+ return 'formatting';
+ }
+
+ function getSort() {
+ return 50;
+ }
+
+ function handle($match, $state, $pos, Doku_Handler $handler) {
+ // this is a syntax plugin that doesn't offer any syntax, so there's nothing to handle by the parser
+ }
+
+ /**
+ * Wraps the included page in a div and writes section edits for the action component
+ * so it can detect where an included page starts/ends.
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ * @author Michael Hamann <michael@content-space.de>
+ */
+ function render($mode, Doku_Renderer $renderer, $data) {
+ if ($mode == 'xhtml') {
+ $state = array_shift($data);
+ switch($state) {
+ case 'open':
+ list($page, $redirect, $secid) = $data;
+ if ($redirect) {
+ if (defined('SEC_EDIT_PATTERN')) { // for DokuWiki Greebo and more recent versions
+ $renderer->startSectionEdit(0, array('target' => 'plugin_include_start', 'name' => $page, 'hid' => ''));
+ } else {
+ $renderer->startSectionEdit(0, 'plugin_include_start', $page);
+ }
+ } else {
+ if (defined('SEC_EDIT_PATTERN')) { // for DokuWiki Greebo and more recent versions
+ $renderer->startSectionEdit(0, array('target' => 'plugin_include_start_noredirect', 'name' => $page, 'hid' => ''));
+ } else {
+ $renderer->startSectionEdit(0, 'plugin_include_start_noredirect', $page);
+ }
+ }
+ $renderer->finishSectionEdit();
+ // Start a new section with type != section so headers in the included page
+ // won't print section edit buttons of the parent page
+ if (defined('SEC_EDIT_PATTERN')) { // for DokuWiki Greebo and more recent versions
+ $renderer->startSectionEdit(0, array('target' => 'plugin_include_end', 'name' => $page, 'hid' => ''));
+ } else {
+ $renderer->startSectionEdit(0, 'plugin_include_end', $page);
+ }
+ if ($secid === NULL) {
+ $id = '';
+ } else {
+ $id = ' id="'.$secid.'"';
+ }
+ $renderer->doc .= '<div class="plugin_include_content plugin_include__' . $page .'"'.$id.'>' . DOKU_LF;
+ if (is_a($renderer,'renderer_plugin_dw2pdf')) {
+ $renderer->doc .= '<a name="'.$secid.'" />';
+ }
+ break;
+ case 'close':
+ $renderer->finishSectionEdit();
+ $renderer->doc .= '</div>' . DOKU_LF;
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+}
+// vim:ts=4:sw=4:et:
diff --git a/platform/www/lib/plugins/meta/_test/rendering.test.php b/platform/www/lib/plugins/meta/_test/rendering.test.php
new file mode 100644
index 0000000..3c39613
--- /dev/null
+++ b/platform/www/lib/plugins/meta/_test/rendering.test.php
@@ -0,0 +1,80 @@
+<?php
+// must be run within Dokuwiki
+if (!defined('DOKU_INC')) die();
+
+/**
+ * Test cases for the meta plugin
+ */
+class plugin_meta_rendering_test extends DokuWikiTest {
+
+ public function setUp() : void {
+ $this->pluginsEnabled[] = 'meta';
+ parent::setUp();
+ }
+
+ public function test_meta_description() {
+ $text = "My page content";
+ saveWikiText('description_test', $text, 'Created');
+ self::assertEquals($text, p_get_metadata('description_test', 'description abstract', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF . '~~META:description abstract=My abstract~~';
+
+ saveWikiText('description_test', $text, 'Added meta');
+
+ self::assertEquals('My abstract', p_get_metadata('description_test', 'description abstract', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF . '~~META:description foobar=bar~~';
+ saveWikiText('description_test', $text, 'Updated meta');
+ self::assertEquals('My abstract', p_get_metadata('description_test', 'description abstract', METADATA_RENDER_UNLIMITED));
+ self::assertEquals('bar', p_get_metadata('description_test', 'description foobar', METADATA_RENDER_UNLIMITED));
+ }
+
+ public function test_meta_description_with_persistent_description() {
+ $text = "My page content";
+ $id = 'description_test';
+ saveWikiText($id, $text, 'Created');
+ self::assertEquals($text, p_get_metadata($id, 'description abstract', METADATA_RENDER_UNLIMITED));
+
+ p_set_metadata($id, array('description' => array('abstract' => 'Persistent description')), false, true);
+ self::assertEquals('Persistent description', p_get_metadata($id, 'description abstract', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF . '~~META:description abstract=My abstract~~';
+
+ saveWikiText($id, $text, 'Added meta');
+
+ self::assertEquals('My abstract', p_get_metadata($id, 'description abstract', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF . '~~META:description foobar=bar~~';
+ saveWikiText($id, $text, 'Updated meta');
+ self::assertEquals('My abstract', p_get_metadata($id, 'description abstract', METADATA_RENDER_UNLIMITED));
+ self::assertEquals('bar', p_get_metadata($id, 'description foobar', METADATA_RENDER_UNLIMITED));
+ }
+
+ public function test_relation_references_with_link() {
+ $text = "My page with a [[link_target|Link]].";
+ $id = "source";
+
+ saveWikiText($id, $text, 'Created');
+
+ self::assertEquals(array('link_target' => false), p_get_metadata($id, 'relation references', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF. "~~META:relation references=foo~~";
+ saveWikiText($id, $text, 'Updated');
+
+ self::assertEquals(array('foo' => false, 'link_target' => false), p_get_metadata($id, 'relation references', METADATA_RENDER_UNLIMITED));
+ }
+
+ public function test_relation_references_without_link() {
+ $text = "My page without a link.";
+ $id = "source";
+
+ saveWikiText($id, $text, 'Created');
+
+ self::assertEquals(null, p_get_metadata($id, 'relation references', METADATA_RENDER_UNLIMITED));
+
+ $text .= DOKU_LF . "~~META:relation references=foo~~";
+ saveWikiText($id, $text, 'Updated');
+
+ self::assertEquals(array('foo' => false), p_get_metadata($id, 'relation references', METADATA_RENDER_UNLIMITED));
+ }
+}
diff --git a/platform/www/lib/plugins/meta/plugin.info.txt b/platform/www/lib/plugins/meta/plugin.info.txt
new file mode 100644
index 0000000..b1e63e4
--- /dev/null
+++ b/platform/www/lib/plugins/meta/plugin.info.txt
@@ -0,0 +1,7 @@
+base meta
+author Michael Hamann
+email michael@content-space.de
+date 2021-10-16
+name Meta plugin
+desc Set Metadata for the current page. (previous authors: Esther Brunner, Gina Häußge, Michael Klier)
+url https://www.dokuwiki.org/plugin:meta
diff --git a/platform/www/lib/plugins/meta/syntax.php b/platform/www/lib/plugins/meta/syntax.php
new file mode 100644
index 0000000..733e5b5
--- /dev/null
+++ b/platform/www/lib/plugins/meta/syntax.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * Meta Plugin: Sets metadata for the current page
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Esther Brunner <wikidesign@gmail.com>
+ */
+if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
+if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
+require_once(DOKU_PLUGIN.'syntax.php');
+
+/**
+ * All DokuWiki plugins to extend the parser/rendering mechanism
+ * need to inherit from this class
+ */
+class syntax_plugin_meta extends DokuWiki_Syntax_Plugin
+{
+ function getType()
+ {
+ return 'substition';
+ }
+
+ function getSort()
+ {
+ return 99;
+ }
+
+ function connectTo($mode)
+ {
+ $this->Lexer->addSpecialPattern('~~META:.*?~~',$mode,'plugin_meta');
+ }
+
+ /**
+ * Handle the match
+ */
+ public function handle($match, $state, $pos, Doku_Handler $handler)
+ {
+ // strip ~~META: from start and ~~ from end
+ $match = substr($match,7,-2);
+
+ $data = array();
+ $pairs = explode('&', $match);
+ foreach ($pairs as $pair) {
+ list($key, $value) = explode('=', $pair, 2);
+ list($key, $subkey) = explode(' ', $key, 2);
+ if (trim($subkey)) {
+ $data[trim($key)][trim($subkey)] = trim($value);
+ } else {
+ $data[trim($key)] = trim($value);
+ }
+ }
+ $data = array_change_key_case($data, CASE_LOWER);
+
+ return $data;
+ }
+
+ /**
+ * Create output
+ */
+ public function render($mode, Doku_Renderer $renderer, $data)
+ {
+ if ($mode == 'xthml') {
+ // don't output anything
+ return true;
+ } elseif ($mode == 'metadata') {
+ /** @var Doku_Renderer_metadata $renderer */
+
+ // do some validation / conversion for date metadata
+ if (isset($data['date'])) {
+ if (is_array($data['date'])) {
+ foreach ($data['date'] as $key => $date) {
+ $date = $this->convertDate(trim($date));
+ if (!$date) {
+ unset($data['date'][$key]);
+ } else {
+ $data['date'][$key] = $date;
+ }
+ }
+ } else {
+ unset($data['date']);
+ }
+ }
+
+ // now merge the arrays
+ $protected = array('description', 'date', 'contributor');
+ foreach ($data as $key => $value) {
+
+ // be careful with sub-arrays of $meta['relation']
+ if ($key == 'relation') {
+ foreach ($value as $subkey => $subvalue) {
+ if ($subkey == 'media') {
+ $renderer->meta[$key][$subkey][cleanID($subvalue)] = @file_exists(mediaFN($subvalue));
+ } elseif ($subkey == 'firstimage') {
+ /* The metadata renderer overrides the first image value with its internal value at the end.
+ Therefore the only thing we can do is setting this internal value by calling _firstimage.
+ This fails if there has already been a first image saved. */
+ $renderer->_firstimage($subvalue);
+ } else {
+ // for everything else assume that we have a page id
+ $renderer->meta[$key][$subkey][cleanID($subvalue)] = page_exists($subvalue);
+ }
+ }
+ } elseif (in_array($key, $protected)) {
+ // be careful with some sensitive arrays of $meta
+ if (is_array($renderer->meta) && is_array($value) && array_key_exists($key, $renderer->meta)) {
+ $renderer->meta[$key] = array_merge($renderer->meta[$key], (array)$value);
+ } else {
+ $renderer->meta[$key] = $value;
+ }
+ } else {
+ // no special treatment for the rest
+ $renderer->meta[$key] = $value;
+ }
+ }
+ }
+ }
+
+ /**
+ * converts YYYY-MM-DD[ hh:mm:ss][ -> [YYYY-MM-DD ]hh:mm:ss] to PHP timestamps
+ */
+ private function convertDate($date)
+ {
+ list($start, $end) = explode('->', $date, 2);
+
+ if (!$end) {
+ // single date
+ list($date, $time) = explode(' ', trim($start), 2);
+ if (!preg_match('/\d{4}\-\d{2}\-\d{2}/', $date)) {
+ return false;
+ }
+ $time = $this->autocompleteTime($time);
+ return strtotime($date.' '.$time);
+ } else {
+ // duration
+
+ // start
+ list($startdate, $starttime) = explode(' ', trim($start), 2);
+ $startdate = $this->autocompleteDate($startdate);
+ if (!$startdate) {
+ return false;
+ }
+ $starttime = $this->autocompleteTime($starttime);
+
+ // end
+ list($enddate, $endtime) = explode(' ', trim($end), 2);
+ if (!trim($endtime)) {
+ // only time given
+ $end_date = $this->autocompleteDate($enddate, true);
+ if (!$end_date) {
+ $endtime = $this->autocompleteTime($enddate, true);
+ $enddate = $startdate;
+ } else {
+ // only date given
+ $enddate = $end_date;
+ $endtime = '23:59:59';
+ }
+ } else {
+ $enddate = $this->autocompleteDate($enddate, true);
+ if (!$enddate) {
+ $enddate = $startdate;
+ }
+ $endtime = $this->autocompleteTime($endtime, true);
+ }
+
+ $start = strtotime($startdate.' '.$starttime);
+ $end = strtotime($enddate.' '.$endtime);
+ if (!$start || !$end) {
+ return false;
+ }
+ return array('start' => $start, 'end' => $end);
+ }
+ }
+
+ private function autocompleteDate($date, $end=false)
+ {
+ if (!preg_match('/^\d{4}\-\d{2}\-\d{2}$/', $date)) {
+ if (preg_match('/^\d{4}\-\d{2}$/', $date)) {
+ // we don't know which month
+ return ($end) ? $date.'-28' : $date.'-01';
+ } elseif (preg_match('/^\d{4}$/', $date)) {
+ return ($end) ? $date.'-12-31' : $date.'-01-01';
+ } else {
+ return false;
+ }
+ } else {
+ return $date;
+ }
+ }
+
+ private function autocompleteTime($time, $end=false)
+ {
+ if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $time)) {
+ if (preg_match('/^\d{2}:\d{2}$/', $time)) {
+ return ($end) ? $time.':59' : $time.':00';
+ } elseif (preg_match('/^\d{2}$/', $time)) {
+ return ($end) ? $time.':59:59': $time.':00:00';
+ } else {
+ return ($end) ? '23:59:59' : '00:00:00';
+ }
+ } else {
+ return $time;
+ }
+ }
+}
+// vim:ts=4:sw=4:et:enc=utf-8:
diff --git a/platform/www/lib/plugins/refnotes/action.php b/platform/www/lib/plugins/refnotes/action.php
new file mode 100644
index 0000000..6f6af89
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/action.php
@@ -0,0 +1,634 @@
+<?php
+
+/**
+ * Plugin RefNotes: Event handler
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+require_once(DOKU_PLUGIN . 'refnotes/core.php');
+require_once(DOKU_PLUGIN . 'refnotes/instructions.php');
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class action_plugin_refnotes extends DokuWiki_Action_Plugin {
+ use refnotes_localization_plugin;
+
+ private $afterParserHandlerDone;
+ private $beforeAjaxCallUnknown;
+ private $beforeParserCacheUse;
+ private $beforeParserWikitextPreprocess;
+ private $beforeTplMetaheaderOutput;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ refnotes_localization::initialize($this);
+
+ $this->afterParserHandlerDone = new refnotes_after_parser_handler_done();
+ $this->beforeAjaxCallUnknown = new refnotes_before_ajax_call_unknown();
+ $this->beforeParserCacheUse = new refnotes_before_parser_cache_use();
+ $this->beforeParserWikitextPreprocess = new refnotes_before_parser_wikitext_preprocess();
+ $this->beforeTplMetaheaderOutput = new refnotes_before_tpl_metaheader_output();
+ }
+
+ /**
+ * Register callbacks
+ */
+ public function register(Doku_Event_Handler $controller) {
+ $this->afterParserHandlerDone->register($controller);
+ $this->beforeAjaxCallUnknown->register($controller);
+ $this->beforeParserCacheUse->register($controller);
+ $this->beforeParserWikitextPreprocess->register($controller);
+ $this->beforeTplMetaheaderOutput->register($controller);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_after_parser_handler_done {
+
+ /**
+ * Register callback
+ */
+ public function register($controller) {
+ $controller->register_hook('PARSER_HANDLER_DONE', 'AFTER', $this, 'handle');
+ }
+
+ /**
+ *
+ */
+ public function handle($event, $param) {
+ refnotes_parser_core::getInstance()->exitParsingContext($event->data);
+
+ /* We need a new instance of mangler for each event because we can trigger it recursively
+ * by loading reference database or by parsing structured notes.
+ */
+ $mangler = new refnotes_instruction_mangler($event);
+
+ $mangler->process();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_instruction_mangler {
+
+ private $core;
+ private $calls;
+ private $paragraphReferences;
+ private $referenceGroup;
+ private $hidden;
+ private $inReference;
+
+ /**
+ * Constructor
+ */
+ public function __construct($event) {
+ $this->core = new refnotes_action_core();
+ $this->calls = new refnotes_instruction_list($event);
+ $this->paragraphReferences = array();
+ $this->referenceGroup = array();
+ $this->hidden = true;
+ $this->inReference = false;
+ }
+
+ /**
+ *
+ */
+ public function process() {
+ $this->scanInstructions();
+
+ if ($this->core->getNamespaceCount() > 0) {
+ $this->insertNotesInstructions($this->core->getStyles(), 'refnotes_notes_style_instruction');
+ $this->insertNotesInstructions($this->core->getMappings(), 'refnotes_notes_map_instruction');
+ $this->renderLeftovers();
+
+ $this->calls->applyChanges();
+
+ $this->renderStructuredNotes();
+
+ $this->calls->applyChanges();
+ }
+ }
+
+ /**
+ *
+ */
+ private function scanInstructions() {
+ foreach ($this->calls as $call) {
+ $this->markHiddenReferences($call);
+ $this->markReferenceGroups($call);
+ $this->markScopeLimits($call);
+ $this->extractStyles($call);
+ $this->extractMappings($call);
+ }
+ }
+
+ /**
+ *
+ */
+ private function markHiddenReferences($call) {
+ switch ($call->getName()) {
+ case 'p_open':
+ $this->paragraphReferences = array();
+ $this->hidden = true;
+ break;
+
+ case 'p_close':
+ if ($this->hidden) {
+ foreach ($this->paragraphReferences as $call) {
+ $call->setRefnotesAttribute('hidden', true);
+ }
+ }
+ break;
+
+ case 'cdata':
+ if (!$this->inReference && !empty(trim($call->getData(0)))) {
+ $this->hidden = false;
+ }
+ break;
+
+ case 'plugin_refnotes_references':
+ switch ($call->getPluginData(0)) {
+ case 'start':
+ $this->inReference = true;
+ break;
+
+ case 'render':
+ $this->inReference = false;
+ $this->paragraphReferences[] = $call;
+ break;
+ }
+ break;
+
+ default:
+ if (!$this->inReference) {
+ $this->hidden = false;
+ }
+ break;
+ }
+ }
+
+ /**
+ *
+ */
+ private function markReferenceGroups($call) {
+ if (($call->getName() == 'plugin_refnotes_references') && ($call->getPluginData(0) == 'render')) {
+ if (!empty($this->referenceGroup)) {
+ $groupNamespace = $this->referenceGroup[0]->getRefnotesAttribute('ns');
+
+ if ($call->getRefnotesAttribute('ns') != $groupNamespace) {
+ $this->closeReferenceGroup();
+ }
+ }
+
+ $this->referenceGroup[] = $call;
+ }
+ elseif (!$this->inReference && !empty($this->referenceGroup)) {
+ // Allow whitespace "cdata" istructions between references in a group
+ if ($call->getName() == 'cdata' && empty(trim($call->getData(0)))) {
+ return;
+ }
+
+ $this->closeReferenceGroup();
+ }
+ }
+
+ /**
+ *
+ */
+ private function closeReferenceGroup() {
+ $count = count($this->referenceGroup);
+
+ if ($count > 1) {
+ $this->referenceGroup[0]->setRefnotesAttribute('group', 'open');
+
+ for ($i = 1; $i < $count - 1; $i++) {
+ $this->referenceGroup[$i]->setRefnotesAttribute('group', 'hold');
+ }
+
+ $this->referenceGroup[$count - 1]->setRefnotesAttribute('group', 'close');
+ }
+
+ $this->referenceGroup = array();
+ }
+
+ /**
+ *
+ */
+ private function markScopeLimits($call) {
+ switch ($call->getName()) {
+ case 'plugin_refnotes_references':
+ if ($call->getPluginData(0) == 'render') {
+ $this->core->markScopeStart($call->getRefnotesAttribute('ns'), $call->getIndex());
+ }
+ break;
+
+ case 'plugin_refnotes_notes':
+ $this->core->markScopeEnd($call->getRefnotesAttribute('ns'), $call->getIndex());
+ break;
+ }
+ }
+
+ /**
+ * Extract style data and replace "split" instructions with "render"
+ */
+ private function extractStyles($call) {
+ if (($call->getName() == 'plugin_refnotes_notes') && ($call->getPluginData(0) == 'split')) {
+ $this->core->addStyle($call->getRefnotesAttribute('ns'), $call->getPluginData(2));
+
+ $call->setPluginData(0, 'render');
+ $call->unsetPluginData(2);
+ }
+ }
+
+ /**
+ * Extract namespace mapping info
+ */
+ private function extractMappings($call) {
+ if ($call->getName() == 'plugin_refnotes_notes') {
+ $map = $call->getRefnotesAttribute('map');
+
+ if (!empty($map)) {
+ $this->core->addMapping($call->getRefnotesAttribute('ns'), $map);
+ $call->unsetRefnotesAttribute('map');
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function insertNotesInstructions($stash, $instruction) {
+ if ($stash->getCount() == 0) {
+ return;
+ }
+
+ $stash->sort();
+
+ foreach ($stash->getIndex() as $index) {
+ foreach ($stash->getAt($index) as $data) {
+ $this->calls->insert($index, new $instruction($data->getNamespace(), $data->getData()));
+ }
+ }
+ }
+
+ /**
+ * Insert render call at the very bottom of the page
+ */
+ private function renderLeftovers() {
+ $this->calls->append(new refnotes_notes_render_instruction('*'));
+ }
+
+ /**
+ *
+ */
+ private function renderStructuredNotes() {
+ $this->core->reset();
+
+ foreach ($this->calls as $call) {
+ $this->styleNamespaces($call);
+ $this->setNamespaceMappings($call);
+ $this->addReferences($call);
+ $this->rewriteReferences($call);
+ }
+ }
+
+ /**
+ *
+ */
+ private function styleNamespaces($call) {
+ if (($call->getName() == 'plugin_refnotes_notes') && ($call->getPluginData(0) == 'style')) {
+ $this->core->styleNamespace($call->getRefnotesAttribute('ns'), $call->getPluginData(2));
+ }
+ }
+
+ /**
+ *
+ */
+ private function setNamespaceMappings($call) {
+ if (($call->getName() == 'plugin_refnotes_notes') && ($call->getPluginData(0) == 'map')) {
+ $this->core->setNamespaceMapping($call->getRefnotesAttribute('ns'), $call->getPluginData(2));
+ }
+ }
+
+ /**
+ *
+ */
+ private function addReferences($call) {
+ if (($call->getName() == 'plugin_refnotes_references') && ($call->getPluginData(0) == 'render')) {
+ $attributes = $call->getPluginData(1);
+ $data = (count($call->getData(1)) > 2) ? $call->getPluginData(2) : array();
+ $reference = $this->core->addReference($attributes, $data, $call);
+
+ if ($call->getPrevious()->getName() != 'plugin_refnotes_references') {
+ $reference->getNote()->setText('defined');
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function rewriteReferences($call) {
+ if (($call->getName() == 'plugin_refnotes_notes') && ($call->getPluginData(0) == 'render')) {
+ $this->core->rewriteReferences($call->getRefnotesAttribute('ns'), $call->getRefnotesAttribute('limit'));
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_before_ajax_call_unknown {
+
+ /**
+ * Register callback
+ */
+ public function register($controller) {
+ $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle');
+ }
+
+ /**
+ *
+ */
+ public function handle($event, $param) {
+ global $conf;
+
+ if ($event->data == 'refnotes-admin') {
+ $event->preventDefault();
+ $event->stopPropagation();
+
+ /* Check admin rights */
+ if (auth_quickaclcheck($conf['start']) < AUTH_ADMIN) {
+ die('access denied');
+ }
+
+ switch ($_POST['action']) {
+ case 'load-settings':
+ $this->sendConfig();
+ break;
+
+ case 'save-settings':
+ $this->saveConfig($_POST['settings']);
+ break;
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function sendResponse($contentType, $data) {
+ static $cookie = '{B27067E9-3DDA-4E31-9768-E66F23D18F4A}';
+
+ header('Content-Type: ' . $contentType);
+ print($cookie . $data . $cookie);
+ }
+
+ /**
+ *
+ */
+ private function sendConfig() {
+ $namespace = refnotes_configuration::load('namespaces');
+ $namespace = $this->translateStyles($namespace, 'dw', 'js');
+
+ $config['general'] = refnotes_configuration::load('general');
+ $config['namespaces'] = $namespace;
+ $config['notes'] = refnotes_configuration::load('notes');
+
+ $this->sendResponse('application/x-suggestions+json', json_encode($config));
+ }
+
+ /**
+ *
+ */
+ private function saveConfig($config) {
+ global $config_cascade;
+
+ $config = json_decode($config, true);
+
+ $namespace = $config['namespaces'];
+ $namespace = $this->translateStyles($namespace, 'js', 'dw');
+
+ $saved = refnotes_configuration::save('general', $config['general']);
+ $saved = $saved && refnotes_configuration::save('namespaces', $namespace);
+ $saved = $saved && refnotes_configuration::save('notes', $config['notes']);
+
+ if ($config['general']['reference-db-enable']) {
+ $saved = $saved && $this->setupReferenceDatabase($config['general']['reference-db-namespace']);
+ }
+
+ /* Touch local config file to expire the cache */
+ $saved = $saved && touch(reset($config_cascade['main']['local']));
+
+ $this->sendResponse('text/plain', $saved ? 'saved' : 'failed');
+ }
+
+ /**
+ *
+ */
+ private function translateStyles($namespace, $from, $to) {
+ foreach ($namespace as &$ns) {
+ foreach ($ns as $styleName => &$style) {
+ $style = $this->translateStyle($styleName, $style, $from, $to);
+ }
+ }
+
+ return $namespace;
+ }
+
+ /**
+ *
+ */
+ private function translateStyle($styleName, $style, $from, $to) {
+ static $dictionary = array(
+ 'refnote-id' => array(
+ 'dw' => array('1' , 'a' , 'A' , 'i' , 'I' , '*' , 'name' ),
+ 'js' => array('numeric', 'latin-lower', 'latin-upper', 'roman-lower', 'roman-upper', 'stars', 'note-name')
+ ),
+ 'reference-base' => array(
+ 'dw' => array('sup' , 'text' ),
+ 'js' => array('super', 'normal-text')
+ ),
+ 'reference-format' => array(
+ 'dw' => array(')' , '()' , ']' , '[]' ),
+ 'js' => array('right-parent', 'parents', 'right-bracket', 'brackets')
+ ),
+ 'reference-group' => array(
+ 'dw' => array('none' , ',' , 's' ),
+ 'js' => array('group-none', 'group-comma', 'group-semicolon')
+ ),
+ 'multi-ref-id' => array(
+ 'dw' => array('ref' , 'note' ),
+ 'js' => array('ref-counter', 'note-counter')
+ ),
+ 'note-id-base' => array(
+ 'dw' => array('sup' , 'text' ),
+ 'js' => array('super', 'normal-text')
+ ),
+ 'note-id-format' => array(
+ 'dw' => array(')' , '()' , ']' , '[]' , '.' ),
+ 'js' => array('right-parent', 'parents', 'right-bracket', 'brackets', 'dot')
+ ),
+ 'back-ref-base' => array(
+ 'dw' => array('sup' , 'text' ),
+ 'js' => array('super', 'normal-text')
+ ),
+ 'back-ref-format' => array(
+ 'dw' => array('1' , 'a' , 'note' ),
+ 'js' => array('numeric', 'latin', 'note-id')
+ ),
+ 'back-ref-separator' => array(
+ 'dw' => array(',' ),
+ 'js' => array('comma')
+ ),
+ 'struct-refs' => array(
+ 'dw' => array('off' , 'on' ),
+ 'js' => array('disable', 'enable')
+ )
+ );
+
+ if (array_key_exists($styleName, $dictionary)) {
+ $key = array_search($style, $dictionary[$styleName][$from]);
+
+ if ($key !== false) {
+ $style = $dictionary[$styleName][$to][$key];
+ }
+ }
+
+ return $style;
+ }
+
+ /**
+ *
+ */
+ private function setupReferenceDatabase($namespace) {
+ $success = true;
+ $source = refnotes_localization::getInstance()->getFileName('__template');
+ $destination = wikiFN(cleanID($namespace . ':template'));
+ $destination = preg_replace('/template.txt$/', '__template.txt', $destination);
+
+ if (@filemtime($destination) < @filemtime($source)) {
+ if (!file_exists(dirname($destination))) {
+ @mkdir(dirname($destination), 0755, true);
+ }
+
+ $success = copy($source, $destination);
+
+ touch($destination, filemtime($source));
+ }
+
+ return $success;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_before_parser_cache_use {
+
+ /**
+ * Register callback
+ */
+ public function register($controller) {
+ $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'handle');
+ }
+
+ /**
+ *
+ */
+ public function handle($event, $param) {
+ global $ID;
+
+ $cache = $event->data;
+
+ if (isset($cache->page) && ($cache->page == $ID)) {
+ if (isset($cache->mode) && (($cache->mode == 'xhtml') || ($cache->mode == 'i'))) {
+ $meta = p_get_metadata($ID, 'plugin refnotes');
+
+ if (!empty($meta) && isset($meta['dbref'])) {
+ $this->addDependencies($cache, array_keys($meta['dbref']));
+ }
+ }
+ }
+ }
+
+ /**
+ * Add extra dependencies to the cache
+ */
+ private function addDependencies($cache, $depends) {
+ foreach ($depends as $file) {
+ if (!in_array($file, $cache->depends['files']) && file_exists($file)) {
+ $cache->depends['files'][] = $file;
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_before_parser_wikitext_preprocess {
+
+ /**
+ * Register callback
+ */
+ public function register($controller) {
+ $controller->register_hook('PARSER_WIKITEXT_PREPROCESS', 'BEFORE', $this, 'handle');
+ }
+
+ /**
+ *
+ */
+ public function handle($event, $param) {
+ refnotes_parser_core::getInstance()->enterParsingContext();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_before_tpl_metaheader_output {
+
+ /**
+ * Register callback
+ */
+ public function register($controller) {
+ $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle');
+ }
+
+ /**
+ *
+ */
+ public function handle($event, $param) {
+ if (!empty($_REQUEST['do']) && $_REQUEST['do'] == 'admin' &&
+ !empty($_REQUEST['page']) && $_REQUEST['page'] == 'refnotes') {
+ $this->addAdminIncludes($event);
+ }
+ }
+
+ /**
+ *
+ */
+ private function addAdminIncludes($event) {
+ $this->addTemplateHeaderInclude($event, 'admin.js');
+ $this->addTemplateHeaderInclude($event, 'admin.css');
+ }
+
+ /**
+ *
+ */
+ private function addTemplateHeaderInclude($event, $fileName) {
+ $type = '';
+ $fileName = DOKU_BASE . 'lib/plugins/refnotes/' . $fileName;
+
+ switch (pathinfo($fileName, PATHINFO_EXTENSION)) {
+ case 'js':
+ $type = 'script';
+ $data = array('type' => 'text/javascript', 'charset' => 'utf-8', 'src' => $fileName, '_data' => '', 'defer' => 'defer');
+ break;
+
+ case 'css':
+ $type = 'link';
+ $data = array('type' => 'text/css', 'rel' => 'stylesheet', 'href' => $fileName);
+ break;
+ }
+
+ if ($type != '') {
+ $event->data[$type][] = $data;
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/admin.css b/platform/www/lib/plugins/refnotes/admin.css
new file mode 100644
index 0000000..2c97a50
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/admin.css
@@ -0,0 +1,100 @@
+div#refnotes-config div#config__manager div.cleared {
+ background-color: #eee;
+ color: #bbb;
+ border: 1px solid #ccc;
+ font-size: 90%;
+ margin: 0;
+ padding: 0.5em;
+ text-align: center;
+}
+
+div#refnotes-config div#config__manager div.info {
+ border: 1px solid #aaf;
+}
+
+div#refnotes-config div#config__manager div.success {
+ border: 1px solid #9e9;
+}
+
+div#refnotes-config div#config__manager div.error {
+ border: 1px solid #faa;
+}
+
+div#refnotes-config div#config__manager td.list {
+ position: relative;
+ background-clip: padding-box;
+ width: 15em;
+}
+
+div#refnotes-config div#config__manager select.list {
+ position: absolute;
+ top: 0.5em;
+ bottom: 0.5em;
+ width: 15em;
+}
+
+div#refnotes-config div#config__manager td.lean-label {
+ padding: 0.6em 0 0.6em 1em;
+ vertical-align: top;
+}
+
+div#refnotes-config div#config__manager td.value {
+ padding: 0.5em 0.5em;
+ width: 20em;
+}
+
+div#refnotes-config div#config__manager td.value div.input {
+ width: auto;
+}
+
+div#refnotes-config div#config__manager td.value select {
+ width: 99%;
+}
+
+div#refnotes-config div#config__manager td.value input.edit {
+ width: auto;
+}
+
+div#refnotes-config div#config__manager td.value input.button {
+ background-color: #fff;
+ color: #000;
+}
+
+div#refnotes-config div#config__manager input.button[disabled],
+div#refnotes-config div#config__manager td.value input.button[disabled] {
+ color: #666;
+}
+
+div#refnotes-config div#config__manager td.value textarea {
+ width: 100%;
+ height: auto;
+ resize: vertical;
+ margin: 0;
+}
+
+div#refnotes-config div#config__manager div.list-controls {
+ text-align: left;
+ margin-bottom: 1em;
+}
+
+div#refnotes-config div#config__manager div.list-controls input.edit {
+ width: 14em;
+}
+
+div#refnotes-config div#config__manager td .input {
+ background-color: inherit;
+}
+
+div#refnotes-config div#config__manager td.default input,
+div#refnotes-config div#config__manager td.default textarea,
+div#refnotes-config div#config__manager td.default select {
+ background-color: #ccddff;
+ color: #000;
+}
+
+div#refnotes-config div#config__manager td.inherited input,
+div#refnotes-config div#config__manager td.inherited textarea,
+div#refnotes-config div#config__manager td.inherited select {
+ background-color: #ddeedd;
+ color: #000;
+}
diff --git a/platform/www/lib/plugins/refnotes/admin.js b/platform/www/lib/plugins/refnotes/admin.js
new file mode 100644
index 0000000..d3a46dd
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/admin.js
@@ -0,0 +1,1035 @@
+let refnotes_admin = (function () {
+ let modified = false;
+
+
+ class NameMap extends Map {
+ constructor(sentinel) {
+ super();
+
+ this.sentinel = sentinel;
+ }
+
+ get(key) {
+ return key == '' ? this.sentinel : super.get(key);
+ }
+
+ has(key) {
+ return key == '' ? true : super.has(key);
+ }
+ }
+
+
+ class NamedObjectMap extends Map {
+ set(value) {
+ super.set(value.getName(), value);
+ }
+ }
+
+
+ function List(id) {
+ let list = jQuery(id);
+
+ function appendOption(value) {
+ jQuery('<option>')
+ .html(value)
+ .val(value)
+ .prop('sorting', value.replace(/:/g, '-').replace(/(-\w+)$/, '-$1'))
+ .appendTo(list);
+ }
+
+ function sortOptions() {
+ list.append(list.children().get().sort(function (a, b) {
+ return a.sorting > b.sorting ? 1 : -1;
+ }));
+ }
+
+ this.getSelectedValue = function () {
+ return list.val();
+ }
+
+ this.insertValue = function (value) {
+ appendOption(value);
+ sortOptions();
+
+ return list.children('[value="' + value + '"]').attr('selected', 'selected').val();
+ }
+
+ this.reload = function (values) {
+ list.empty();
+
+ for (let value of values.keys()) {
+ if (value != '') {
+ appendOption(value);
+ }
+ }
+
+ sortOptions();
+
+ return list.children(':first').attr('selected', 'selected').val();
+ }
+
+ this.removeValue = function (value) {
+ let option = list.children('[value="' + value + '"]');
+
+ if (option.length == 1) {
+ list.prop('selectedIndex', option.index() + (option.is(':last-child') ? -1 : 1));
+ option.remove();
+ }
+
+ return list.val();
+ }
+
+ this.renameValue = function (oldValue, newValue) {
+ if (list.children('[value="' + oldValue + '"]').remove().length == 1) {
+ this.insertValue(newValue);
+ }
+
+ return list.val();
+ }
+ }
+
+
+ let locale = (function () {
+ let lang = new Map();
+
+ function initialize() {
+ jQuery.each(jQuery('#refnotes-lang').html().split(/:eos:/), function (key, value) {
+ let match = value.match(/^\s*(\w+) : (.+)/);
+ if (match != null) {
+ lang.set(match[1], match[2]);
+ }
+ });
+ }
+
+ function getString(key) {
+ let string = lang.has(key) ? lang.get(key) : '';
+
+ if ((string.length > 0) && (arguments.length > 1)) {
+ for (let i = 1; i < arguments.length; i++) {
+ string = string.replace(new RegExp('\\{' + i + '\\}'), arguments[i]);
+ }
+ }
+
+ return string;
+ }
+
+ return {
+ initialize,
+ getString
+ }
+ })();
+
+
+ let server = (function () {
+ let timer = null;
+ let transaction = null;
+
+ function sendRequest(request, data, success) {
+ if (transaction == null) {
+ transaction = request;
+
+ jQuery.ajax({
+ cache : false,
+ data : data,
+ global : false,
+ success : success,
+ type : 'POST',
+ timeout : 10000,
+ url : DOKU_BASE + 'lib/exe/ajax.php',
+ beforeSend() {
+ setStatus('info', transaction);
+ },
+ error(xhr, status, message) {
+ setErrorStatus((status == 'parseerror') ? 'invalid_data' : transaction + '_failed', message);
+ },
+ dataFilter(data) {
+ let cookie = '{B27067E9-3DDA-4E31-9768-E66F23D18F4A}';
+ let match = data.match(new RegExp(cookie + '(.+?)' + cookie));
+
+ if ((match == null) || (match.length != 2)) {
+ throw 'Malformed response';
+ }
+
+ return match[1];
+ },
+ complete() {
+ transaction = null;
+ }
+ });
+ }
+ else {
+ setErrorStatus(request + '_failed', 'Server is busy');
+ }
+ }
+
+ function loadSettings() {
+ sendRequest('loading', {
+ call : 'refnotes-admin',
+ action : 'load-settings'
+ }, function (data) {
+ setSuccessStatus('loaded', 3000);
+ reloadSettings(data);
+ });
+ }
+
+ function saveSettings(settings) {
+ sendRequest('saving', {
+ call : 'refnotes-admin',
+ action : 'save-settings',
+ settings : JSON.stringify(settings)
+ }, function (data) {
+ if (data == 'saved') {
+ modified = false;
+
+ setSuccessStatus('saved', 10000);
+ }
+ else {
+ setErrorStatus('saving_failed', 'Server FS access error');
+ }
+ });
+ }
+
+ function setStatus(status, message) {
+ window.clearTimeout(timer);
+
+ if (message.match(/^\w+$/) != null) {
+ message = locale.getString(message);
+ }
+
+ jQuery('#server-status')
+ .removeClass()
+ .addClass(status)
+ .text(message);
+ }
+
+ function setErrorStatus(messageId, details) {
+ setStatus('error', locale.getString(messageId, details));
+ }
+
+ function setSuccessStatus(messageId, timeout) {
+ setStatus('success', messageId);
+
+ timer = window.setTimeout(function () {
+ setStatus('cleared', 'status');
+ }, timeout);
+ }
+
+ return {
+ loadSettings,
+ saveSettings
+ }
+ })();
+
+
+ let general = (function () {
+ let fields = new NamedObjectMap();
+ let defaults = new Map([
+ ['replace-footnotes' , false],
+ ['reference-db-enable' , false],
+ ['reference-db-namespace', ':refnotes:']
+ ]);
+
+ function Field(settingName) {
+ this.element = jQuery('#field-' + settingName);
+
+ this.element.change(this, function (event) {
+ event.data.updateDefault();
+ modified = true;
+ });
+
+ this.getName = function () {
+ return settingName;
+ }
+
+ this.updateDefault = function () {
+ this.element.parents('td').toggleClass('default', this.getValue() == defaults.get(settingName));
+ }
+
+ this.enable = function (enable) {
+ this.element.prop('disabled', !enable);
+ }
+ }
+
+ function CheckField(settingName) {
+ this.baseClass = Field;
+ this.baseClass(settingName);
+
+ this.setValue = function (value) {
+ this.element.attr('checked', value);
+ this.updateDefault();
+ }
+
+ this.getValue = function () {
+ return this.element.is(':checked');
+ }
+
+ this.setValue(defaults.get(settingName));
+ this.enable(false);
+ }
+
+ function TextField(settingName) {
+ this.baseClass = Field;
+ this.baseClass(settingName);
+
+ this.setValue = function (value) {
+ this.element.val(value);
+ this.updateDefault();
+ }
+
+ this.getValue = function () {
+ return this.element.val();
+ }
+
+ this.setValue(defaults.get(settingName));
+ this.enable(false);
+ }
+
+ function initialize() {
+ fields.set(new CheckField('replace-footnotes'));
+ fields.set(new CheckField('reference-db-enable'));
+ fields.set(new TextField('reference-db-namespace'));
+
+ jQuery('#field-reference-db-namespace').css('width', '19em');
+ }
+
+ function reload(settings) {
+ for (let name in settings) {
+ if (fields.has(name)) {
+ fields.get(name).setValue(settings[name]);
+ }
+ }
+
+ for (let field of fields.values()) {
+ field.enable(true);
+ }
+ }
+
+ function getSettings() {
+ let settings = {};
+
+ for (let [name, field] of fields) {
+ settings[name] = field.getValue();
+ }
+
+ return settings;
+ }
+
+ return {
+ initialize,
+ reload,
+ getSettings
+ }
+ })();
+
+
+ let namespaces = (function () {
+ let list = null;
+ let fields = new NamedObjectMap();
+ let namespaces = new NameMap(new DefaultNamespace());
+ let current = namespaces.get('');
+ let defaults = new Map([
+ ['refnote-id' , 'numeric'],
+ ['reference-base' , 'super'],
+ ['reference-font-weight', 'normal'],
+ ['reference-font-style' , 'normal'],
+ ['reference-format' , 'right-parent'],
+ ['reference-group' , 'group-none'],
+ ['reference-render' , 'basic'],
+ ['multi-ref-id' , 'ref-counter'],
+ ['note-preview' , 'popup'],
+ ['notes-separator' , '100%'],
+ ['note-text-align' , 'justify'],
+ ['note-font-size' , 'normal'],
+ ['note-render' , 'basic'],
+ ['note-id-base' , 'super'],
+ ['note-id-font-weight' , 'normal'],
+ ['note-id-font-style' , 'normal'],
+ ['note-id-format' , 'right-parent'],
+ ['back-ref-caret' , 'none'],
+ ['back-ref-base' , 'super'],
+ ['back-ref-font-weight' , 'bold'],
+ ['back-ref-font-style' , 'normal'],
+ ['back-ref-format' , 'note-id'],
+ ['back-ref-separator' , 'comma'],
+ ['scoping' , 'reset']
+ ]);
+
+ function DefaultNamespace() {
+ this.isReadOnly = function () {
+ return true;
+ }
+
+ this.setName = function (newName) {
+ }
+
+ this.getName = function () {
+ return '';
+ }
+
+ this.setStyle = function (name, value) {
+ }
+
+ this.getStyle = function (name) {
+ return defaults.get(name);
+ }
+
+ this.getStyleInheritance = function (name) {
+ return 'default';
+ }
+
+ this.getSettings = function () {
+ return {};
+ }
+ }
+
+ function Namespace(name, data) {
+ let styles = data ? new Map(Object.entries(data)) : new Map();
+
+ function getParent() {
+ let parent = name.replace(/\w*:$/, '');
+
+ while (!namespaces.has(parent)) {
+ parent = parent.replace(/\w*:$/, '');
+ }
+
+ return namespaces.get(parent);
+ }
+
+ this.isReadOnly = function () {
+ return false;
+ }
+
+ this.setName = function (newName) {
+ name = newName;
+ }
+
+ this.getName = function () {
+ return name;
+ }
+
+ this.setStyle = function (name, value) {
+ if (value == 'inherit') {
+ styles.delete(name);
+ }
+ else {
+ styles.set(name, value);
+ }
+ }
+
+ this.getStyle = function (name) {
+ let result;
+
+ if (styles.has(name)) {
+ result = styles.get(name);
+ }
+ else {
+ result = getParent().getStyle(name);
+ }
+
+ return result;
+ }
+
+ this.getStyleInheritance = function (name) {
+ let result = '';
+
+ if (!styles.has(name)) {
+ result = getParent().getStyleInheritance(name) || 'inherited';
+ }
+
+ return result;
+ }
+
+ this.getSettings = function () {
+ let settings = {};
+
+ for (let [name, style] of styles) {
+ settings[name] = style;
+ }
+
+ return settings;
+ }
+ }
+
+ function Field(styleName) {
+ this.element = jQuery('#field-' + styleName);
+
+ this.getName = function () {
+ return styleName;
+ }
+
+ this.updateInheretance = function () {
+ this.element.parents('td')
+ .removeClass('default inherited')
+ .addClass(current.getStyleInheritance(styleName));
+ }
+ }
+
+ function SelectField(styleName) {
+ this.baseClass = Field;
+ this.baseClass(styleName);
+
+ let combo = this.element;
+
+ combo.change(this, function (event) {
+ event.data.onChange();
+ });
+
+ function setSelection(value) {
+ combo.val(value);
+ }
+
+ this.onChange = function () {
+ let value = combo.val();
+
+ current.setStyle(styleName, value);
+
+ this.updateInheretance();
+
+ if ((value == 'inherit') || current.isReadOnly()) {
+ setSelection(current.getStyle(styleName));
+ }
+
+ modified = true;
+ }
+
+ this.update = function () {
+ this.updateInheretance();
+ setSelection(current.getStyle(styleName));
+ combo.prop('disabled', current.isReadOnly());
+ }
+ }
+
+ function TextField(styleName, validate) {
+ this.baseClass = Field;
+ this.baseClass(styleName);
+
+ let edit = this.element;
+ let button = jQuery('#field-' + styleName + '-inherit');
+
+ edit.change(this, function (event) {
+ event.data.setValue(validate(edit.val()));
+ });
+
+ button.click(this, function (event) {
+ event.data.setValue('inherit');
+ });
+
+ this.setValue = function (value) {
+ current.setStyle(styleName, value);
+
+ this.updateInheretance();
+
+ if ((edit.val() != value) || (value == 'inherit') || current.isReadOnly()) {
+ edit.val(current.getStyle(styleName));
+ }
+
+ modified = true;
+ }
+
+ this.update = function () {
+ this.updateInheretance();
+
+ edit.val(current.getStyle(styleName));
+ edit.prop('disabled', current.isReadOnly());
+ button.prop('disabled', current.isReadOnly());
+ }
+ }
+
+ function initialize() {
+ list = new List('#select-namespaces');
+
+ fields.set(new SelectField('refnote-id'));
+ fields.set(new SelectField('reference-base'));
+ fields.set(new SelectField('reference-font-weight'));
+ fields.set(new SelectField('reference-font-style'));
+ fields.set(new SelectField('reference-format'));
+ fields.set(new SelectField('reference-group'));
+ fields.set(new SelectField('reference-render'));
+ fields.set(new SelectField('multi-ref-id'));
+ fields.set(new SelectField('note-preview'));
+ fields.set(new TextField('notes-separator', function (value) {
+ return (value.match(/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/) != null) ? value : 'none';
+ }));
+ fields.set(new SelectField('note-text-align'));
+ fields.set(new SelectField('note-font-size'));
+ fields.set(new SelectField('note-render'));
+ fields.set(new SelectField('note-id-base'));
+ fields.set(new SelectField('note-id-font-weight'));
+ fields.set(new SelectField('note-id-font-style'));
+ fields.set(new SelectField('note-id-format'));
+ fields.set(new SelectField('back-ref-caret'));
+ fields.set(new SelectField('back-ref-base'));
+ fields.set(new SelectField('back-ref-font-weight'));
+ fields.set(new SelectField('back-ref-font-style'));
+ fields.set(new SelectField('back-ref-format'));
+ fields.set(new SelectField('back-ref-separator'));
+ fields.set(new SelectField('scoping'));
+
+ jQuery('#select-namespaces').change(onNamespaceChange);
+ jQuery('#name-namespaces').prop('disabled', true);
+ jQuery('#add-namespaces').click(onAddNamespace).prop('disabled', true);
+ jQuery('#rename-namespaces').click(onRenameNamespace).prop('disabled', true);
+ jQuery('#delete-namespaces').click(onDeleteNamespace).prop('disabled', true);
+
+ updateFields();
+ }
+
+ function onNamespaceChange(event) {
+ setCurrent(list.getSelectedValue());
+ }
+
+ function onAddNamespace(event) {
+ try {
+ let name = validateName(jQuery('#name-namespaces').val(), 'ns', namespaces);
+
+ namespaces.set(name, new Namespace(name));
+
+ setCurrent(list.insertValue(name));
+
+ modified = true;
+ }
+ catch (error) {
+ alert(error);
+ }
+ }
+
+ function onRenameNamespace(event) {
+ try {
+ let newName = validateName(jQuery('#name-namespaces').val(), 'ns', namespaces);
+ let oldName = current.getName();
+
+ current.setName(newName);
+
+ namespaces.delete(oldName);
+ namespaces.set(newName, current);
+
+ setCurrent(list.renameValue(oldName, newName));
+
+ modified = true;
+ }
+ catch (error) {
+ alert(error);
+ }
+ }
+
+ function onDeleteNamespace(event) {
+ if (confirm(locale.getString('delete_ns', current.getName()))) {
+ namespaces.delete(current.getName());
+
+ setCurrent(list.removeValue(current.getName()));
+
+ modified = true;
+ }
+ }
+
+ function reload(settings) {
+ namespaces.clear();
+
+ for (let name in settings) {
+ if (name.match(/^:$|^:.+?:$/) != null) {
+ namespaces.set(name, new Namespace(name, settings[name]));
+ }
+ }
+
+ jQuery('#name-namespaces').prop('disabled', false);
+ jQuery('#add-namespaces').prop('disabled', false);
+
+ setCurrent(list.reload(namespaces));
+ }
+
+ function setCurrent(name) {
+ current = namespaces.get(name);
+
+ updateFields();
+ }
+
+ function updateFields() {
+ jQuery('#name-namespaces').val(current.getName());
+ jQuery('#rename-namespaces').prop('disabled', current.isReadOnly());
+ jQuery('#delete-namespaces').prop('disabled', current.isReadOnly());
+
+ for (let field of fields.values()) {
+ field.update();
+ }
+ }
+
+ function getSettings() {
+ let settings = {};
+
+ for (let [name, namespace] of namespaces) {
+ settings[name] = namespace.getSettings();
+ }
+
+ return settings;
+ }
+
+ return {
+ initialize,
+ reload,
+ getSettings
+ }
+ })();
+
+
+ let notes = (function () {
+ let list = null;
+ let fields = new NamedObjectMap();
+ let notes = new NameMap(new EmptyNote());
+ let current = notes.get('');
+ let defaults = new Map([
+ ['inline' , false],
+ ['use-reference-base' , true],
+ ['use-reference-font-weight', true],
+ ['use-reference-font-style' , true],
+ ['use-reference-format' , true]
+ ]);
+ let inlineAttributes = [
+ 'use-reference-base',
+ 'use-reference-font-weight',
+ 'use-reference-font-style',
+ 'use-reference-format'
+ ];
+
+ function isInlineAttribute(name) {
+ return inlineAttributes.indexOf(name) != -1;
+ }
+
+ function EmptyNote() {
+ this.isReadOnly = function () {
+ return true;
+ }
+
+ this.setName = function (newName) {
+ }
+
+ this.getName = function () {
+ return '';
+ }
+
+ this.setText = function (text) {
+ }
+
+ this.getText = function () {
+ return '';
+ }
+
+ this.setAttribute = function (name, value) {
+ }
+
+ this.getAttribute = function (name) {
+ return defaults.get(name);
+ }
+
+ this.getSettings = function () {
+ return {};
+ }
+ }
+
+ function Note(name, data) {
+ let attributes = data ? new Map(Object.entries(data)) : new Map();
+
+ this.isReadOnly = function () {
+ return false;
+ }
+
+ this.setName = function (newName) {
+ name = newName;
+ }
+
+ this.getName = function () {
+ return name;
+ }
+
+ this.setText = function (text) {
+ attributes.set('text', text);
+ }
+
+ this.getText = function () {
+ return attributes.get('text');
+ }
+
+ this.setAttribute = function (name, value) {
+ attributes.set(name, value);
+ }
+
+ this.getAttribute = function (name) {
+ if (!attributes.has(name) || (isInlineAttribute(name) && !this.getAttribute('inline'))) {
+ return defaults.get(name);
+ }
+ else {
+ return attributes.get(name);
+ }
+ }
+
+ this.getSettings = function () {
+ let settings = {};
+
+ if (!this.getAttribute('inline')) {
+ for (let i in inlineAttributes) {
+ if (attributes.has(inlineAttributes[i])) {
+ attributes.delete(inlineAttributes[i]);
+ }
+ }
+ }
+
+ for (let [name, attribute] of attributes) {
+ settings[name] = attribute;
+ }
+
+ return settings;
+ }
+ }
+
+ function Field(attributeName) {
+ this.element = jQuery('#field-' + attributeName);
+
+ this.element.change(this, function (event) {
+ current.setAttribute(attributeName, event.data.getValue());
+ modified = true;
+ });
+
+ this.getName = function () {
+ return attributeName;
+ }
+
+ this.enable = function (enable) {
+ this.element.prop('disabled', !enable);
+ }
+ }
+
+ function CheckField(attributeName) {
+ this.baseClass = Field;
+ this.baseClass(attributeName);
+
+ this.setValue = function (value) {
+ this.element.attr('checked', value);
+ }
+
+ this.getValue = function () {
+ return this.element.is(':checked');
+ }
+
+ this.update = function () {
+ this.setValue(current.getAttribute(attributeName));
+ this.enable(!current.isReadOnly() && (!isInlineAttribute(attributeName) || current.getAttribute('inline')));
+ }
+ }
+
+ function InlineField() {
+ this.baseClass = CheckField;
+ this.baseClass('inline');
+
+ this.element.change(this, function (event) {
+ for (let i in inlineAttributes) {
+ fields.get(inlineAttributes[i]).update();
+ }
+ });
+ }
+
+ function initialize() {
+ list = new List('#select-notes');
+
+ fields.set(new InlineField());
+ fields.set(new CheckField('use-reference-base'));
+ fields.set(new CheckField('use-reference-font-weight'));
+ fields.set(new CheckField('use-reference-font-style'));
+ fields.set(new CheckField('use-reference-format'));
+
+ jQuery('#select-notes').change(onNoteChange);
+ jQuery('#name-notes').prop('disabled', true);
+ jQuery('#add-notes').click(onAddNote).prop('disabled', true);
+ jQuery('#rename-notes').click(onRenameNote).prop('disabled', true);
+ jQuery('#delete-notes').click(onDeleteNote).prop('disabled', true);
+ jQuery('#field-note-text').change(onTextChange);
+
+ updateFields();
+ }
+
+ function onNoteChange(event) {
+ setCurrent(list.getSelectedValue());
+ }
+
+ function onAddNote(event) {
+ try {
+ let name = validateName(jQuery('#name-notes').val(), 'note', notes);
+
+ notes.set(name, new Note(name));
+
+ setCurrent(list.insertValue(name));
+
+ modified = true;
+ }
+ catch (error) {
+ alert(error);
+ }
+ }
+
+ function onRenameNote(event) {
+ try {
+ let newName = validateName(jQuery('#name-notes').val(), 'note', notes);
+ let oldName = current.getName();
+
+ current.setName(newName);
+
+ notes.delete(oldName);
+ notes.set(newName, current);
+
+ setCurrent(list.renameValue(oldName, newName));
+
+ modified = true;
+ }
+ catch (error) {
+ alert(error);
+ }
+ }
+
+ function onDeleteNote(event) {
+ if (confirm(locale.getString('delete_note', current.getName()))) {
+ notes.delete(current.getName());
+
+ setCurrent(list.removeValue(current.getName()));
+
+ modified = true;
+ }
+ }
+
+ function onTextChange(event) {
+ current.setText(event.target.value);
+
+ modified = true;
+ }
+
+ function reload(settings) {
+ notes.clear();
+
+ for (let name in settings) {
+ if (name.match(/^:.+?\w$/) != null) {
+ notes.set(name, new Note(name, settings[name]));
+ }
+ }
+
+ jQuery('#name-notes').prop('disabled', false);
+ jQuery('#add-notes').prop('disabled', false);
+
+ setCurrent(list.reload(notes));
+ }
+
+ function setCurrent(name) {
+ current = notes.get(name);
+
+ updateFields();
+ }
+
+ function updateFields() {
+ jQuery('#name-notes').val(current.getName());
+ jQuery('#rename-notes').prop('disabled', current.isReadOnly());
+ jQuery('#delete-notes').prop('disabled', current.isReadOnly());
+ jQuery('#field-note-text').val(current.getText()).prop('disabled', current.isReadOnly());
+
+ for (let field of fields.values()) {
+ field.update();
+ }
+ }
+
+ function getSettings() {
+ let settings = {};
+
+ for (let [name, note] of notes) {
+ settings[name] = note.getSettings();
+ }
+
+ return settings;
+ }
+
+ return {
+ initialize,
+ reload,
+ getSettings
+ }
+ })();
+
+
+ function initialize() {
+ locale.initialize();
+ general.initialize();
+ namespaces.initialize();
+ notes.initialize();
+
+ jQuery('#save-config').click(function () {
+ saveSettings();
+ });
+
+ window.onbeforeunload = onBeforeUnload;
+
+ jQuery('#server-status').show();
+
+ server.loadSettings();
+ }
+
+ function reloadSettings(settings) {
+ general.reload(settings.general);
+ namespaces.reload(settings.namespaces);
+ notes.reload(settings.notes);
+ }
+
+ function saveSettings() {
+ let settings = {};
+
+ settings.general = general.getSettings();
+ settings.namespaces = namespaces.getSettings();
+ settings.notes = notes.getSettings();
+
+ server.saveSettings(settings);
+
+ scroll(0, 0);
+ }
+
+ function onBeforeUnload(event) {
+ if (modified) {
+ let message = locale.getString('unsaved');
+
+ (event || window.event).returnValue = message;
+
+ return message;
+ }
+ }
+
+ function validateName(name, type, existing) {
+ let names = name.split(':');
+
+ name = (type == 'ns') ? ':' : '';
+
+ for (let i = 0; i < names.length; i++) {
+ if (names[i] != '') {
+ /* ECMA regexp doesn't support POSIX character classes, so [a-zA-Z] is used instead of [[:alpha:]] */
+ if (names[i].match(/^[a-zA-Z]\w*$/) == null) {
+ name = '';
+ break;
+ }
+
+ name += (type == 'ns') ? names[i] + ':' : ':' + names[i];
+ }
+ }
+
+ if (name == '') {
+ throw locale.getString('invalid_' + type + '_name');
+ }
+
+ if (existing.has(name)) {
+ throw locale.getString(type + '_name_exists', name);
+ }
+
+ return name;
+ }
+
+ return {
+ initialize
+ }
+})();
+
+
+jQuery(function () {
+ if (jQuery('#refnotes-config').length != 0) {
+ refnotes_admin.initialize();
+ }
+});
diff --git a/platform/www/lib/plugins/refnotes/admin.php b/platform/www/lib/plugins/refnotes/admin.php
new file mode 100644
index 0000000..499aa8c
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/admin.php
@@ -0,0 +1,751 @@
+<?php
+
+/**
+ * Plugin RefNotes: Configuration interface
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class admin_plugin_refnotes extends DokuWiki_Admin_Plugin {
+ use refnotes_localization_plugin;
+
+ private $html;
+ private $locale;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ refnotes_localization::initialize($this);
+
+ $this->html = new refnotes_html_sink();
+ $this->locale = refnotes_localization::getInstance();
+ }
+
+ /**
+ * Handle user request
+ */
+ public function handle() {
+ /* All handling is done using AJAX */
+ }
+
+ /**
+ * Output appropriate html
+ */
+ public function html() {
+ print($this->locale_xhtml('intro'));
+
+ $this->html->ptln('<!-- refnotes -->');
+
+ $this->printLanguageStrings();
+
+ $this->html->ptln('<div id="refnotes-config"><div id="config__manager">');
+ $this->html->ptln('<noscript><div class="error">' . $this->locale->getLang('noscript') . '</div></noscript>');
+ $this->html->ptln('<div id="server-status" class="info" style="display: none;">&nbsp;</div>');
+ $this->html->ptln('<form action="" method="post">');
+ $this->html->indent();
+
+ $this->printGeneral();
+ $this->printNamespaces();
+ $this->printNotes();
+
+ $this->html->ptln($this->getButton('save'));
+
+ $this->html->unindent();
+ $this->html->ptln('</form></div></div>');
+ $this->html->ptln('<!-- /refnotes -->');
+ }
+
+ /**
+ * Built-in JS localization stores all language strings in the common script (produced by js.php).
+ * The strings used by administration plugin seem to be unnecessary in that script. Instead we print
+ * them as part of the page and then load them into the LANG array on the client side.
+ */
+ private function printLanguageStrings() {
+ $lang = $this->locale->getByPrefix('js');
+
+ $this->html->ptln('<div id="refnotes-lang" style="display: none;">');
+
+ foreach ($lang as $key => $value) {
+ ptln($key . ' : ' . $value . ':eos:');
+ }
+
+ $this->html->ptln('</div>');
+ }
+
+ /**
+ *
+ */
+ private function printGeneral() {
+ $section = new refnotes_config_general();
+ $section->printHtml($this->html);
+ }
+
+ /**
+ *
+ */
+ private function printNamespaces() {
+ $section = new refnotes_config_namespaces();
+ $section->printHtml($this->html);
+ }
+
+ /**
+ *
+ */
+ private function printNotes() {
+ $section = new refnotes_config_notes();
+ $section->printHtml($this->html);
+ }
+
+ /**
+ *
+ */
+ private function getButton($action) {
+ $html = '<input type="button" class="button"';
+ $id = $action . '-config';
+ $html .= ' id="' . $id . '"';
+ $html .= ' name="' . $id . '"';
+ $html .= ' value="' . $this->locale->getLang('btn_' . $action) . '"';
+ $html .= ' />';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_section {
+
+ protected $html;
+ protected $id;
+ protected $title;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id) {
+ $this->html = NULL;
+ $this->id = $id;
+ $this->title = 'sec_' . $id;
+ }
+
+ /**
+ *
+ */
+ public function printHtml($html) {
+ $this->html = $html;
+ $this->open();
+ $this->printFields();
+ $this->close();
+ }
+
+ /**
+ *
+ */
+ protected function open() {
+ $title = refnotes_localization::getInstance()->getLang($this->title);
+
+ $this->html->ptln('<fieldset id="' . $this->id . '">');
+ $this->html->ptln('<legend>' . $title . '</legend>');
+ $this->html->ptln('<table class="inline" cols="3">');
+ $this->html->indent();
+ }
+
+ /**
+ *
+ */
+ protected function close() {
+ $this->html->unindent();
+ $this->html->ptln('</table>');
+ $this->html->ptln('</fieldset>');
+ }
+
+ /**
+ *
+ */
+ protected function printFields() {
+ $field = $this->getFields();
+ foreach ($field as $f) {
+ $this->printFieldRow($f);
+ }
+ }
+
+ /**
+ *
+ */
+ protected function getFields() {
+ $fieldData = $this->getFieldDefinitions();
+ $field = array();
+
+ foreach ($fieldData as $id => $fd) {
+ $class = 'refnotes_config_' . $fd['class'];
+ $field[] = new $class($id, $fd);
+ }
+
+ return $field;
+ }
+
+ /**
+ *
+ */
+ protected function printFieldRow($field, $startRow = true) {
+ if ($startRow) {
+ $this->html->ptln('<tr>');
+ $this->html->indent();
+ }
+
+ if (get_class($field) != 'refnotes_config_textarea') {
+ $settingName = $field->getSettingName();
+ if ($settingName != '') {
+ $this->html->ptln('<td class="label">');
+ $this->html->ptln($settingName);
+ }
+ else {
+ $this->html->ptln('<td class="lean-label">');
+ }
+
+ $this->html->ptln($field->getLabel());
+ $this->html->ptln('</td><td class="value">');
+ }
+ else {
+ $this->html->ptln('<td class="value" colspan="2">');
+ }
+
+ $this->html->ptln($field->getControl());
+ $this->html->ptln('</td>');
+
+ $this->html->unindent();
+ $this->html->ptln('</tr>');
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_list_section extends refnotes_config_section {
+
+ private $listRows;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $listRows) {
+ parent::__construct($id);
+
+ $this->listRows = $listRows;
+ }
+
+ /**
+ *
+ */
+ protected function close() {
+ $this->html->unindent();
+ $this->html->ptln('</table>');
+ $this->printListControls();
+ $this->html->ptln('</fieldset>');
+ }
+
+ /**
+ *
+ */
+ private function printListControls() {
+ $this->html->ptln('<div class="list-controls">');
+ $this->html->indent();
+
+ $this->html->ptln($this->getEdit());
+ $this->html->ptln($this->getButton('add'));
+ $this->html->ptln($this->getButton('rename'));
+ $this->html->ptln($this->getButton('delete'));
+
+ $this->html->unindent();
+ $this->html->ptln('</div>');
+ }
+
+ /**
+ *
+ */
+ private function getEdit() {
+ $html = '<input type="text" class="edit"';
+ $id = 'name-' . $this->id;
+ $html .= ' id="' . $id . '"';
+ $html .= ' name="' . $id . '"';
+ $html .= ' value=""';
+ $html .= ' />';
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ private function getButton($action) {
+ $label = refnotes_localization::getInstance()->getLang('btn_' . $action);
+
+ $id = $action . '-' . $this->id;
+ $html = '<input type="button" class="button"';
+ $html .= ' id="' . $id . '"';
+ $html .= ' name="' . $id . '"';
+ $html .= ' value="' . $label . '"';
+ $html .= ' />';
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function printFields() {
+ $field = $this->getFields();
+ $fields = count($field);
+
+ $this->html->ptln('<tr>');
+ $this->html->indent();
+ $this->html->ptln('<td class="list" rowspan="' . $fields . '">');
+ $this->html->ptln('<select class="list" id="select-' . $this->id . '" size="' . $this->listRows . '"></select>');
+ $this->html->ptln('</td>');
+
+ $this->printFieldRow($field[0], false);
+
+ for ($f = 1; $f < $fields; $f++) {
+ $this->printFieldRow($field[$f]);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_general extends refnotes_config_section {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct('general');
+ }
+
+ /**
+ *
+ */
+ protected function getFieldDefinitions() {
+ static $field = array(
+ 'replace-footnotes' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'reference-db-enable' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'reference-db-namespace' => array(
+ 'class' => 'edit',
+ 'lean' => true
+ )
+ );
+
+ return $field;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_namespaces extends refnotes_config_list_section {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct('namespaces', 48);
+ }
+
+ /**
+ *
+ */
+ protected function getFieldDefinitions() {
+ static $field = array(
+ 'refnote-id' => array(
+ 'class' => 'select',
+ 'option' => array('numeric', 'latin-lower', 'latin-upper', 'roman-lower', 'roman-upper', 'stars', 'note-name', 'inherit')
+ ),
+ 'reference-base' => array(
+ 'class' => 'select',
+ 'option' => array('super', 'normal-text', 'inherit')
+ ),
+ 'reference-font-weight' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'bold', 'inherit')
+ ),
+ 'reference-font-style' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'italic', 'inherit')
+ ),
+ 'reference-format' => array(
+ 'class' => 'select',
+ 'option' => array('right-parent', 'parents', 'right-bracket', 'brackets', 'none', 'inherit')
+ ),
+ 'reference-group' => array(
+ 'class' => 'select',
+ 'option' => array('group-none', 'group-comma', 'group-semicolon', 'inherit')
+ ),
+ 'reference-render' => array(
+ 'class' => 'select',
+ 'option' => array('basic', 'harvard', 'inherit')
+ ),
+ 'multi-ref-id' => array(
+ 'class' => 'select',
+ 'option' => array('ref-counter', 'note-counter', 'inherit')
+ ),
+ 'note-preview' => array(
+ 'class' => 'select',
+ 'option' => array('popup', 'tooltip', 'none', 'inherit')
+ ),
+ 'notes-separator' => array(
+ 'class' => 'edit_inherit'
+ ),
+ 'note-text-align' => array(
+ 'class' => 'select',
+ 'option' => array('justify', 'left', 'inherit')
+ ),
+ 'note-font-size' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'small', 'inherit')
+ ),
+ 'note-render' => array(
+ 'class' => 'select',
+ 'option' => array('basic', 'harvard', 'inherit')
+ ),
+ 'note-id-base' => array(
+ 'class' => 'select',
+ 'option' => array('super', 'normal-text', 'inherit')
+ ),
+ 'note-id-font-weight' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'bold', 'inherit')
+ ),
+ 'note-id-font-style' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'italic', 'inherit')
+ ),
+ 'note-id-format' => array(
+ 'class' => 'select',
+ 'option' => array('right-parent', 'parents', 'right-bracket', 'brackets', 'dot', 'none', 'inherit')
+ ),
+ 'back-ref-caret' => array(
+ 'class' => 'select',
+ 'option' => array('prefix', 'merge', 'none', 'inherit')
+ ),
+ 'back-ref-base' => array(
+ 'class' => 'select',
+ 'option' => array('super', 'normal-text', 'inherit')
+ ),
+ 'back-ref-font-weight' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'bold', 'inherit')
+ ),
+ 'back-ref-font-style' => array(
+ 'class' => 'select',
+ 'option' => array('normal', 'italic', 'inherit')
+ ),
+ 'back-ref-format' => array(
+ 'class' => 'select',
+ 'option' => array('note-id', 'latin', 'numeric', 'caret', 'arrow', 'none', 'inherit')
+ ),
+ 'back-ref-separator' => array(
+ 'class' => 'select',
+ 'option' => array('comma', 'none', 'inherit')
+ ),
+ 'scoping' => array(
+ 'class' => 'select',
+ 'option' => array('reset', 'single')
+ )
+ );
+
+ return $field;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_notes extends refnotes_config_list_section {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct('notes', 14);
+ }
+
+ /**
+ *
+ */
+ protected function getFieldDefinitions() {
+ static $field = array(
+ 'note-text' => array(
+ 'class' => 'textarea',
+ 'rows' => '4',
+ 'lean' => true
+ ),
+ 'inline' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'use-reference-base' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'use-reference-font-weight' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'use-reference-font-style' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ ),
+ 'use-reference-format' => array(
+ 'class' => 'checkbox',
+ 'lean' => true
+ )
+ );
+
+ return $field;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_field {
+
+ protected $id;
+ protected $settingName;
+ protected $label;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ $this->id = 'field-' . $id;
+ $this->label = 'lbl_' . $id;
+
+ if (array_key_exists('lean', $data) && $data['lean']) {
+ $this->settingName = '';
+ }
+ else {
+ $this->settingName = $id;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getSettingName() {
+ $html = '';
+
+ if ($this->settingName != '') {
+ $html = '<span class="outkey">' . $this->settingName . '</span>';
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ public function getLabel() {
+ $label = refnotes_localization::getInstance()->getLang($this->label);
+
+ return '<label for="' . $this->id . '">' . $label . '</label>';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_checkbox extends refnotes_config_field {
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ parent::__construct($id, $data);
+ }
+
+ /**
+ *
+ */
+ public function getControl() {
+ $html = '<div class="input">';
+ $html .= '<input type="checkbox" class="checkbox"';
+ $html .= ' id="' . $this->id . '"';
+ $html .= ' name="' . $this->id . '" value="1"';
+ $html .= '/></div>';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_select extends refnotes_config_field {
+
+ private $option;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ parent::__construct($id, $data);
+
+ $this->option = $data['option'];
+ }
+
+ /**
+ *
+ */
+ public function getControl() {
+ $locale = refnotes_localization::getInstance();
+
+ $html = '<div class="input">';
+
+ $html .= '<select class="edit"';
+ $html .= ' id="' . $this->id . '"';
+ $html .= ' name="' . $this->id . '">' . DOKU_LF;
+
+ foreach ($this->option as $option) {
+ $html .= '<option value="' . $option . '">' . $locale->getLang('opt_' . $option) . '</option>' . DOKU_LF;
+ }
+
+ $html .= '</select>';
+ $html .= '</div>';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_edit extends refnotes_config_field {
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ parent::__construct($id, $data);
+ }
+
+ /**
+ *
+ */
+ public function getControl() {
+ $html = '<div class="input">';
+
+ $html .= '<input type="text" class="edit"';
+ $html .= ' id="' . $this->id . '"';
+ $html .= ' name="' . $this->id . '" />' . DOKU_LF;
+
+ $html .= '</div>';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_edit_inherit extends refnotes_config_field {
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ parent::__construct($id, $data);
+ }
+
+ /**
+ *
+ */
+ public function getControl() {
+ $buttonLabel = refnotes_localization::getInstance()->getLang('opt_inherit');
+
+ $html = '<div class="input">';
+
+ $html .= '<input type="text" class="edit"';
+ $html .= ' id="' . $this->id . '"';
+ $html .= ' name="' . $this->id . '" />' . DOKU_LF;
+
+ $html .= '<input type="button" class="button"';
+ $html .= ' id="' . $this->id . '-inherit"';
+ $html .= ' name="' . $this->id . '-inherit"';
+ $html .= ' value="' . $buttonLabel . '"';
+ $html .= ' />';
+
+ $html .= '</div>';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_config_textarea extends refnotes_config_field {
+
+ private $rows;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id, $data) {
+ parent::__construct($id, $data);
+
+ $this->rows = $data['rows'];
+ }
+
+ /**
+ *
+ */
+ public function getControl() {
+ $html = '<div class="input">';
+ $html .= '<textarea class="edit"';
+ $html .= ' id="' . $this->id . '"';
+ $html .= ' name="' . $this->id . '"';
+ $html .= ' cols="40" rows="' . $this->rows . '">';
+ $html .= '</textarea></div>';
+
+ return $html;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_html_sink {
+
+ private $indentIncrement;
+ private $indent;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->indentIncrement = 2;
+ $this->indent = 0;
+ }
+
+ /**
+ *
+ */
+ public function indent() {
+ $this->indent += $this->indentIncrement;
+ }
+
+ /**
+ *
+ */
+ public function unindent() {
+ if ($this->indent >= $this->indentIncrement) {
+ $this->indent -= $this->indentIncrement;
+ }
+ }
+
+ /**
+ *
+ */
+ public function ptln($string, $indentDelta = 0) {
+ if ($indentDelta < 0) {
+ $this->indent += $this->indentIncrement * $indentDelta;
+ }
+
+ $text = explode(DOKU_LF, $string);
+ foreach ($text as $string) {
+ ptln($string, $this->indent);
+ }
+
+ if ($indentDelta > 0) {
+ $this->indent += $this->indentIncrement * $indentDelta;
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/admin.svg b/platform/www/lib/plugins/refnotes/admin.svg
new file mode 100644
index 0000000..02553fa
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/admin.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 24 24" width="24" height="24"><path d="M7.51 21.488H2.526V2.465H7.51v1.432H4.204v16.157H7.51zM12.221 21.589q-4.66-4.371-4.66-9.663 0-1.238.242-2.467.253-1.238.799-2.476.556-1.239 1.455-2.477.91-1.239 2.204-2.457l1.021 1.055q-3.922 3.92-3.922 8.69 0 2.376.99 4.566.991 2.19 2.933 4.135zM14.685 7.108l1.092-1.135 6.795 5.742-6.795 5.742-1.092-1.126 5.51-4.596z"/></svg>
diff --git a/platform/www/lib/plugins/refnotes/bibtex.php b/platform/www/lib/plugins/refnotes/bibtex.php
new file mode 100644
index 0000000..04b335f
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/bibtex.php
@@ -0,0 +1,669 @@
+<?php
+
+/**
+ * Plugin RefNotes: BibTeX parser
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_parser extends \dokuwiki\Parsing\Parser {
+
+ private static $instance = NULL;
+
+ /**
+ *
+ */
+ public static function getInstance() {
+ if (self::$instance == NULL) {
+ self::$instance = new refnotes_bibtex_parser();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->handler = new refnotes_bibtex_handler();
+ $this->lexer = new refnotes_bibtex_lexer($this->handler, 'base', true);
+
+ $this->addBibtexMode(new refnotes_bibtex_outside_mode());
+ $this->addBibtexMode(new refnotes_bibtex_entry_mode('parented'));
+ $this->addBibtexMode(new refnotes_bibtex_entry_mode('braced'));
+ $this->addBibtexMode(new refnotes_bibtex_field_mode());
+ $this->addBibtexMode(new refnotes_bibtex_integer_value_mode());
+ $this->addBibtexMode(new refnotes_bibtex_string_value_mode('quoted'));
+ $this->addBibtexMode(new refnotes_bibtex_string_value_mode('braced'));
+ $this->addBibtexMode(new refnotes_bibtex_nested_braces_mode('quoted'));
+ $this->addBibtexMode(new refnotes_bibtex_nested_braces_mode('braced'));
+ $this->addBibtexMode(new refnotes_bibtex_concatenation_mode());
+ }
+
+ /**
+ *
+ */
+ private function addBibtexMode($mode) {
+ $this->addMode($mode->getName(), $mode);
+ }
+
+ /**
+ *
+ */
+ public function connectModes() {
+ if (!$this->connected) {
+ $this->modes['outside']->connectTo('base');
+ $this->modes['entry_parented']->connectTo('base');
+ $this->modes['entry_braced']->connectTo('base');
+
+ parent::connectModes();
+ }
+ }
+
+ /**
+ *
+ */
+ public function parse($text) {
+ $this->connectModes();
+
+ $this->handler->reset();
+ $this->lexer->parse(str_replace("\r\n", "\n", $text));
+
+ return $this->handler->finalize();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_lexer extends \dokuwiki\Parsing\Lexer\Lexer {
+
+ /**
+ *
+ */
+ public function parse($text) {
+ $lastMode = '';
+
+ while (is_array($parsed = $this->reduce($text))) {
+ list($unmatched, $matched, $mode) = $parsed;
+
+ if (!$this->dispatchTokens($unmatched, $matched, $mode, 0, 0)) {
+ return false;
+ }
+
+ if (empty($unmatched) && empty($matched) && ($lastMode == $this->modeStack->getCurrent())) {
+ return false;
+ }
+
+ $lastMode = $this->modeStack->getCurrent();
+ }
+
+ if (!$parsed) {
+ return false;
+ }
+
+ return $this->invokeHandler($text, DOKU_LEXER_UNMATCHED, 0);
+ }
+
+ /**
+ *
+ */
+ protected function invokeHandler($text, $state, $pos) {
+ if ($text == "" && $state == DOKU_LEXER_UNMATCHED) {
+ return true;
+ }
+
+ $mode = $this->modeStack->getCurrent();
+ $handler = isset($this->mode_handlers[$mode]) ? $this->mode_handlers[$mode] : $mode;
+
+ return $this->handler->$handler($text, $state, $pos);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_mode extends \dokuwiki\Parsing\ParserMode\AbstractMode {
+
+ protected $name;
+ protected $handler;
+ protected $specialPattern;
+ protected $entryPattern;
+ protected $exitPattern;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->name = preg_replace('/refnotes_bibtex_(\w+)_mode/', '$1', get_class($this));
+ $this->handler = '';
+
+ $this->specialPattern = array();
+ $this->entryPattern = array();
+ $this->exitPattern = array();
+ }
+
+ /**
+ *
+ */
+ public function getSort() {
+ return 0;
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function connectTo($mode) {
+ foreach ($this->specialPattern as $pattern) {
+ $this->Lexer->addSpecialPattern($pattern, $mode, $this->name);
+ }
+
+ foreach ($this->entryPattern as $pattern) {
+ $this->Lexer->addEntryPattern($pattern, $mode, $this->name);
+ }
+
+ if ($this->handler != '') {
+ $this->Lexer->mapHandler($this->name, $this->handler);
+ }
+ }
+
+ /**
+ *
+ */
+ public function postConnect() {
+ foreach ($this->exitPattern as $pattern) {
+ $this->Lexer->addExitPattern($pattern, $this->name);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_outside_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->specialPattern[] = '[^@]+(?=@)';
+ }
+
+ /**
+ *
+ */
+ public function connectTo($mode) {
+ parent::connectTo($mode);
+
+ $this->Lexer->mapHandler('base', $this->name);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_entry_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct($type) {
+ parent::__construct();
+
+ $this->handler = $this->name;
+ $this->name .= '_' . $type;
+
+ list($open, $close) = ($type == 'parented') ? array('\(', '\)') : array('{', '}');
+
+ $this->entryPattern[] = '^@\w+\s*' . $open . '(?=.*' . $close . ')';
+ $this->exitPattern[] = '\s*(?:' . $close . '|(?=@))';
+
+ $this->allowedModes = array('field');
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_field_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->entryPattern[] = '^\s*\w[\w-]+\s*=\s*';
+ $this->exitPattern[] = '\s*(?:,|(?=[\)}@]))';
+
+ $this->allowedModes = array('integer_value', 'string_value_quoted', 'string_value_braced', 'concatenation');
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_integer_value_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->specialPattern[] = '^\d+';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_string_value_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct($type) {
+ parent::__construct();
+
+ $this->handler = $this->name;
+ $this->name .= '_' . $type;
+
+ list($open, $close, $exit) = ($type == 'quoted') ? array('"', '"', '"') : array('{', '}', '(?:}|(?=@))');
+
+ $this->entryPattern[] = '^' . $open . '(?=.*' . $close . ')';
+ $this->exitPattern[] = $exit;
+
+ $this->allowedModes = array('nested_braces_' . $type);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_nested_braces_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct($type) {
+ parent::__construct();
+
+ $this->handler = $this->name;
+ $this->name .= '_' . $type;
+
+ $this->entryPattern[] = '{(?=.*})';
+ $this->exitPattern[] = ($type == 'quoted') ? '}' : '(?:}|(?=@))';
+
+ $this->allowedModes = array($this->name);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_concatenation_mode extends refnotes_bibtex_mode {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->specialPattern[] = '\s*#\s*';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_handler {
+
+ private $entries;
+ private $entry;
+ private $field;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->reset();
+ }
+
+ /**
+ *
+ */
+ public function reset() {
+ $this->entries = new refnotes_bibtex_entry_stash();
+ $this->entry = NULL;
+ $this->field = NULL;
+ }
+
+ /**
+ *
+ */
+ public function finalize() {
+ $entries = $this->entries->getEntries();
+
+ foreach ($entries as &$entry) {
+ if (array_key_exists('author', $entry)) {
+ $authors = explode(' and ', $entry['author']);
+
+ foreach ($authors as &$author) {
+ $author = implode(' ', array_reverse(explode(', ', $author)));
+ }
+
+ $entry['author'] = implode(', ', $authors);
+ }
+ }
+
+ return $entries;
+ }
+
+ /**
+ *
+ */
+ public function outside($match, $state) {
+ /* Ignore everything outside the entries */
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function entry($match, $state) {
+ switch ($state) {
+ case DOKU_LEXER_ENTER:
+ $this->entry = new refnotes_bibtex_entry(preg_replace('/@(\w+)\W+/', '$1', $match));
+ break;
+
+ case DOKU_LEXER_UNMATCHED:
+ $this->entry->handleUnmatched($match);
+ break;
+
+ case DOKU_LEXER_EXIT:
+ $this->entries->add($this->entry);
+ $this->entry = NULL;
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function field($match, $state) {
+ switch ($state) {
+ case DOKU_LEXER_ENTER:
+ $this->field = new refnotes_bibtex_field(preg_replace('/\W*(\w[\w-]+)\W*/', '$1', $match));
+ break;
+
+ case DOKU_LEXER_UNMATCHED:
+ $this->field->addToken('unmatched', $match);
+ break;
+
+ case DOKU_LEXER_EXIT:
+ $this->entry->addField($this->field);
+ $this->field = NULL;
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function integer_value($match, $state) {
+ $this->field->addToken('integer', $match);
+
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function string_value($match, $state) {
+ if ($state == DOKU_LEXER_UNMATCHED) {
+ $this->field->addToken('string', $match);
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function nested_braces($match, $state) {
+ if ($state == DOKU_LEXER_UNMATCHED) {
+ $this->field->addToken('braces', $match);
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ */
+ public function concatenation($match, $state) {
+ /* Nothing special to do, concatenation will happen anyway */
+ return true;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_entry_stash {
+
+ private $entry;
+ private $strings;
+ private $namespace;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->entry = array();
+ $this->strings = new refnotes_bibtex_strings();
+ $this->namespace = ':';
+ }
+
+ /**
+ *
+ */
+ public function getEntries() {
+ return $this->entry;
+ }
+
+ /**
+ *
+ */
+ public function add($entry) {
+ static $entryType = array(
+ 'article', 'book', 'booklet', 'conference', 'inbook', 'incollection', 'inproceedings', 'manual',
+ 'mastersthesis', 'misc', 'phdthesis', 'proceedings', 'techreport', 'unpublished');
+
+ $type = $entry->getType();
+ $name = $entry->getName();
+
+ if (in_array($type, $entryType)) {
+ if ($this->isValidRefnotesName($name)) {
+ if ($name[0] != ':') {
+ $name = $this->namespace . $name;
+ }
+
+ $this->entry[] = array_merge(array('note-name' => $name), $entry->getData($this->strings));
+ }
+ }
+ elseif ($type == 'string') {
+ $data = $entry->getData($this->strings);
+ $name = reset(array_keys($data));
+
+ if ($this->isValidStringName($name)) {
+ $this->strings->add($name, $data[$name]);
+ }
+ }
+ elseif (($type == 'comment') && (strtolower($name) == 'refnotes')) {
+ $data = $entry->getData($this->strings);
+
+ if (isset($data['namespace']) && $this->isValidRefnotesName($data['namespace'])) {
+ $this->namespace = refnotes_namespace::canonizeName($data['namespace']);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function isValidRefnotesName($name) {
+ return preg_match('/^' . refnotes_note::getNamePattern('full-extended') . '$/', $name) == 1;
+ }
+
+ /**
+ *
+ */
+ private function isValidStringName($name) {
+ return preg_match('/^[[:alpha:]]\w*$/', $name) == 1;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_entry {
+
+ private $type;
+ private $name;
+ private $field;
+
+ /**
+ * Constructor
+ */
+ public function __construct($type) {
+ $this->type = strtolower($type);
+ $this->name = '';
+ $this->field = array();
+ }
+
+ /**
+ *
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function getData($strings) {
+ $data = array();
+
+ foreach ($this->field as $field) {
+ $data[$field->getName()] = $field->getValue($strings);
+ }
+
+ return $data;
+ }
+
+ /**
+ *
+ */
+ public function handleUnmatched($token) {
+ if (($this->name == '') && (preg_match('/\s*([^\s,]+)\s*,/', $token, $match) == 1)) {
+ $this->name = $match[1];
+ }
+ }
+
+ /**
+ *
+ */
+ public function addField($field) {
+ $this->field[] = $field;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_field {
+
+ private $name;
+ private $token;
+
+ /**
+ * Constructor
+ */
+ public function __construct($name) {
+ $this->name = strtolower($name);
+ $this->token = array();
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function getValue($strings) {
+ $value = '';
+
+ foreach ($this->token as $token) {
+ $text = $token->text;
+
+ if ($token->type == 'unmatched') {
+ $text = $strings->lookup(strtolower(trim($text)));
+ }
+
+ $value .= $text;
+ }
+
+ return preg_replace('/\s+/', ' ', trim($value));
+ }
+
+ /**
+ *
+ */
+ public function addToken($type, $text) {
+ $this->token[] = new refnotes_bibtex_field_token($type, $text);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_field_token {
+
+ public $type;
+ public $text;
+
+ /**
+ * Constructor
+ */
+ public function __construct($type, $text) {
+ $this->type = $type;
+ $this->text = $text;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_bibtex_strings {
+
+ private $string;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->string = array();
+ }
+
+ /**
+ *
+ */
+ public function add($name, $value) {
+ $this->string[$name] = $value;
+ }
+
+ /**
+ *
+ */
+ public function lookup($name) {
+ return array_key_exists($name, $this->string) ? $this->string[$name] : '';
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/conf/namespaces.dat b/platform/www/lib/plugins/refnotes/conf/namespaces.dat
new file mode 100644
index 0000000..3377084
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/conf/namespaces.dat
@@ -0,0 +1 @@
+a:11:{s:1:":";a:0:{}s:8:":biblio:";a:11:{s:10:"refnote-id";s:4:"name";s:14:"reference-base";s:4:"text";s:16:"reference-format";s:2:"[]";s:12:"multi-ref-id";s:4:"note";s:12:"note-preview";s:7:"tooltip";s:12:"note-id-base";s:4:"text";s:19:"note-id-font-weight";s:6:"normal";s:18:"note-id-font-style";s:6:"normal";s:14:"note-id-format";s:4:"none";s:14:"back-ref-caret";s:6:"prefix";s:15:"back-ref-format";s:1:"a";}s:6:":cite:";a:5:{s:16:"reference-format";s:2:"[]";s:12:"multi-ref-id";s:4:"note";s:12:"note-id-base";s:4:"text";s:14:"note-id-format";s:1:".";s:15:"back-ref-format";s:1:"a";}s:4:":dw:";a:24:{s:10:"refnote-id";s:1:"1";s:14:"reference-base";s:3:"sup";s:21:"reference-font-weight";s:6:"normal";s:20:"reference-font-style";s:6:"normal";s:16:"reference-format";s:1:")";s:15:"reference-group";s:4:"none";s:16:"reference-render";s:5:"basic";s:12:"multi-ref-id";s:3:"ref";s:12:"note-preview";s:5:"popup";s:15:"notes-separator";s:4:"100%";s:15:"note-text-align";s:7:"justify";s:14:"note-font-size";s:6:"normal";s:11:"note-render";s:5:"basic";s:12:"note-id-base";s:3:"sup";s:19:"note-id-font-weight";s:6:"normal";s:18:"note-id-font-style";s:6:"normal";s:14:"note-id-format";s:1:")";s:14:"back-ref-caret";s:4:"none";s:13:"back-ref-base";s:3:"sup";s:20:"back-ref-font-weight";s:4:"bold";s:19:"back-ref-font-style";s:6:"normal";s:15:"back-ref-format";s:4:"note";s:18:"back-ref-separator";s:1:",";s:7:"scoping";s:5:"reset";}s:4:":fn:";a:0:{}s:9:":harvard:";a:11:{s:14:"reference-base";s:4:"text";s:16:"reference-format";s:2:"()";s:16:"reference-render";s:7:"harvard";s:12:"multi-ref-id";s:4:"note";s:15:"notes-separator";s:4:"none";s:11:"note-render";s:7:"harvard";s:12:"note-id-base";s:4:"text";s:14:"note-id-format";s:1:".";s:14:"back-ref-caret";s:5:"merge";s:15:"back-ref-format";s:1:"a";s:18:"back-ref-separator";s:4:"none";}s:4:":mw:";a:24:{s:10:"refnote-id";s:1:"1";s:14:"reference-base";s:3:"sup";s:21:"reference-font-weight";s:6:"normal";s:20:"reference-font-style";s:6:"normal";s:16:"reference-format";s:2:"[]";s:15:"reference-group";s:4:"none";s:16:"reference-render";s:5:"basic";s:12:"multi-ref-id";s:4:"note";s:12:"note-preview";s:4:"none";s:15:"notes-separator";s:4:"none";s:15:"note-text-align";s:4:"left";s:14:"note-font-size";s:6:"normal";s:11:"note-render";s:5:"basic";s:12:"note-id-base";s:4:"text";s:19:"note-id-font-weight";s:6:"normal";s:18:"note-id-font-style";s:6:"normal";s:14:"note-id-format";s:1:".";s:14:"back-ref-caret";s:5:"merge";s:13:"back-ref-base";s:3:"sup";s:20:"back-ref-font-weight";s:4:"bold";s:19:"back-ref-font-style";s:6:"italic";s:15:"back-ref-format";s:1:"a";s:18:"back-ref-separator";s:4:"none";s:7:"scoping";s:5:"reset";}s:7:":stars:";a:5:{s:10:"refnote-id";s:1:"*";s:16:"reference-format";s:4:"none";s:12:"multi-ref-id";s:4:"note";s:12:"note-preview";s:7:"tooltip";s:15:"back-ref-format";s:1:"a";}s:7:":table:";a:4:{s:12:"multi-ref-id";s:4:"note";s:12:"note-preview";s:7:"tooltip";s:15:"notes-separator";s:4:"none";s:15:"back-ref-format";s:4:"none";}s:13:":table:alpha:";a:1:{s:10:"refnote-id";s:1:"a";}s:13:":table:stars:";a:2:{s:10:"refnote-id";s:1:"*";s:16:"reference-format";s:4:"none";}} \ No newline at end of file
diff --git a/platform/www/lib/plugins/refnotes/conf/notes.dat b/platform/www/lib/plugins/refnotes/conf/notes.dat
new file mode 100644
index 0000000..c24e182
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/conf/notes.dat
@@ -0,0 +1 @@
+a:4:{s:6:":fixme";a:2:{s:4:"text";s:29:"This part has to be reworked.";s:6:"inline";b:0;}s:5:":todo";a:6:{s:4:"text";s:51:"%%[%%//[[:missing_citation|citation needed]]//%%]%%";s:6:"inline";b:1;s:18:"use-reference-base";b:1;s:25:"use-reference-font-weight";b:1;s:24:"use-reference-font-style";b:0;s:20:"use-reference-format";b:0;}s:10:":cite:todo";a:6:{s:4:"text";s:37:"[[:missing_citation|citation needed]]";s:6:"inline";b:1;s:18:"use-reference-base";b:1;s:25:"use-reference-font-weight";b:1;s:24:"use-reference-font-style";b:1;s:20:"use-reference-format";b:1;}s:9:":ref:todo";a:6:{s:4:"text";s:53:"%%[%%//[[:missing_reference|reference needed]]//%%]%%";s:6:"inline";b:1;s:18:"use-reference-base";b:1;s:25:"use-reference-font-weight";b:0;s:24:"use-reference-font-style";b:0;s:20:"use-reference-format";b:0;}} \ No newline at end of file
diff --git a/platform/www/lib/plugins/refnotes/config.php b/platform/www/lib/plugins/refnotes/config.php
new file mode 100644
index 0000000..80b0925
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/config.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Plugin RefNotes: Configuration
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+class refnotes_configuration {
+
+ private static $section = array();
+ private static $setting = array(
+ 'replace-footnotes' => array('general', false),
+ 'reference-db-enable' => array('general', false),
+ 'reference-db-namespace' => array('general', ':refnotes:')
+ );
+
+ /**
+ *
+ */
+ public static function getSetting($name) {
+ $result = null;
+
+ if (array_key_exists($name, self::$setting)) {
+ $sectionName = self::$setting[$name][0];
+ $result = self::$setting[$name][1];
+
+ if (!array_key_exists($sectionName, self::$section)) {
+ self::$section[$sectionName] = self::load($sectionName);
+ }
+
+ if (array_key_exists($name, self::$section[$sectionName])) {
+ $result = self::$section[$sectionName][$name];
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public static function load($sectionName) {
+ $fileName = DOKU_CONF . 'refnotes.' . $sectionName . '.local.dat';
+
+ if (!file_exists($fileName)) {
+ // TODO: This backward compatibility fix should be eventually removed
+ $pluginRoot = DOKU_PLUGIN . 'refnotes/';
+ $fileName = $pluginRoot . $sectionName . '.local.dat';
+ if (!file_exists($fileName)) {
+ $fileName = $pluginRoot . 'conf/' . $sectionName . '.dat';
+ if (!file_exists($fileName)) {
+ $fileName = '';
+ }
+ }
+ }
+
+ if ($fileName != '') {
+ $result = unserialize(io_readFile($fileName, false));
+ }
+ else {
+ $result = array();
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public static function save($sectionName, $config) {
+ $fileName = DOKU_CONF . 'refnotes.' . $sectionName . '.local.dat';
+
+ return io_saveFile($fileName, serialize($config));
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/core.php b/platform/www/lib/plugins/refnotes/core.php
new file mode 100644
index 0000000..a3ce28d
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/core.php
@@ -0,0 +1,483 @@
+<?php
+
+/**
+ * Plugin RefNotes: Core functionality
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+require_once(DOKU_PLUGIN . 'refnotes/locale.php');
+require_once(DOKU_PLUGIN . 'refnotes/config.php');
+require_once(DOKU_PLUGIN . 'refnotes/refnote.php');
+require_once(DOKU_PLUGIN . 'refnotes/reference.php');
+require_once(DOKU_PLUGIN . 'refnotes/note.php');
+require_once(DOKU_PLUGIN . 'refnotes/namespace.php');
+require_once(DOKU_PLUGIN . 'refnotes/scope.php');
+require_once(DOKU_PLUGIN . 'refnotes/rendering.php');
+require_once(DOKU_PLUGIN . 'refnotes/database.php');
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_parser_core {
+
+ private static $instance = NULL;
+
+ private $context;
+ private $lexer;
+ private $handler;
+
+ /**
+ *
+ */
+ public static function getInstance() {
+ if (self::$instance == NULL) {
+ self::$instance = new refnotes_parser_core();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ /* Default context. Should never be used, but just in case... */
+ $this->context = array(new refnotes_parsing_context());
+ $this->lexer = NULL;
+ $this->handler = NULL;
+ }
+
+ /**
+ *
+ */
+ public function registerLexer($lexer) {
+ $this->lexer = $lexer;
+ }
+
+ /**
+ *
+ */
+ public function enterParsingContext() {
+ $this->context[] = new refnotes_parsing_context();
+ }
+
+ /**
+ *
+ */
+ public function exitParsingContext($handler) {
+ $this->handler = $handler;
+
+ unset($this->context[count($this->context) - 1]);
+ }
+
+ /**
+ *
+ */
+ public function getInstructions($text) {
+ $this->callWriter = new refnotes_nested_call_writer($this->handler->getCallWriter(), $this->handler);
+
+ $this->callWriter->connect();
+ $this->lexer->parse($text);
+ $this->callWriter->disconnect();
+
+ return $this->callWriter->calls;
+ }
+
+ /**
+ *
+ */
+ private function getCurrentContext() {
+ return end($this->context);
+ }
+
+ /**
+ *
+ */
+ public function canHandle($state) {
+ return $this->getCurrentContext()->canHandle($state);
+ }
+
+ /**
+ *
+ */
+ public function enterReference($name, $data) {
+ $this->getCurrentContext()->enterReference($name, $data);
+ }
+
+ /**
+ *
+ */
+ public function exitReference() {
+ return $this->getCurrentContext()->exitReference();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_parsing_context {
+
+ private $handling;
+ private $reference;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->reset();
+ }
+
+ /**
+ *
+ */
+ private function reset() {
+ $this->handling = false;
+ $this->reference = NULL;
+ }
+
+ /**
+ *
+ */
+ public function canHandle($state) {
+ switch ($state) {
+ case DOKU_LEXER_ENTER:
+ $result = !$this->handling;
+ break;
+
+ case DOKU_LEXER_EXIT:
+ $result = $this->handling;
+ break;
+
+ default:
+ $result = false;
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function enterReference($name, $data) {
+ $this->handling = true;
+ $this->reference = new refnotes_parser_reference($name, $data);
+ }
+
+ /**
+ *
+ */
+ public function exitReference() {
+ $reference = $this->reference;
+
+ $this->reset();
+
+ return $reference;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+abstract class refnotes_core {
+
+ protected $presetStyle;
+ protected $namespace;
+ protected $mapping;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->presetStyle = refnotes_configuration::load('namespaces');
+ $this->namespace = array();
+ $this->mapping = array();
+ }
+
+ /**
+ *
+ */
+ public function getNamespaceCount() {
+ return count($this->namespace);
+ }
+
+ /**
+ * Returns a namespace given it's name. The namespace is created if it doesn't exist yet.
+ */
+ public function getNamespace($name) {
+ $result = $this->findNamespace($name);
+
+ if ($result == NULL) {
+ $result = $this->createNamespace($name);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Finds a namespace given it's name
+ */
+ protected function findNamespace($name) {
+ $result = NULL;
+
+ if (array_key_exists($name, $this->namespace)) {
+ $result = $this->namespace[$name];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Finds a namespace or it's parent
+ */
+ public function findParentNamespace($name) {
+ while (($name != '') && !array_key_exists($name, $this->namespace)) {
+ $name = refnotes_namespace::getParentName($name);
+ }
+
+ return ($name != '') ? $this->namespace[$name] : NULL;
+ }
+
+ /**
+ *
+ */
+ public function styleNamespace($namespaceName, $style) {
+ $namespace = $this->getNamespace($namespaceName);
+
+ if (array_key_exists('inherit', $style)) {
+ $source = $this->getNamespace($style['inherit']);
+ $namespace->inheritStyle($source);
+ }
+
+ $namespace->setStyle($style);
+ }
+
+ /**
+ *
+ */
+ public function setNamespaceMapping($namespaceName, $map) {
+ foreach ($map as $ns) {
+ $this->mapping[$ns] = $namespaceName;
+ }
+ }
+
+ /**
+ *
+ */
+ protected function clearNamespaceMapping($namespaceName) {
+ $this->mapping = array_diff($this->mapping, array($namespaceName));
+ }
+
+ /**
+ *
+ */
+ protected function createNamespace($name) {
+ if ($name != ':') {
+ $parentName = refnotes_namespace::getParentName($name);
+ $parent = $this->getNamespace($parentName);
+ $this->namespace[$name] = new refnotes_namespace($name, $parent);
+ }
+ else {
+ $this->namespace[$name] = new refnotes_namespace($name);
+ }
+
+ if (array_key_exists($name, $this->presetStyle)) {
+ $this->namespace[$name]->setStyle($this->presetStyle[$name]);
+ }
+
+ return $this->namespace[$name];
+ }
+
+ /**
+ *
+ */
+ protected function getNote($namespaceName, $noteName) {
+ $scope = $this->getNamespace($namespaceName)->getActiveScope();
+ $note = $scope->findNote($namespaceName, $noteName);
+
+ if (($note == NULL) && array_key_exists($namespaceName, $this->mapping)) {
+ $scope = $this->getNamespace($this->mapping[$namespaceName])->getActiveScope();
+ $note = $scope->findNote($namespaceName, $noteName);
+ }
+
+ if ($note == NULL) {
+ if (!is_int($noteName)) {
+ $note = $this->createNote($scope, $namespaceName, $noteName);
+
+ $scope->addNote($note);
+ }
+ else {
+ $note = new refnotes_note_mock();
+ }
+ }
+
+ return $note;
+ }
+
+ /**
+ *
+ */
+ abstract protected function createNote($scope, $namespaceName, $noteName);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer_core extends refnotes_core {
+
+ private static $instance = NULL;
+
+ /**
+ * Renderer core is used by both references and notes syntax plugins during the rendering
+ * stage. The instance has to be shared between the plugins, and since there should be no
+ * more than one rendering pass during a DW page request, a single instance of the syntax
+ * core should be enough.
+ */
+ public static function getInstance() {
+ if (self::$instance == NULL) {
+ self::$instance = new refnotes_renderer_core();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ *
+ */
+ public function addReference($attributes, $data) {
+ $note = $this->getNote($attributes['ns'], $attributes['name']);
+ $reference = new refnotes_renderer_reference($note, $attributes, $data);
+
+ $note->addReference($reference);
+
+ return $reference;
+ }
+
+ /**
+ *
+ */
+ public function renderNotes($mode, $namespaceName, $limit) {
+ $this->clearNamespaceMapping($namespaceName);
+
+ $html = '';
+
+ if ($namespaceName == '*') {
+ foreach ($this->namespace as $namespace) {
+ $html .= $namespace->renderNotes($mode);
+ }
+ }
+ else {
+ $namespace = $this->findNamespace($namespaceName);
+ if ($namespace != NULL) {
+ $html = $namespace->renderNotes($mode, $limit);
+ }
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function createNote($scope, $namespaceName, $noteName) {
+ return new refnotes_renderer_note($scope, $namespaceName, $noteName);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_action_core extends refnotes_core {
+
+ private $styleStash;
+ private $mappingStash;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ $this->styleStash = new refnotes_namespace_style_stash($this);
+ $this->mappingStash = new refnotes_namespace_mapping_stash();
+ }
+
+ /**
+ *
+ */
+ public function markScopeStart($namespaceName, $callIndex) {
+ $this->getNamespace($namespaceName)->markScopeStart($callIndex);
+ }
+
+ /**
+ *
+ */
+ public function markScopeEnd($namespaceName, $callIndex) {
+ $this->getNamespace($namespaceName)->markScopeEnd($callIndex);
+ }
+
+ /**
+ * Collect styling information from the page
+ */
+ public function addStyle($namespaceName, $style) {
+ $this->styleStash->add($this->getNamespace($namespaceName), $style);
+ }
+
+ /**
+ *
+ */
+ public function getStyles() {
+ return $this->styleStash;
+ }
+
+ /**
+ * Collect mapping information from the page
+ */
+ public function addMapping($namespaceName, $map) {
+ $this->mappingStash->add($this->getNamespace($namespaceName), $map);
+ }
+
+ /**
+ *
+ */
+ public function getMappings() {
+ return $this->mappingStash;
+ }
+
+ /**
+ *
+ */
+ public function reset() {
+ $this->namespace = array();
+ }
+
+ /**
+ *
+ */
+ public function addReference($attributes, $data, $call) {
+ $note = $this->getNote($attributes['ns'], $attributes['name']);
+ $reference = new refnotes_action_reference($note, $attributes, $data, $call);
+
+ $note->addReference($reference);
+
+ return $reference;
+ }
+
+ /**
+ *
+ */
+ public function rewriteReferences($namespaceName, $limit) {
+ $this->clearNamespaceMapping($namespaceName);
+
+ if ($namespaceName == '*') {
+ foreach ($this->namespace as $namespace) {
+ $namespace->rewriteReferences();
+ }
+ }
+ else {
+ $namespace = $this->findNamespace($namespaceName);
+ if ($namespace != NULL) {
+ $namespace->rewriteReferences($limit);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ protected function createNote($scope, $namespaceName, $noteName) {
+ return new refnotes_action_note($scope, $namespaceName, $noteName);
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/database.php b/platform/www/lib/plugins/refnotes/database.php
new file mode 100644
index 0000000..47388a2
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/database.php
@@ -0,0 +1,563 @@
+<?php
+
+/**
+ * Plugin RefNotes: Reference database
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_reference_database {
+
+ private static $instance = NULL;
+
+ private $note;
+ private $key;
+ private $page;
+ private $namespace;
+ private $enabled;
+
+ /**
+ *
+ */
+ public static function getInstance() {
+ if (self::$instance == NULL) {
+ self::$instance = new refnotes_reference_database();
+
+ /* Loading has to be separated from construction to prevent infinite recursion */
+ self::$instance->load();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->page = array();
+ $this->namespace = array();
+ $this->enabled = true;
+ }
+
+ /**
+ *
+ */
+ private function load() {
+ $this->loadNotesFromConfiguration();
+
+ if (refnotes_configuration::getSetting('reference-db-enable')) {
+ $this->loadKeys();
+ $this->loadPages();
+ $this->loadNamespaces();
+ }
+ }
+
+ /**
+ *
+ */
+ private function loadNotesFromConfiguration() {
+ $note = refnotes_configuration::load('notes');
+
+ foreach ($note as $name => $data) {
+ $this->note[$name] = new refnotes_reference_database_note('{configuration}', $data);
+ }
+ }
+
+ /**
+ *
+ */
+ private function loadKeys() {
+ $locale = refnotes_localization::getInstance();
+ foreach ($locale->getByPrefix('dbk') as $key => $text) {
+ $this->key[$this->normalizeKeyText($text)] = $key;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getKey($text) {
+ $result = '';
+ $text = $this->normalizeKeyText($text);
+
+ if (in_array($text, $this->key)) {
+ $result = $text;
+ }
+ elseif (array_key_exists($text, $this->key)) {
+ $result = $this->key[$text];
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ private function normalizeKeyText($text) {
+ return preg_replace('/\s+/', ' ', utf8_strtolower(trim($text)));
+ }
+
+ /**
+ *
+ */
+ private function loadPages() {
+ global $conf;
+
+ if (file_exists($conf['indexdir'] . '/page.idx')) {
+ require_once(DOKU_INC . 'inc/indexer.php');
+
+ $pageIndex = idx_getIndex('page', '');
+ $namespace = refnotes_configuration::getSetting('reference-db-namespace');
+ $namespacePattern = '/^' . trim($namespace, ':') . ':/';
+ $cache = new refnotes_reference_database_cache();
+
+ foreach ($pageIndex as $pageId) {
+ $pageId = trim($pageId);
+
+ if ((preg_match($namespacePattern, $pageId) == 1) && file_exists(wikiFN($pageId))) {
+ $this->enabled = false;
+ $this->page[$pageId] = new refnotes_reference_database_page($this, $cache, $pageId);
+ $this->enabled = true;
+ }
+ }
+
+ $cache->save();
+ }
+ }
+
+ /**
+ *
+ */
+ private function loadNamespaces() {
+ foreach ($this->page as $pageId => $page) {
+ foreach ($page->getNamespaces() as $ns) {
+ $this->namespace[$ns][] = $pageId;
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ public function findNote($name) {
+ if (!$this->enabled) {
+ return NULL;
+ }
+
+ $found = array_key_exists($name, $this->note);
+
+ if (!$found) {
+ list($namespace, $temp) = refnotes_namespace::parseName($name);
+
+ if (array_key_exists($namespace, $this->namespace)) {
+ $this->loadNamespaceNotes($namespace);
+
+ $found = array_key_exists($name, $this->note);
+ }
+ }
+
+ return $found ? $this->note[$name] : NULL;
+ }
+
+ /**
+ *
+ */
+ private function loadNamespaceNotes($namespace) {
+ foreach ($this->namespace[$namespace] as $pageId) {
+ if (array_key_exists($pageId, $this->page)) {
+ $this->enabled = false;
+ $this->note = array_merge($this->note, $this->page[$pageId]->getNotes());
+ $this->enabled = true;
+
+ unset($this->page[$pageId]);
+ }
+ }
+
+ unset($this->namespace[$namespace]);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_reference_database_page {
+
+ private $database;
+ private $id;
+ private $fileName;
+ private $namespace;
+ private $note;
+
+ /**
+ * Constructor
+ */
+ public function __construct($database, $cache, $id) {
+ $this->database = $database;
+ $this->id = $id;
+ $this->fileName = wikiFN($id);
+ $this->namespace = array();
+ $this->note = array();
+
+ if ($cache->isCached($this->fileName)) {
+ $this->namespace = $cache->getNamespaces($this->fileName);
+ }
+ else {
+ $this->parse();
+
+ $cache->update($this->fileName, $this->namespace);
+ }
+ }
+
+ /**
+ *
+ */
+ private function parse() {
+ $text = io_readWikiPage($this->fileName, $this->id);
+ $call = p_cached_instructions($this->fileName);
+ $calls = count($call);
+
+ for ($c = 0; $c < $calls; $c++) {
+ if ($call[$c][0] == 'table_open') {
+ $c = $this->parseTable($call, $calls, $c, $text);
+ }
+ elseif ($call[$c][0] == 'code') {
+ $this->parseCode($call[$c]);
+ }
+ elseif (($call[$c][0] == 'plugin') && ($call[$c][1][0] == 'data_entry')) {
+ $this->parseDataEntry($call[$c][1][1]);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function parseTable($call, $calls, $c, $text) {
+ $row = 0;
+ $column = 0;
+ $columns = 0;
+ $valid = true;
+
+ for ( ; $c < $calls; $c++) {
+ switch ($call[$c][0]) {
+ case 'tablerow_open':
+ $column = 0;
+ break;
+
+ case 'tablerow_close':
+ if ($row == 0) {
+ $columns = $column;
+ }
+ else {
+ if ($column != $columns) {
+ $valid = false;
+ break 2;
+ }
+ }
+ $row++;
+ break;
+
+ case 'tablecell_open':
+ case 'tableheader_open':
+ $cellOpen = $call[$c][2];
+ break;
+
+ case 'tablecell_close':
+ case 'tableheader_close':
+ $table[$row][$column] = trim(substr($text, $cellOpen, $call[$c][2] - $cellOpen), "^| ");
+ $column++;
+ break;
+
+ case 'table_close':
+ break 2;
+ }
+ }
+
+ if ($valid && ($row > 1) && ($columns > 1)) {
+ $this->handleTable($table, $columns, $row);
+ }
+
+ return $c;
+ }
+
+ /**
+ *
+ */
+ private function handleTable($table, $columns, $rows) {
+ $key = array();
+ for ($c = 0; $c < $columns; $c++) {
+ $key[$c] = $this->database->getKey($table[0][$c]);
+ }
+
+ if (!in_array('', $key)) {
+ $this->handleDataSheet($table, $columns, $rows, $key);
+ }
+ else {
+ if ($columns == 2) {
+ $key = array();
+ for ($r = 0; $r < $rows; $r++) {
+ $key[$r] = $this->database->getKey($table[$r][0]);
+ }
+
+ if (!in_array('', $key)) {
+ $this->handleDataCard($table, $rows, $key);
+ }
+ }
+ }
+ }
+
+ /**
+ * The data is organized in rows, one note per row. The first row contains the caption.
+ */
+ private function handleDataSheet($table, $columns, $rows, $key) {
+ for ($r = 1; $r < $rows; $r++) {
+ $data = array();
+
+ for ($c = 0; $c < $columns; $c++) {
+ $data[$key[$c]] = $table[$r][$c];
+ }
+
+ $this->handleNote($data);
+ }
+ }
+
+ /**
+ * Every note is stored in a separate table. The first column of the table contains
+ * the caption, the second one contains the data.
+ */
+ private function handleDataCard($table, $rows, $key) {
+ $data = array();
+
+ for ($r = 0; $r < $rows; $r++) {
+ $data[$key[$r]] = $table[$r][1];
+ }
+
+ $this->handleNote($data);
+ }
+
+ /**
+ *
+ */
+ private function parseCode($call) {
+ switch ($call[1][1]) {
+ case 'bibtex':
+ $this->parseBibtex($call[1][0]);
+ break;
+ }
+ }
+
+ /**
+ *
+ */
+ private function parseBibtex($text) {
+ foreach (refnotes_bibtex_parser::getInstance()->parse($text) as $data) {
+ $this->handleNote($data);
+ }
+ }
+
+ /**
+ *
+ */
+ private function parseDataEntry($pluginData) {
+ if (preg_match('/\brefnotes\b/', $pluginData['classes'])) {
+ $data = array();
+
+ foreach ($pluginData['data'] as $key => $value) {
+ if (is_array($value)) {
+ $data[$key . 's'] = implode(', ', $value);
+ }
+ else {
+ $data[$key] = $value;
+ }
+ }
+
+ $this->handleNote($data);
+ }
+ }
+
+ /**
+ *
+ */
+ private function handleNote($data) {
+ $note = new refnotes_reference_database_note($this->id, $data);
+
+ list($namespace, $name) = $note->getNameParts();
+
+ if ($name != '') {
+ if (!in_array($namespace, $this->namespace)) {
+ $this->namespace[] = $namespace;
+ }
+
+ $this->note[$namespace . $name] = $note;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getNamespaces() {
+ return $this->namespace;
+ }
+
+ /**
+ *
+ */
+ public function getNotes() {
+ if (empty($this->note)) {
+ $this->parse();
+ }
+
+ return $this->note;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_reference_database_note extends refnotes_refnote {
+
+ private $nameParts;
+
+ /**
+ * Constructor
+ */
+ public function __construct($source, $data) {
+ parent::__construct();
+
+ $this->nameParts = array('', '');
+
+ if ($source == '{configuration}') {
+ $this->initializeConfigNote($data);
+ }
+ else {
+ $this->initializePageNote($data);
+ }
+
+ $this->attributes['source'] = $source;
+ }
+
+ /**
+ *
+ */
+ public function initializeConfigNote($data) {
+ $this->data['note-text'] = $data['text'];
+
+ unset($data['text']);
+
+ $this->attributes = $data;
+ }
+
+ /**
+ *
+ */
+ public function initializePageNote($data) {
+ if (isset($data['note-name'])) {
+ if (preg_match('/^' . refnotes_note::getNamePattern('full-extended') . '$/', $data['note-name']) == 1) {
+ $this->nameParts = refnotes_namespace::parseName($data['note-name']);
+ }
+
+ unset($data['note-name']);
+ }
+
+ $this->data = $data;
+ }
+
+ /**
+ *
+ */
+ public function getNameParts() {
+ return $this->nameParts;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_reference_database_cache {
+
+ private $fileName;
+ private $cache;
+ private $requested;
+ private $updated;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ global $conf;
+
+ $this->fileName = $conf['cachedir'] . '/refnotes.database.dat';
+
+ $this->load();
+ }
+
+ /**
+ *
+ */
+ private function load() {
+ $this->cache = array();
+ $this->requested = array();
+
+ if (file_exists($this->fileName)) {
+ $this->cache = unserialize(io_readFile($this->fileName, false));
+ }
+
+ foreach (array_keys($this->cache) as $fileName) {
+ $this->requested[$fileName] = false;
+ }
+
+ $this->updated = false;
+ }
+
+ /**
+ *
+ */
+ public function isCached($fileName) {
+ $result = false;
+
+ if (array_key_exists($fileName, $this->cache)) {
+ if ($this->cache[$fileName]['time'] == @filemtime($fileName)) {
+ $result = true;
+ }
+ }
+
+ $this->requested[$fileName] = true;
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function getNamespaces($fileName) {
+ return $this->cache[$fileName]['ns'];
+ }
+
+ /**
+ *
+ */
+ public function update($fileName, $namespace) {
+ $this->cache[$fileName] = array('ns' => $namespace, 'time' => @filemtime($fileName));
+ $this->updated = true;
+ }
+
+ /**
+ *
+ */
+ public function save() {
+ $this->removeOldPages();
+
+ if ($this->updated) {
+ io_saveFile($this->fileName, serialize($this->cache));
+ }
+ }
+
+ /**
+ *
+ */
+ private function removeOldPages() {
+ foreach ($this->requested as $fileName => $requested) {
+ if (!$requested && array_key_exists($fileName, $this->cache)) {
+ unset($this->cache[$fileName]);
+
+ $this->updated = true;
+ }
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/instructions.php b/platform/www/lib/plugins/refnotes/instructions.php
new file mode 100644
index 0000000..7711a27
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/instructions.php
@@ -0,0 +1,318 @@
+<?php
+
+/**
+ * Plugin RefNotes: Handling of instruction array
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_instruction {
+
+ protected $data;
+
+ /**
+ * Constructor
+ */
+ public function __construct($name, $data, $offset = -1) {
+ $this->data = array($name, $data, $offset);
+ }
+
+ /**
+ *
+ */
+ public function getData() {
+ return $this->data;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_nest_instruction extends refnotes_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($data) {
+ parent::__construct('nest', array($data));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_plugin_instruction extends refnotes_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($name, $data, $type, $text, $offset = -1) {
+ parent::__construct('plugin', array($name, $data, $type, $text), $offset);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_notes_instruction extends refnotes_plugin_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($type, $attributes, $data = NULL) {
+ $pluginData[0] = $type;
+ $pluginData[1] = $attributes;
+
+ if (!empty($data)) {
+ $pluginData[2] = $data;
+ }
+
+ parent::__construct('refnotes_notes', $pluginData, DOKU_LEXER_SPECIAL, '');
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_notes_style_instruction extends refnotes_notes_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace, $data) {
+ parent::__construct('style', array('ns' => $namespace), $data);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_notes_map_instruction extends refnotes_notes_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace, $data) {
+ parent::__construct('map', array('ns' => $namespace), $data);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_notes_render_instruction extends refnotes_notes_instruction {
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace) {
+ parent::__construct('render', array('ns' => $namespace));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_instruction_reference {
+
+ private $list;
+ private $data;
+ private $index;
+ private $name;
+
+ /**
+ * Constructor
+ */
+ public function __construct($list, &$data, $index) {
+ $this->list = $list;
+ $this->data =& $data;
+ $this->index = $index;
+ $this->name = ($data[0] == 'plugin') ? 'plugin_' . $data[1][0] : $data[0];
+ }
+
+ /**
+ *
+ */
+ public function getIndex() {
+ return $this->index;
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function getData($index) {
+ return $this->data[1][$index];
+ }
+
+ /**
+ *
+ */
+ public function getPluginData($index) {
+ return $this->data[1][1][$index];
+ }
+
+ /**
+ *
+ */
+ public function setPluginData($index, $data) {
+ $this->data[1][1][$index] = $data;
+ }
+
+ /**
+ *
+ */
+ public function unsetPluginData($index) {
+ unset($this->data[1][1][$index]);
+ }
+
+ /**
+ *
+ */
+ public function getRefnotesAttribute($name) {
+ return array_key_exists($name, $this->data[1][1][1]) ? $this->data[1][1][1][$name] : '';
+ }
+
+ /**
+ *
+ */
+ public function setRefnotesAttribute($name, $value) {
+ $this->data[1][1][1][$name] = $value;
+ }
+
+ /**
+ *
+ */
+ public function unsetRefnotesAttribute($name) {
+ unset($this->data[1][1][1][$name]);
+ }
+
+ /**
+ *
+ */
+ public function getPrevious() {
+ return $this->list->getAt($this->index - 1);
+ }
+
+ /**
+ *
+ */
+ public function insertBefore($call) {
+ return $this->list->insert($this->index, $call);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_instruction_list implements Iterator {
+
+ private $event;
+ private $index;
+ private $extraCalls;
+
+ /**
+ * Constructor
+ */
+ public function __construct($event) {
+ $this->event = $event;
+ $this->index = 0;
+ $this->extraCalls = array();
+ }
+
+ /**
+ * Implementation of Iterator interface
+ */
+ public function rewind() {
+ $this->index = 0;
+ }
+
+ /**
+ * Implementation of Iterator interface
+ */
+ public function current() {
+ return new refnotes_instruction_reference($this, $this->event->data->calls[$this->index], $this->index);
+ }
+
+ /**
+ * Implementation of Iterator interface
+ */
+ public function key() {
+ return $this->index;
+ }
+
+ /**
+ * Implementation of Iterator interface
+ */
+ public function next() {
+ ++$this->index;
+ }
+
+ /**
+ * Implementation of Iterator interface
+ */
+ public function valid() {
+ return array_key_exists($this->index, $this->event->data->calls);
+ }
+
+ /**
+ *
+ */
+ public function getAt($index) {
+ return new refnotes_instruction_reference($this, $this->event->data->calls[$index], $index);
+ }
+
+ /**
+ *
+ */
+ public function insert($index, $call) {
+ $this->extraCalls[$index][] = $call;
+ }
+
+ /**
+ *
+ */
+ public function append($call) {
+ $this->extraCalls[count($this->event->data->calls)][] = $call;
+ }
+
+ /**
+ *
+ */
+ public function applyChanges() {
+ if (empty($this->extraCalls)) {
+ return;
+ }
+
+ ksort($this->extraCalls);
+
+ $calls = array();
+ $prevIndex = 0;
+
+ foreach ($this->extraCalls as $index => $extraCalls) {
+ if ($prevIndex < $index) {
+ $slice = array_slice($this->event->data->calls, $prevIndex, $index - $prevIndex);
+ $calls = array_merge($calls, $slice);
+ }
+
+ foreach ($extraCalls as $call) {
+ $calls[] = $call->getData();
+ }
+
+ $prevIndex = $index;
+ }
+
+ $callCount = count($this->event->data->calls);
+
+ if ($prevIndex < $callCount) {
+ $slice = array_slice($this->event->data->calls, $prevIndex, $callCount - $prevIndex);
+ $calls = array_merge($calls, $slice);
+ }
+
+ $offset = $this->event->data->calls[$callCount - 1][2];
+
+ for ($i = count($calls) - 1; $i >= 0; --$i) {
+ if ($calls[$i][2] == -1) {
+ $calls[$i][2] = $offset;
+ }
+ else {
+ $offset = $calls[$i][2];
+ }
+ }
+
+ $this->event->data->calls = $calls;
+ $this->extraCalls = array();
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/lang/en/__template.txt b/platform/www/lib/plugins/refnotes/lang/en/__template.txt
new file mode 100644
index 0000000..2022a92
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/lang/en/__template.txt
@@ -0,0 +1,82 @@
+====== References ======
+
+On this page you can define commonly used notes for [[doku>plugin:refnotes|RefNotes plugin]]. Every note is defined as collection of data //fields//. There are number of ways to organize the note definitions:
+
+ * Group a number of notes into single data table (//sheet//). The first row of the table is used to specify which field the corresponding column contains.
+ * Use separate table for each note (//card//). The table should have two columns where the first column is used to specify the field names.
+ * Define notes using [[wp>BibTeX]] syntax. BibTeX entries have to be wrapped into a ''<code>'' section. The key of BibTeX entry serves as name of the note. The namespace can be either specified as part of the key or in a separate comment (see example below) for all entries that follow.
+ * Store one note per page as [[doku>plugin:data|Data plugin]] entry. This way the notes are stored in a database, which allows to make queries against the bibliography data, for example, see all books of a certain author. Unfortunately Data plugin allows only one ''dataentry'' section per page.
+
+For sheets and cards plugin does not make a distinction between normal table cells and header cells. The field name cells are identified only based on their content. The names are case insensitive and can also be specified using locale-specific labels. BibTeX and ''dataentry'' sections support only field names. The full list of field names is provided in [[doku>plugin:refnotes:refdb|reference database documentation]].
+
+
+===== Note sheet example =====
+
+^ Note name ^ Note text ^
+^ :ref:sample1 | A sample reference. |
+^ :ref:sample2 | A sample reference with //some// **formatting**. |
+^ :ref:sample3 | A sample reference with a [[http://www.dokuwiki.org/|link.]] |
+
+
+===== Note card example =====
+
+^ Note name ^ :ref:knuth-aop-2 ^
+^ Author | Donald Knuth |
+^ Title | The Art of Computer Programming, Volume 2: Seminumerical Algorithms |
+^ Edition | Third Edition |
+^ Published | 1997 |
+^ Publisher | Addison-Wesley |
+^ Pages | xiv + 762 pp. |
+^ ISBN | 0-201-89684-2 |
+^ URL | http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming |
+
+
+===== BibTeX example =====
+
+<code bibtex>
+@Comment{refnotes,
+ namespace = "ref:prog"
+}
+
+@Book{GangOfFour,
+ author = "Erich {Gamma} and Richard {Helm} and Ralph {Johnson} and John {Vlissides}",
+ author-ref = "Gamma, et al.",
+ title = "Design Patterns: Elements of Reusable Object-Oriented Software",
+ publisher = "Addison-Wesley",
+ year = 1994,
+ address = "Reading, Mass.",
+ pages = 395,
+ isbn = "0-201-63361-2",
+ url = "http://en.wikipedia.org/wiki/Design_Patterns"
+}
+
+@Article{:ref:Knuth-LCE-1985,
+ author = "Donald Knuth",
+ title = "Deciphering a linear congruential encryption",
+ journal = "IEEE Transactions on Information Theory",
+ volume = "31(1)",
+ year = 1985,
+ month = "Jan",
+ publisher = "IEEE",
+ pages = "49-52",
+ issn = "0018-9448",
+ url = "http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=1056997"
+}
+</code>
+
+===== Dataentry example =====
+
+The dataentry below is wrapped into ''<code>'' section to be properly presented in absence of [[doku>plugin:data|Data plugin]].
+
+<code>
+---- dataentry refnotes ----
+note-name : :ref:prog:Hunt&Thomas(1999)
+authors : Andrew Hunt, David Thomas
+title : The Pragmatic Programmer: From Journeyman to Master
+published : 1999
+publisher : Addison-Wesley Professional
+pages : 352
+isbn : 0-201-61622-X
+url : http://en.wikipedia.org/wiki/The_Pragmatic_Programmer
+----
+</code>
diff --git a/platform/www/lib/plugins/refnotes/lang/en/intro.txt b/platform/www/lib/plugins/refnotes/lang/en/intro.txt
new file mode 100644
index 0000000..42f5829
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/lang/en/intro.txt
@@ -0,0 +1,15 @@
+====== RefNotes Configuration ======
+
+On this page you modify the configuration settings used by [[doku>plugin:refnotes|RefNotes plugin]]. There are three sections that group related settings:
+
+ * **General settings**
+ * //Use footnotes syntax// --- if enabled the RefNotes plugin will be used to handle native DokuWiki footnotes along with it's own syntax.
+ * //Enable reference database// --- if enabled the plugin will load predefined notes form the [[doku>plugin:refnotes:refdb|reference database]].
+ * //Reference database namespace// --- DokuWiki namespace for the reference database.
+ * **Namespaces** --- in this section you can specify rendering style for predefined namespaces. For a detailed explanation of each style see the [[doku>plugin:refnotes:style|style reference]].
+ * **Notes** --- this section is used to predefine commonly used notes.
+ * //Inline// --- specifies if the note text should be [[doku>plugin:refnotes:syntax#inline_notes|inlined]]. For inline notes you can configure if various reference styles are applied or not.
+
+Settings that are shown on a blue background are the default values. In the //Namespaces// section settings that are shown on a green background are inherited from the parent namespace.
+
+Remember to press the **Save** button on the bottom of this page before leaving otherwise your changes will be lost.
diff --git a/platform/www/lib/plugins/refnotes/lang/en/lang.php b/platform/www/lib/plugins/refnotes/lang/en/lang.php
new file mode 100644
index 0000000..4106ce1
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/lang/en/lang.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Plugin RefNotes: English language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+// Settings must be present and set appropriately for the language
+$lang['encoding'] = 'utf-8';
+$lang['direction'] = 'ltr';
+
+// Reference database keys
+$lang['dbk_author'] = 'Author';
+$lang['dbk_authors'] = 'Authors';
+$lang['dbk_chapter'] = 'Chapter';
+$lang['dbk_edition'] = 'Edition';
+$lang['dbk_isbn'] = 'ISBN';
+$lang['dbk_issn'] = 'ISSN';
+$lang['dbk_journal'] = 'Journal';
+$lang['dbk_month'] = 'Month';
+$lang['dbk_note-name'] = 'Note name';
+$lang['dbk_note-page'] = 'Note page';
+$lang['dbk_note-pages'] = 'Note pages';
+$lang['dbk_note-text'] = 'Note text';
+$lang['dbk_page'] = 'Page';
+$lang['dbk_pages'] = 'Pages';
+$lang['dbk_published'] = 'Published';
+$lang['dbk_publisher'] = 'Publisher';
+$lang['dbk_ref-author'] = 'Reference author';
+$lang['dbk_ref-authors'] = 'Reference authors';
+$lang['dbk_title'] = 'Title';
+$lang['dbk_url'] = 'URL';
+$lang['dbk_volume'] = 'Volume';
+$lang['dbk_year'] = 'Year';
+
+$lang['txt_in_cap'] = 'In';
+$lang['txt_page_abbr'] = 'p.';
+$lang['txt_pages_abbr'] = 'pp.';
+
+// For admin plugins, the menu prompt to be displayed in the admin menu
+// if set here, the plugin doesn't need to override the getMenuText() method
+$lang['menu'] = 'RefNotes Configuration';
+
+$lang['noscript'] = 'Sorry, this page requires JavaScript to function properly. Please enable it or get a decent browser.';
+
+$lang['sec_general'] = 'General settings';
+$lang['sec_namespaces'] = 'Namespaces';
+$lang['sec_notes'] = 'Notes';
+
+$lang['lbl_replace-footnotes'] = 'Use footnotes syntax';
+$lang['lbl_reference-db-enable'] = 'Enable reference database';
+$lang['lbl_reference-db-namespace'] = 'Reference database namespace';
+
+$lang['lbl_refnote-id'] = 'Reference/note identifier style';
+$lang['lbl_reference-base'] = 'Reference baseline';
+$lang['lbl_reference-font-weight'] = 'Reference font weight';
+$lang['lbl_reference-font-style'] = 'Reference font style';
+$lang['lbl_reference-format'] = 'Reference formatting';
+$lang['lbl_reference-group'] = 'Reference grouping';
+$lang['lbl_reference-render'] = 'Reference rendering';
+$lang['lbl_multi-ref-id'] = 'Multi-reference identifier';
+$lang['lbl_note-preview'] = 'Note preview';
+$lang['lbl_notes-separator'] = 'Notes block separator';
+$lang['lbl_note-text-align'] = 'Note text alignment';
+$lang['lbl_note-font-size'] = 'Note font size';
+$lang['lbl_note-render'] = 'Note rendering';
+$lang['lbl_note-id-base'] = 'Note identifier baseline';
+$lang['lbl_note-id-font-weight'] = 'Note identifier font weight';
+$lang['lbl_note-id-font-style'] = 'Note identifier font style';
+$lang['lbl_note-id-format'] = 'Note identifier formatting';
+$lang['lbl_back-ref-caret'] = 'Back reference circumflex';
+$lang['lbl_back-ref-base'] = 'Back reference base line';
+$lang['lbl_back-ref-font-weight'] = 'Back reference font weight';
+$lang['lbl_back-ref-font-style'] = 'Back reference font style';
+$lang['lbl_back-ref-format'] = 'Back reference formatting';
+$lang['lbl_back-ref-separator'] = 'Back reference separator';
+$lang['lbl_scoping'] = 'Scoping behavior';
+
+$lang['lbl_inline'] = 'Inline';
+$lang['lbl_use-reference-base'] = 'Apply reference baseline';
+$lang['lbl_use-reference-font-weight'] = 'Apply reference font weight';
+$lang['lbl_use-reference-font-style'] = 'Apply reference font style';
+$lang['lbl_use-reference-format'] = 'Apply reference formatting';
+
+$lang['opt_arrow'] = 'Up arrow';
+$lang['opt_basic'] = 'Plain text';
+$lang['opt_bold'] = 'Bold';
+$lang['opt_brackets'] = 'Brackets';
+$lang['opt_caret'] = 'Circumflex';
+$lang['opt_comma'] = 'Comma';
+$lang['opt_dot'] = 'Dot';
+$lang['opt_group-comma'] = 'Separate with comma';
+$lang['opt_group-none'] = 'Don\'t group';
+$lang['opt_group-semicolon'] = 'Separate with semicolon';
+$lang['opt_harvard'] = 'Harvard system of referencing';
+$lang['opt_inherit'] = 'Inherit';
+$lang['opt_italic'] = 'Italic';
+$lang['opt_justify'] = 'Justify';
+$lang['opt_latin'] = 'Latin';
+$lang['opt_latin-lower'] = 'Latin lower case';
+$lang['opt_latin-upper'] = 'Latin upper case';
+$lang['opt_left'] = 'Left';
+$lang['opt_merge'] = 'Merge with back references';
+$lang['opt_none'] = 'None';
+$lang['opt_normal'] = 'Normal';
+$lang['opt_normal-text'] = 'Normal text';
+$lang['opt_note-counter'] = 'Note counter';
+$lang['opt_note-id'] = 'Note identifier';
+$lang['opt_note-name'] = 'Note name';
+$lang['opt_numeric'] = 'Numeric';
+$lang['opt_parents'] = 'Parentheses';
+$lang['opt_popup'] = 'Static pop-up';
+$lang['opt_prefix'] = 'Prefix back references';
+$lang['opt_ref-counter'] = 'Reference counter';
+$lang['opt_reset'] = 'New scope after each notes block';
+$lang['opt_right-bracket'] = 'Right bracket';
+$lang['opt_right-parent'] = 'Right parenthesis';
+$lang['opt_roman-lower'] = 'Roman lower case';
+$lang['opt_roman-upper'] = 'Roman upper case';
+$lang['opt_single'] = 'Use single scope';
+$lang['opt_small'] = 'Small';
+$lang['opt_stars'] = 'Stars';
+$lang['opt_super'] = 'Superscript';
+$lang['opt_tooltip'] = 'Tooltip';
+
+$lang['btn_add'] = 'Add';
+$lang['btn_rename'] = 'Rename';
+$lang['btn_delete'] = 'Delete';
+$lang['btn_save'] = 'Save';
+
+$lang['js_status'] = 'Server communication status.';
+$lang['js_loading'] = 'Loading configuration settings from the server...';
+$lang['js_loaded'] = 'Configuration settings are successfully loaded from the server.';
+$lang['js_loading_failed'] = 'Failed to load configuration settings from the server ({1}).';
+$lang['js_invalid_data'] = 'Configuration settings loaded from the server are invalid or corrupted ({1}).';
+$lang['js_saving'] = 'Saving configuration settings on the server...';
+$lang['js_saved'] = 'Configuration settings are successfully saved on the server.';
+$lang['js_saving_failed'] = 'Failed to save configuration settings on the server ({1}).';
+$lang['js_invalid_ns_name'] = 'The specified namespace name is invalid.';
+$lang['js_ns_name_exists'] = 'The {1} namespace already exists.';
+$lang['js_delete_ns'] = 'Are you sure you want to delete {1} namespace?';
+$lang['js_invalid_note_name'] = 'The specified note name is invalid.';
+$lang['js_note_name_exists'] = 'The {1} note already exists.';
+$lang['js_delete_note'] = 'Are you sure you want to delete {1} note?';
+$lang['js_unsaved'] = 'Your changes to the configuration settings are not saved.';
diff --git a/platform/www/lib/plugins/refnotes/locale.php b/platform/www/lib/plugins/refnotes/locale.php
new file mode 100644
index 0000000..8950621
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/locale.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * Plugin RefNotes: Localization
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+/**
+ * Plugins that rely on refnotes_localization should use this trait.
+ */
+trait refnotes_localization_plugin {
+ /**
+ *
+ */
+ public function getRawLang() {
+ return $this->lang;
+ }
+}
+
+class refnotes_localization {
+
+ private static $instance = NULL;
+
+ private $plugin;
+
+ /**
+ *
+ */
+ public static function initialize($plugin) {
+ if (self::$instance == NULL) {
+ self::$instance = new refnotes_localization($plugin);
+ }
+ }
+
+ /**
+ *
+ */
+ public static function getInstance() {
+ if (self::$instance == NULL) {
+ throw new Exception('Shared refnotes_localization instance is not properly initialized.');
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Constructor
+ */
+ private function __construct($plugin) {
+ $this->plugin = $plugin;
+ }
+
+ /**
+ *
+ */
+ public function getLang($id) {
+ return $this->plugin->getLang($id);
+ }
+
+ /**
+ *
+ */
+ public function getFileName($id) {
+ return $this->plugin->localFN($id);
+ }
+
+ /**
+ *
+ */
+ public function getByPrefix($prefix, $strip = true) {
+ $this->plugin->setupLocale();
+
+ if ($strip) {
+ $pattern = '/^' . $prefix . '_(.+)$/';
+ }
+ else {
+ $pattern = '/^(' . $prefix . '_.+)$/';
+ }
+
+ $result = array();
+
+ foreach ($this->plugin->getRawLang() as $key => $value) {
+ if (preg_match($pattern, $key, $match) == 1) {
+ $result[$match[1]] = $value;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/namespace.php b/platform/www/lib/plugins/refnotes/namespace.php
new file mode 100644
index 0000000..c3fa4b5
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/namespace.php
@@ -0,0 +1,463 @@
+<?php
+
+/**
+ * Plugin RefNotes: Namespace heplers
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+abstract class refnotes_namespace_data_stash {
+
+ protected $index;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->index = array();
+ }
+
+ /**
+ *
+ */
+ abstract public function add($namespace, $data);
+
+ /**
+ *
+ */
+ public function getCount() {
+ return count($this->index);
+ }
+
+ /**
+ *
+ */
+ public function getIndex() {
+ return array_keys($this->index);
+ }
+
+ /**
+ *
+ */
+ public function getAt($index) {
+ return array_key_exists($index, $this->index) ? $this->index[$index] : array();
+ }
+
+ /**
+ *
+ */
+ public function sort() {
+ ksort($this->index);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_namespace_data {
+
+ protected $namespace;
+ protected $data;
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace, $data) {
+ $this->namespace = $namespace;
+ $this->data = $data;
+ }
+
+ /**
+ *
+ */
+ public function getNamespace() {
+ return $this->namespace->getName();
+ }
+
+ /**
+ *
+ */
+ public function getData() {
+ return $this->data;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_namespace_style_stash extends refnotes_namespace_data_stash {
+
+ private $page;
+
+ /**
+ * Constructor
+ */
+ public function __construct($page) {
+ parent::__construct();
+
+ $this->page = $page;
+ }
+
+ /**
+ *
+ */
+ public function add($namespace, $data) {
+ $style = new refnotes_namespace_style_info($namespace, $data);
+ $parent = $style->getInheritedNamespace();
+
+ if (($parent == '') && ($namespace->getScopesCount() == 1)) {
+ /* Default inheritance for the first scope */
+ $parent = refnotes_namespace::getParentName($namespace->getName());
+ }
+
+ $index = $namespace->getStyleIndex($this->page->findParentNamespace($parent));
+
+ $this->index[$index][] = $style;
+ }
+ /**
+ * Sort the style blocks so that the namespaces with inherited style go after
+ * the namespaces they inherit from.
+ */
+ public function sort() {
+ parent::sort();
+
+ $this->sortByDefaultInheritance();
+ $this->sortByExplicitInheritance();
+ }
+
+ /**
+ *
+ */
+ private function sortByDefaultInheritance() {
+ foreach ($this->index as &$index) {
+ $namespace = array();
+
+ foreach ($index as $style) {
+ $namespace[] = $style->getNamespace();
+ }
+
+ array_multisort($namespace, SORT_ASC, $index);
+ }
+ }
+
+ /**
+ *
+ */
+ private function sortByExplicitInheritance() {
+ foreach ($this->index as &$index) {
+ $derived = array();
+ $sorted = array();
+
+ foreach ($index as $style) {
+ if ($style->isDerived()) {
+ $derived[] = $style;
+ }
+ else {
+ $sorted[] = $style;
+ }
+ }
+
+ $derivedCount = count($derived);
+
+ if ($derivedCount > 0) {
+ if ($derivedCount == 1) {
+ $sorted[] = $derived[0];
+ }
+ else {
+ /* Perform simplified topological sorting */
+ $target = array();
+ $source = array();
+
+ for ($i = 0; $i < $derivedCount; $i++) {
+ $target[$i] = $derived[$i]->getNamespace();
+ $source[$i] = $derived[$i]->getInheritedNamespace();
+ }
+
+ for ($j = 0; $j < $derivedCount; $j++) {
+ foreach ($source as $i => $s) {
+ if (!in_array($s, $target)) {
+ break;
+ }
+ }
+
+ $sorted[] = $derived[$i];
+
+ unset($target[$i]);
+ unset($source[$i]);
+ }
+ }
+ }
+
+ $index = $sorted;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_namespace_style_info extends refnotes_namespace_data {
+
+ /**
+ *
+ */
+ public function isDerived() {
+ return array_key_exists('inherit', $this->data);
+ }
+
+ /**
+ *
+ */
+ public function getInheritedNamespace() {
+ return $this->isDerived() ? $this->data['inherit'] : '';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_namespace_mapping_stash extends refnotes_namespace_data_stash {
+
+ /**
+ *
+ */
+ public function add($namespace, $data) {
+ $this->index[$namespace->getMappingIndex()][] = new refnotes_namespace_data($namespace, $data);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_namespace {
+
+ private $name;
+ private $style;
+ private $renderer;
+ private $scope;
+ private $newScope;
+
+ /**
+ *
+ */
+ public static function getNamePattern($type) {
+ $result = '(?:(?:' . refnotes_note::getNamePattern('strict') . ')?:)*';
+
+ if ($type == 'required') {
+ $result .= '(?::|' . refnotes_note::getNamePattern('strict') . '):*';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns canonic name for a namespace
+ */
+ public static function canonizeName($name) {
+ return preg_replace('/:{2,}/', ':', ':' . $name . ':');
+ }
+
+ /**
+ * Returns name of the parent namespace
+ */
+ public static function getParentName($name) {
+ return preg_replace('/\w*:$/', '', $name);
+ }
+
+ /**
+ * Splits full note name into namespace and name components
+ */
+ public static function parseName($name) {
+ $pos = strrpos($name, ':');
+ if ($pos !== false) {
+ $namespace = self::canonizeName(substr($name, 0, $pos));
+ $name = substr($name, $pos + 1);
+ }
+ else {
+ $namespace = ':';
+ }
+
+ return array($namespace, $name);
+ }
+
+ /**
+ * Constructor
+ */
+ public function __construct($name, $parent = NULL) {
+ $this->name = $name;
+ $this->style = array();
+ $this->renderer = NULL;
+ $this->scope = array();
+ $this->newScope = true;
+
+ if ($parent != NULL) {
+ $this->style = $parent->style;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function getScopesCount() {
+ return count($this->scope);
+ }
+
+ /**
+ *
+ */
+ public function inheritStyle($source) {
+ $this->style = $source->style;
+ $this->renderer = NULL;
+ }
+
+ /**
+ *
+ */
+ public function setStyle($style) {
+ $this->style = array_merge($this->style, $style);
+ $this->renderer = NULL;
+ }
+
+ /**
+ *
+ */
+ public function getStyle($name) {
+ return array_key_exists($name, $this->style) ? $this->style[$name] : '';
+ }
+
+ /**
+ * Defer creation of renderer until namespace style is set.
+ */
+ public function getRenderer() {
+ if ($this->renderer == NULL) {
+ $this->renderer = new refnotes_renderer($this);
+ }
+
+ return $this->renderer;
+ }
+
+ /**
+ *
+ */
+ private function getScope($index) {
+ $index = count($this->scope) + $index;
+
+ return ($index >= 0) ? $this->scope[$index] : new refnotes_scope_mock();
+ }
+
+ /**
+ *
+ */
+ private function getPreviousScope() {
+ return $this->getScope(-2);
+ }
+
+ /**
+ *
+ */
+ private function getCurrentScope() {
+ return $this->getScope(-1);
+ }
+
+ /**
+ *
+ */
+ public function getActiveScope() {
+ if ($this->newScope) {
+ $this->scope[] = new refnotes_scope($this, count($this->scope) + 1);
+ $this->newScope = false;
+ }
+
+ return $this->getCurrentScope();
+ }
+
+ /**
+ *
+ */
+ public function markScopeStart($callIndex) {
+ if (!$this->getCurrentScope()->isOpen()) {
+ $this->scope[] = new refnotes_scope(NULL, 0, $callIndex);
+ }
+ }
+
+ /**
+ *
+ */
+ public function markScopeEnd($callIndex) {
+ /* Create an empty scope if there is no open one */
+ $this->markScopeStart($callIndex - 1);
+ $this->getCurrentScope()->getLimits()->end = $callIndex;
+ }
+
+
+ /**
+ * Find last scope end within specified range
+ */
+ private function findScopeEnd($start, $end) {
+ for ($i = count($this->scope) - 1; $i >= 0; $i--) {
+ $scopeEnd = $this->scope[$i]->getLimits()->end;
+
+ if (($scopeEnd > $start) && ($scopeEnd < $end)) {
+ return $scopeEnd;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ *
+ */
+ public function getStyleIndex($parent) {
+ $previousEnd = $this->getPreviousScope()->getLimits()->end;
+ $currentStart = $this->getCurrentScope()->getLimits()->start;
+ $parentEnd = ($parent != NULL) ? $parent->findScopeEnd($previousEnd, $currentStart) : -1;
+
+ return max($parentEnd, $previousEnd) + 1;
+ }
+
+ /**
+ *
+ */
+ public function getMappingIndex() {
+ return $this->getPreviousScope()->getLimits()->end + 1;
+ }
+
+ /**
+ *
+ */
+ public function rewriteReferences($limit = '') {
+ $this->resetScope();
+
+ if (count($this->scope) > 0) {
+ $html = $this->getCurrentScope()->rewriteReferences($limit);
+ }
+ }
+
+ /**
+ *
+ */
+ public function renderNotes($mode, $limit = '') {
+ $this->resetScope();
+ $doc = '';
+
+ if (count($this->scope) > 0) {
+ $doc = $this->getCurrentScope()->renderNotes($mode, $limit);
+ }
+
+ return $doc;
+ }
+
+ /**
+ *
+ */
+ private function resetScope() {
+ switch ($this->getStyle('scoping')) {
+ case 'single':
+ break;
+
+ default:
+ $this->newScope = true;
+ break;
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/note.php b/platform/www/lib/plugins/refnotes/note.php
new file mode 100644
index 0000000..8379168
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/note.php
@@ -0,0 +1,336 @@
+<?php
+
+/**
+ * Plugin RefNotes: Note
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_note_block_iterator extends FilterIterator {
+
+ private $note;
+ private $limit;
+ private $count;
+
+ /**
+ * Constructor
+ */
+ public function __construct($note, $limit) {
+ $this->note = new ArrayObject($note);
+ $this->limit = $this->getBlockLimit($limit);
+ $this->count = 0;
+
+ parent::__construct($this->note->getIterator());
+ }
+
+ /**
+ *
+ */
+ function accept() {
+ $result = $this->current()->isValid();
+
+ if ($result) {
+ ++$this->count;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ function valid() {
+ return parent::valid() && (($this->limit == 0) || ($this->count <= $this->limit));
+ }
+
+ /**
+ *
+ */
+ private function getBlockLimit($limit) {
+ if (preg_match('/(\/?)(\d+)/', $limit, $match) == 1) {
+ if ($match[1] != '') {
+ $devider = intval($match[2]);
+ $result = ceil($this->getValidCount() / $devider);
+ }
+ else {
+ $result = intval($match[2]);
+ }
+ }
+ else {
+ $result = 0;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ private function getValidCount() {
+ $result = 0;
+
+ foreach ($this->note as $note) {
+ if ($note->isValid()) {
+ ++$result;
+ }
+ }
+
+ return $result;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_note_mock {
+
+ /**
+ *
+ */
+ public function getScope() {
+ return new refnotes_scope_mock();
+ }
+
+ /**
+ *
+ */
+ public function setText($text) {
+ }
+
+ /**
+ *
+ */
+ public function addReference($reference) {
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_note extends refnotes_refnote {
+
+ protected $scope;
+ protected $namespaceName;
+ protected $id;
+ protected $name;
+ protected $inline;
+ protected $reference;
+ protected $text;
+ protected $processed;
+
+ /**
+ *
+ */
+ public static function getNamePattern($type) {
+ if (($type == 'full-extended') || ($type == 'extended')) {
+ $result = ($type == 'full-extended') ? refnotes_namespace::getNamePattern('optional') : '';
+ $result .= '[[:alpha:]\d][\w.&\(\)\[\]{}+-]*';
+ }
+ else {
+ $result = '[[:alpha:]]\w*';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Constructor
+ */
+ public function __construct($scope, $namespaceName, $name) {
+ parent::__construct();
+
+ $this->scope = $scope;
+ $this->namespaceName = $namespaceName;
+ $this->id = -1;
+ $this->name = $name;
+ $this->inline = false;
+ $this->reference = array();
+ $this->text = '';
+ $this->processed = false;
+ }
+
+ /**
+ *
+ */
+ private function initId() {
+ $this->id = $this->scope->getNoteId();
+
+ if ($this->name == '') {
+ $this->name = '#' . $this->id;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ *
+ */
+ public function getNamespaceName() {
+ return $this->namespaceName;
+ }
+
+ /**
+ *
+ */
+ public function getScope() {
+ return $this->scope;
+ }
+
+ /**
+ *
+ */
+ public function setText($text) {
+ if ($this->text == '' || !$this->inline) {
+ $this->text = $text;
+ }
+ }
+
+ /**
+ *
+ */
+ public function getText() {
+ return $this->text;
+ }
+
+ /**
+ *
+ */
+ public function addReference($reference) {
+ if ($this->id == -1 && !$this->inline) {
+ $this->inline = $reference->isInline();
+
+ if (!$this->inline) {
+ $this->initId();
+ }
+ }
+
+ if ($reference->isBackReferenced()) {
+ $this->reference[] = $reference;
+ $this->processed = false;
+ }
+ }
+
+ /**
+ * Checks if the note should be processed
+ */
+ public function isValid() {
+ return !$this->processed && !empty($this->reference) && $this->text != '';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer_note extends refnotes_note {
+
+ /**
+ *
+ */
+ public function getMinReferenceId() {
+ $result = -1;
+
+ /* References are added in ascending order, so the first valid id should be minimal. */
+ foreach ($this->reference as $reference) {
+ if ($reference->getId() != -1) {
+ $result = $reference->getId();
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function getAnchorName() {
+ $result = 'refnotes';
+ $result .= $this->scope->getName();
+ $result .= ':note' . $this->id;
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function render($mode) {
+ $doc = $this->scope->getRenderer()->renderNote($mode, $this, $this->reference);
+
+ $this->reference = array();
+ $this->processed = true;
+
+ return $doc;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_action_note extends refnotes_note {
+
+ /**
+ * Constructor
+ */
+ public function __construct($scope, $namespaceName, $name) {
+ parent::__construct($scope, $namespaceName, $name);
+
+ $this->loadDatabaseDefinition();
+
+ $this->inline = $this->getAttribute('inline', false);
+ }
+
+ /**
+ *
+ */
+ private function loadDatabaseDefinition() {
+ $name = $this->namespaceName . $this->name;
+ $note = refnotes_reference_database::getInstance()->findNote($name);
+
+ if ($note != NULL) {
+ $this->attributes = $note->getAttributes();
+ $this->data = $note->getData();
+ }
+ }
+
+ /**
+ *
+ */
+ public function addReference($reference) {
+ parent::addReference($reference);
+
+ $exclude = $this->scope->getRenderer()->getReferencePrivateDataSet();
+ $data = array_diff_key($reference->getData(), array_flip($exclude));
+ $this->data = array_merge($this->data, $data);
+ }
+
+ /**
+ * Checks if the note should be processed. Simple notes are also reported as valid so that
+ * scope limits will produce note blocks identical to ones during rendering.
+ */
+ public function isValid() {
+ return !$this->processed && !empty($this->reference) && ($this->text != '' || $this->hasData());
+ }
+
+ /**
+ * Inject reference database data into references so that they can be properly rendered.
+ * Inject note text into the first reference.
+ */
+ public function rewriteReferences() {
+ if ($this->text == '' && $this->hasData()) {
+ foreach ($this->reference as $reference) {
+ $reference->rewrite($this->attributes, $this->data);
+ }
+
+ $this->reference[0]->setNoteText($this->scope->getRenderer()->renderNoteText($this));
+ }
+
+ $this->processed = true;
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/plugin.info.txt b/platform/www/lib/plugins/refnotes/plugin.info.txt
new file mode 100644
index 0000000..5f2d881
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/plugin.info.txt
@@ -0,0 +1,7 @@
+base refnotes
+author Mykola Ostrovskyy
+email dwpforge@gmail.com
+date 2021-05-23
+name RefNotes Plugin
+desc Extended syntax for footnotes and references.
+url http://www.dokuwiki.org/plugin:refnotes
diff --git a/platform/www/lib/plugins/refnotes/reference.php b/platform/www/lib/plugins/refnotes/reference.php
new file mode 100644
index 0000000..6a5f82a
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/reference.php
@@ -0,0 +1,192 @@
+<?php
+
+/**
+ * Plugin RefNotes: Reference
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_parser_reference extends refnotes_refnote {
+
+ /**
+ * Constructor
+ */
+ public function __construct($name, $data) {
+ list($namespace, $name) = refnotes_namespace::parseName($name);
+
+ if (preg_match('/(?:@@FNT|#)(\d+)/', $name, $match) == 1) {
+ $name = intval($match[1]);
+ }
+
+ parent::__construct(array('ns' => $namespace, 'name' => $name));
+
+ if ($data != '') {
+ $this->parseStructuredData($data);
+ }
+ }
+
+ /**
+ *
+ */
+ private function parseStructuredData($data) {
+ if (preg_match('/^\s*\|/', $data) == 1) {
+ preg_match_all('/\|\s*([-\w]+)\s*=\s*([^|]+)/', $data, $match, PREG_SET_ORDER);
+
+ foreach ($match as $m) {
+ $this->data[$m[1]] = preg_replace('/\s+/', ' ', trim($m[2]));
+ }
+ }
+ else {
+ preg_match_all('/([-\w]+)\s*:\s*(.+?)\s*?(?:(?<!\\\\);|\n|$)/', $data, $match, PREG_SET_ORDER);
+
+ foreach ($match as $m) {
+ $this->data[$m[1]] = str_replace('\\;', ';', $m[2]);
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_reference extends refnotes_refnote {
+
+ protected $inline;
+ protected $hidden;
+ protected $note;
+ protected $id;
+
+ /**
+ * Constructor
+ */
+ public function __construct($note, $attributes, $data) {
+ parent::__construct($attributes, $data);
+
+ $this->inline = $this->getAttribute('inline', false);
+ $this->hidden = $this->getAttribute('hidden', false);
+ $this->note = $note;
+ $this->id = -1;
+
+ if ($this->isBackReferenced()) {
+ $this->id = $this->note->getScope()->getReferenceId();
+ }
+ }
+
+ /**
+ *
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+ /**
+ *
+ */
+ public function getNote() {
+ return $this->note;
+ }
+
+ /**
+ *
+ */
+ public function isInline() {
+ return $this->inline;
+ }
+
+ /**
+ *
+ */
+ public function isBackReferenced() {
+ return !$this->inline && !$this->hidden;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer_reference extends refnotes_reference {
+
+ /**
+ *
+ */
+ public function getAnchorName() {
+ $result = 'refnotes';
+ $result .= $this->note->getScope()->getName();
+ $result .= ':ref' . $this->id;
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function render($mode) {
+ $doc = '';
+
+ if (!$this->hidden) {
+ $doc = $this->note->getScope()->getRenderer()->renderReference($mode, $this);
+ }
+
+ return $doc;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_action_reference extends refnotes_reference {
+
+ private $call;
+
+ /**
+ * Constructor
+ */
+ public function __construct($note, $attributes, $data, $call) {
+ parent::__construct($note, $attributes, $data);
+
+ $this->call = $call;
+ }
+
+ /**
+ *
+ */
+ private function updateAttributes($attributes) {
+ static $key = array('inline', 'use-reference-base', 'use-reference-font-weight', 'use-reference-font-style', 'use-reference-format', 'source');
+
+ foreach ($key as $k) {
+ if (array_key_exists($k, $attributes)) {
+ $this->attributes[$k] = $attributes[$k];
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private function updateData($data) {
+ $include = $this->note->getScope()->getRenderer()->getReferenceSharedDataSet();
+ $data = array_intersect_key($data, array_flip($include));
+ $this->data = array_merge($data, $this->data);
+ }
+
+ /**
+ *
+ */
+ public function rewrite($attributes, $data) {
+ $this->updateAttributes($attributes);
+ $this->updateData($data);
+
+ $this->call->setPluginData(1, $this->attributes);
+
+ if ($this->hasData()) {
+ $this->call->setPluginData(2, $this->data);
+ }
+ }
+
+ /**
+ *
+ */
+ public function setNoteText($text) {
+ if ($text != '') {
+ $calls = refnotes_parser_core::getInstance()->getInstructions($text);
+
+ $this->call->insertBefore(new refnotes_nest_instruction($calls));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/refnote.php b/platform/www/lib/plugins/refnotes/refnote.php
new file mode 100644
index 0000000..127cd18
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/refnote.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Plugin RefNotes: Common base class for references and notes
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_refnote {
+
+ protected $attributes;
+ protected $data;
+
+ /**
+ * Constructor
+ */
+ public function __construct($attributes = array(), $data = array()) {
+ $this->attributes = $attributes;
+ $this->data = $data;
+ }
+
+ /**
+ *
+ */
+ public function getAttributes() {
+ return $this->attributes;
+ }
+
+ /**
+ *
+ */
+ public function getAttribute($name, $default = '') {
+ return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
+ }
+
+ /**
+ *
+ */
+ public function getData() {
+ return $this->data;
+ }
+
+ /**
+ *
+ */
+ public function hasData() {
+ return !empty($this->data);
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/rendering.php b/platform/www/lib/plugins/refnotes/rendering.php
new file mode 100644
index 0000000..22f7c9f
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/rendering.php
@@ -0,0 +1,1272 @@
+<?php
+
+/**
+ * Plugin RefNotes: Renderer
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer_mock {
+
+ /**
+ *
+ */
+ public function renderReference($reference) {
+ return '';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+abstract class refnotes_renderer_base {
+
+ protected $namespace;
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace) {
+ $this->namespace = $namespace;
+ }
+
+ /**
+ *
+ */
+ protected function getStyle($name) {
+ return $this->namespace->getStyle($name);
+ }
+
+ /**
+ * Returns an array of keys for data that is shared between references and notes.
+ */
+ abstract public function getReferenceSharedDataSet();
+
+ /**
+ * Returns an array of keys for data that is specific to references.
+ */
+ abstract public function getReferencePrivateDataSet();
+
+ /**
+ *
+ */
+ abstract public function renderReference($mode, $reference);
+
+ /**
+ *
+ */
+ abstract public function renderNoteText($note);
+
+ /**
+ *
+ */
+ abstract public function renderNote($mode, $note, $reference);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer extends refnotes_renderer_base {
+
+ private $referenceRenderer;
+ private $noteRenderer;
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace) {
+ parent::__construct($namespace);
+
+ $this->referenceRenderer = $this->createRenderer($this->getStyle('reference-render'));
+ $this->noteRenderer = $this->createRenderer($this->getStyle('note-render'));
+ }
+
+ /**
+ *
+ */
+ private function createRenderer($style) {
+ switch ($style) {
+ case 'harvard':
+ $renderer = new refnotes_harvard_renderer($this->namespace);
+ break;
+
+ default:
+ $renderer = new refnotes_basic_renderer($this->namespace);
+ break;
+ }
+
+ return $renderer;
+ }
+
+ /**
+ *
+ */
+ public function getReferenceSharedDataSet() {
+ return $this->referenceRenderer->getReferenceSharedDataSet();
+ }
+
+ /**
+ *
+ */
+ public function getReferencePrivateDataSet() {
+ return $this->referenceRenderer->getReferencePrivateDataSet();
+ }
+
+ /**
+ *
+ */
+ public function renderReference($mode, $reference) {
+ return $this->referenceRenderer->renderReference($mode, $reference);
+ }
+
+ /**
+ *
+ */
+ public function renderNotesSeparator() {
+ $html = '';
+ $style = $this->getStyle('notes-separator');
+ if ($style != 'none') {
+ if ($style != '') {
+ $style = ' style="width: '. $style . '"';
+ }
+ $html = '<hr' . $style . '>' . DOKU_LF;
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ public function renderNoteText($note) {
+ return $this->noteRenderer->renderNoteText($note);
+ }
+
+ /**
+ *
+ */
+ public function renderNote($mode, $note, $reference) {
+ return $this->noteRenderer->renderNote($mode, $note, $reference);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_renderer_data {
+
+ private $data;
+
+ /**
+ * Constructor
+ */
+ public function __construct($data) {
+ $this->data = $data;
+ }
+
+ /**
+ *
+ */
+ public function has($key) {
+ if (func_num_args() > 1) {
+ $result = false;
+
+ foreach (func_get_args() as $key) {
+ if (array_key_exists($key, $this->data)) {
+ $result = true;
+ break;
+ }
+ }
+
+ return $result;
+ }
+ else {
+ return array_key_exists($key, $this->data);
+ }
+ }
+
+ /**
+ *
+ */
+ public function get($key) {
+ if (func_num_args() > 1) {
+ $result = '';
+
+ foreach (func_get_args() as $key) {
+ if (array_key_exists($key, $this->data)) {
+ $result = $this->data[$key];
+ break;
+ }
+ }
+
+ return $result;
+ }
+ else {
+ return array_key_exists($key, $this->data) ? $this->data[$key] : '';
+ }
+ }
+
+ /**
+ *
+ */
+ public function getLongest() {
+ $result = '';
+
+ if (func_num_args() > 0) {
+ foreach (func_get_args() as $key) {
+ if (array_key_exists($key, $this->data) && (strlen($result) < strlen($this->data[$key]))) {
+ $result = $this->data[$key];
+ }
+ }
+ }
+ else {
+ foreach ($this->data as $value) {
+ if (strlen($result) < strlen($value)) {
+ $result = $value;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ public function isPositive($key)
+ {
+ static $lookup = array('y', 'yes', 'on', 'true', '1');
+
+ return in_array(strtolower($this->get($key)), $lookup);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_basic_renderer extends refnotes_renderer_base {
+
+ protected $renderedNoteId = array();
+
+ /**
+ *
+ */
+ public function getReferenceSharedDataSet() {
+ return array();
+ }
+
+ /**
+ *
+ */
+ public function getReferencePrivateDataSet() {
+ return array();
+ }
+
+ /**
+ *
+ */
+ public function renderReference($mode, $reference) {
+ if ($reference->isInline()) {
+ $doc = $this->renderInlineReference($reference);
+ }
+ else {
+ $doc = $this->renderRegularReference($mode, $reference);
+ }
+
+ return $doc;
+ }
+
+ /**
+ *
+ */
+ public function renderNoteText($note) {
+ $data = new refnotes_renderer_data($note->getData());
+
+ $text = $data->get('note-text', 'title');
+
+ if ($text == '') {
+ $text = $data->getLongest();
+ }
+
+ if ($url = $data->get('url')) {
+ $text = '[[' . $url . '|' . $text . ']]';
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ public function renderNote($mode, $note, $reference) {
+ $doc = '';
+
+ switch ($mode) {
+ case 'xhtml':
+ $doc = $this->renderNoteXhtml($note, $reference);
+ break;
+
+ case 'odt':
+ $doc = $this->renderNoteOdt($note, $reference);
+ break;
+ }
+
+ return $doc;
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteXhtml($note, $reference) {
+ $html = '<div class="' . $this->renderNoteClass() . '">' . DOKU_LF;
+ $html .= $this->renderBackReferences($note, $reference);
+ $html .= '<span id="' . $note->getAnchorName() . ':text">' . DOKU_LF;
+ $html .= $note->getText() . DOKU_LF;
+ $html .= '</span></div>' . DOKU_LF;
+
+ $this->rendered = true;
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteOdt($note, $reference) {
+ $this->rendered = true;
+
+ return '';
+ }
+
+ /**
+ *
+ */
+ protected function getInlineReferenceStyle($reference, $name, $default) {
+ return ($reference->getAttribute('use-' . $name) === false) ? $default : $this->getStyle($name);
+ }
+
+ /**
+ *
+ */
+ protected function renderInlineReference($reference) {
+ $baseStyle = $this->getInlineReferenceStyle($reference, 'reference-base', 'text');
+ $fontWeightStyle = $this->getInlineReferenceStyle($reference, 'reference-font-weight', 'normal');
+ $fontStyle = $this->getInlineReferenceStyle($reference, 'reference-font-style', 'normal');
+ $formatStyle = $this->getInlineReferenceStyle($reference, 'reference-format', 'none');
+
+ list($baseOpen, $baseClose) = $this->renderBase($baseStyle);
+ list($fontOpen, $fontClose) = $this->renderFont($fontWeightStyle, 'normal', $fontStyle);
+ list($formatOpen, $formatClose) = $this->renderFormat($formatStyle);
+
+ $html = $baseOpen . $fontOpen . $formatOpen;
+ $html .= $reference->getNote()->getText();
+ $html .= $formatClose . $fontClose . $baseClose;
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderRegularReference($mode, $reference) {
+ $doc = '';
+
+ switch ($mode) {
+ case 'xhtml':
+ $doc = $this->renderRegularReferenceXhtml($reference);
+ break;
+
+ case 'odt':
+ $doc = $this->renderRegularReferenceOdt($reference);
+ break;
+ }
+
+ return $doc;
+ }
+
+ /**
+ *
+ */
+ protected function renderRegularReferenceXhtml($reference) {
+ $noteName = $reference->getNote()->getAnchorName();
+ $referenceName = $reference->getAnchorName();
+ $class = $this->renderReferenceClass();
+
+ list($baseOpen, $baseClose) = $this->renderReferenceBase();
+ list($fontOpen, $fontClose) = $this->renderReferenceFont();
+ list($formatOpen, $formatClose) = $this->renderReferenceFormat($reference);
+
+ $html = $baseOpen . $fontOpen;
+ $html .= '<a href="#' . $noteName . '" name="' . $referenceName . '" class="' . $class . '">';
+ $html .= $formatOpen . $this->renderReferenceId($reference) . $formatClose;
+ $html .= '</a>';
+ $html .= $fontClose . $baseClose;
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderRegularReferenceOdt($reference) {
+ $xmlOdt = '';
+ $note = $reference->getNote();
+ $noteId = $note->getId();
+ $refId = $reference->getId();
+
+ // Check to see if this note has been seen before
+
+ if (array_search($noteId, $this->renderedNoteId) === false) {
+ // new note, add it to the $renderedNoteId array
+ $this->renderedNoteId[] = $noteId;
+
+ $xmlOdt .= '<text:note text:id="refnote' . $refId . '" text:note-class="footnote">';
+ $xmlOdt .= '<text:note-citation text:label="' . $refId . '">' . $refId . '</text:note-citation>';
+ $xmlOdt .= '<text:note-body>';
+ $xmlOdt .= '<text:p>' . $note->getText();
+ $xmlOdt .= '</text:p>';
+ $xmlOdt .= '</text:note-body>';
+ $xmlOdt .= '</text:note>';
+ }
+ else {
+ // Seen this one before - just reference it FIXME: style isn't correct
+ $xmlOdt = '<text:note-ref text:note-class="footnote" text:ref-name="refnote' . $noteId . '">';
+ $xmlOdt .= $refId;
+ $xmlOdt .= '</text:note-ref>';
+ }
+
+ return $xmlOdt;
+ }
+
+ /**
+ *
+ */
+ protected function renderBackReferences($note, $reference) {
+ $references = count($reference);
+ $singleReference = ($references == 1);
+ $nameAttribute = ' name="' . $note->getAnchorName() .'"';
+ $backRefFormat = $this->getStyle('back-ref-format');
+ $backRefCaret = '';
+ $html = '';
+
+ list($formatOpen, $formatClose) = $this->renderNoteIdFormat();
+
+ if (($backRefFormat != 'note') && ($backRefFormat != '')) {
+ list($baseOpen, $baseClose) = $this->renderNoteIdBase();
+ list($fontOpen, $fontClose) = $this->renderNoteIdFont();
+
+ $html .= $baseOpen . $fontOpen;
+ $html .= '<a' . $nameAttribute .' class="nolink">';
+ $html .= $formatOpen . $this->renderNoteId($note) . $formatClose;
+ $html .= '</a>';
+ $html .= $fontClose . $baseClose . DOKU_LF;
+
+ $nameAttribute = '';
+ $formatOpen = '';
+ $formatClose = '';
+ $backRefCaret = $this->renderBackRefCaret($singleReference);
+ }
+
+ if ($backRefFormat != 'none') {
+ $separator = $this->renderBackRefSeparator();
+
+ list($baseOpen, $baseClose) = $this->renderBackRefBase();
+ list($fontOpen, $fontClose) = $this->renderBackRefFont();
+
+ $html .= $baseOpen . $backRefCaret;
+
+ for ($r = 0; $r < $references; $r++) {
+ $referenceName = $reference[$r]->getAnchorName();
+
+ if ($r > 0) {
+ $html .= $separator . DOKU_LF;
+ }
+
+ $html .= $fontOpen;
+ $html .= '<a href="#' . $referenceName . '"' . $nameAttribute .' class="backref">';
+ $html .= $formatOpen . $this->renderBackRefId($reference[$r], $r, $singleReference) . $formatClose;
+ $html .= '</a>';
+ $html .= $fontClose;
+
+ $nameAttribute = '';
+ }
+
+ $html .= $baseClose . DOKU_LF;
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceClass() {
+ switch ($this->getStyle('note-preview')) {
+ case 'tooltip':
+ $result = 'refnotes-ref note-tooltip';
+ break;
+
+ case 'none':
+ $result = 'refnotes-ref';
+ break;
+
+ default:
+ $result = 'refnotes-ref note-popup';
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceBase() {
+ return $this->renderBase($this->getStyle('reference-base'));
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceFont() {
+ return $this->renderFont('reference-font-weight', 'normal', 'reference-font-style');
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceFormat($reference) {
+ $result = $this->renderFormat($this->getStyle('reference-format'));
+
+ if ($this->getReferenceGrouping($reference)) {
+ switch ($reference->getAttribute('group')) {
+ case 'open':
+ $result = array($result[0], $this->renderReferenceGroupSeparator());
+ break;
+
+ case 'hold':
+ $result = array('', $this->renderReferenceGroupSeparator());
+ break;
+
+ case 'close':
+ $result = array('', $result[1]);
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function getReferenceGrouping($reference) {
+ $group = $reference->getAttribute('group');
+ return !empty($group) && in_array($group, array('open', 'hold', 'close')) &&
+ in_array($this->getStyle('reference-group'), array(',', 's'));
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceGroupSeparator() {
+ $style = $this->getStyle('reference-group');
+ switch ($style) {
+ case ',':
+ $result = ',';
+ break;
+
+ case 's':
+ $result = ';';
+ break;
+
+ default:
+ $result = '';
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceId($reference) {
+ $idStyle = $this->getStyle('refnote-id');
+ if ($idStyle == 'name') {
+ $html = $reference->getNote()->getName();
+ }
+ else {
+ switch ($this->getStyle('multi-ref-id')) {
+ case 'note':
+ $id = $reference->getNote()->getId();
+ break;
+
+ default:
+ $id = $reference->getId();
+ break;
+ }
+
+ $html = $this->convertToStyle($id, $idStyle);
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteClass() {
+ $result = 'note';
+
+ switch ($this->getStyle('note-font-size')) {
+ case 'small':
+ $result .= ' small';
+ break;
+ }
+
+ switch ($this->getStyle('note-text-align')) {
+ case 'left':
+ $result .= ' left';
+ break;
+
+ default:
+ $result .= ' justify';
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteIdBase() {
+ return $this->renderBase($this->getStyle('note-id-base'));
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteIdFont() {
+ return $this->renderFont('note-id-font-weight', 'normal', 'note-id-font-style');
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteIdFormat() {
+ $style = $this->getStyle('note-id-format');
+ switch ($style) {
+ case '.':
+ $result = array('', '.');
+ break;
+
+ default:
+ $result = $this->renderFormat($style);
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderNoteId($note) {
+ $idStyle = $this->getStyle('refnote-id');
+ if ($idStyle == 'name') {
+ $html = $note->getName();
+ }
+ else {
+ $html = $this->convertToStyle($note->getId(), $idStyle);
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderBackRefCaret($singleReference) {
+ switch ($this->getStyle('back-ref-caret')) {
+ case 'prefix':
+ $result = '^ ';
+ break;
+
+ case 'merge':
+ $result = $singleReference ? '' : '^ ';
+ break;
+
+ default:
+ $result = '';
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderBackRefBase() {
+ return $this->renderBase($this->getStyle('back-ref-base'));
+ }
+
+ /**
+ *
+ */
+ protected function renderBackRefFont() {
+ return $this->renderFont('back-ref-font-weight', 'bold', 'back-ref-font-style');
+ }
+
+ /**
+ *
+ */
+ protected function renderBackRefSeparator() {
+ static $html = array('' => ',', 'none' => '');
+
+ $style = $this->getStyle('back-ref-separator');
+ if (!array_key_exists($style, $html)) {
+ $style = '';
+ }
+
+ return $html[$style];
+ }
+
+ /**
+ *
+ */
+ protected function renderBackRefId($reference, $index, $singleReference) {
+ $style = $this->getStyle('back-ref-format');
+ switch ($style) {
+ case 'a':
+ $result = $this->convertToLatin($index + 1, $style);
+ break;
+
+ case '1':
+ $result = $index + 1;
+ break;
+
+ case 'caret':
+ $result = '^';
+ break;
+
+ case 'arrow':
+ $result = '&uarr;';
+ break;
+
+ default:
+ $result = $this->renderReferenceId($reference);
+ break;
+ }
+
+ if ($singleReference && ($this->getStyle('back-ref-caret') == 'merge')) {
+ $result = '^';
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function renderBase($style) {
+ static $html = array(
+ '' => array('<sup>', '</sup>'),
+ 'text' => array('', '')
+ );
+
+ if (!array_key_exists($style, $html)) {
+ $style = '';
+ }
+
+ return $html[$style];
+ }
+
+ /**
+ *
+ */
+ protected function renderFont($weight, $defaultWeight, $style) {
+ list($weightOpen, $weightClose) = $this->renderFontWeight($this->getStyle($weight), $defaultWeight);
+ list($styleOpen, $styleClose) = $this->renderFontStyle($this->getStyle($style));
+
+ return array($weightOpen . $styleOpen, $styleClose . $weightClose);
+ }
+
+ /**
+ *
+ */
+ protected function renderFontWeight($style, $default) {
+ static $html = array(
+ 'normal' => array('', ''),
+ 'bold' => array('<b>', '</b>')
+ );
+
+ if (!array_key_exists($style, $html)) {
+ $style = $default;
+ }
+
+ return $html[$style];
+ }
+
+ /**
+ *
+ */
+ protected function renderFontStyle($style) {
+ static $html = array(
+ '' => array('', ''),
+ 'italic' => array('<i>', '</i>')
+ );
+
+ if (!array_key_exists($style, $html)) {
+ $style = '';
+ }
+
+ return $html[$style];
+ }
+
+ /**
+ *
+ */
+ protected function renderFormat($style) {
+ static $html = array(
+ '' => array('', ')'),
+ '()' => array('(', ')'),
+ ']' => array('', ']'),
+ '[]' => array('[', ']'),
+ 'none' => array('', '')
+ );
+
+ if (!array_key_exists($style, $html)) {
+ $style = '';
+ }
+
+ return $html[$style];
+ }
+
+ /**
+ *
+ */
+ protected function convertToStyle($id, $style) {
+ switch ($style) {
+ case 'a':
+ case 'A':
+ $result = $this->convertToLatin($id, $style);
+ break;
+
+ case 'i':
+ case 'I':
+ $result = $this->convertToRoman($id, $style);
+ break;
+
+ case '*':
+ $result = str_repeat('*', $id);
+ break;
+
+ default:
+ $result = $id;
+ break;
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function convertToLatin($number, $case) {
+ static $alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+ $result = '';
+
+ while ($number > 0) {
+ --$number;
+ $digit = $number % 26;
+ $result = $alpha[$digit] . $result;
+ $number = intval($number / 26);
+ }
+
+ if ($case == 'a') {
+ $result = strtolower($result);
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ protected function convertToRoman($number, $case) {
+ static $lookup = array(
+ 'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400,
+ 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40,
+ 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1
+ );
+
+ $result = '';
+
+ foreach ($lookup as $roman => $value) {
+ $matches = intval($number / $value);
+
+ if ($matches > 0) {
+ $result .= str_repeat($roman, $matches);
+ $number = $number % $value;
+ }
+ }
+
+ if ($case == 'i') {
+ $result = strtolower($result);
+ }
+
+ return $result;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_harvard_renderer extends refnotes_basic_renderer {
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace) {
+ parent::__construct($namespace);
+ }
+
+ /**
+ *
+ */
+ public function getReferenceSharedDataSet() {
+ static $key = array('ref-authors', 'ref-author', 'authors', 'author', 'published', 'month', 'year');
+
+ return $key;
+ }
+
+ /**
+ *
+ */
+ public function getReferencePrivateDataSet() {
+ static $key = array('direct', 'pages', 'page');
+
+ return $key;
+ }
+
+ /**
+ *
+ */
+ public function renderNoteText($note) {
+ $data = new refnotes_renderer_data($note->getData());
+
+ if (!$data->has('title')) {
+ return parent::renderNoteText($note);
+ }
+
+ // authors, published. //[[url|title.]]// edition. publisher, pages, isbn.
+ // authors, published. chapter In //[[url|title.]]// edition. publisher, pages, isbn.
+ // authors, published. [[url|title.]] //journal//, volume, publisher, pages, issn.
+ // authors, published. [[url|title.]] //booktitle//, publisher, pages, issn.
+
+ $title = $this->renderTitle($data);
+
+ // authors, published. //$title// edition. publisher, pages, isbn.
+ // authors, published. chapter In //$title// edition. publisher, pages, isbn.
+ // authors, published. $title //journal//, volume, publisher, pages, issn.
+ // authors, published. $title //booktitle//, publisher, pages, issn.
+
+ $authors = $this->renderAuthors($data);
+
+ // $authors? //$title// edition. publisher, pages, isbn.
+ // $authors? chapter In //$title// edition. publisher, pages, isbn.
+ // $authors? $title //journal//, volume, publisher, pages, issn.
+ // $authors? $title //booktitle//, publisher, pages, issn.
+
+ $publication = $this->renderPublication($data, $authors != '');
+
+ if ($data->has('journal')) {
+ // $authors? $title //journal//, volume, $publication?
+
+ $subtitle = $this->renderJournal($data);
+ }
+ elseif ($data->has('booktitle')) {
+ // $authors? $title //booktitle//, $publication?
+
+ $subtitle = $this->renderBookTitle($data);
+ }
+
+ if (!empty($subtitle)) {
+ // $authors? $title $subtitle?, $publication?
+
+ $text = $title . ' ' . $subtitle;
+
+ // $authors? $text, $publication?
+
+ $text .= ($publication != '') ? ',' : '.';
+ }
+ else {
+ // $authors? //$title// edition. $publication?
+ // $authors? chapter In //$title// edition. $publication?
+
+ $text = $this->renderBook($data, $title);
+ }
+
+ // $authors? $text $publication?
+
+ if ($authors != '') {
+ $text = $authors . ' ' . $text;
+ }
+
+ if ($publication != '') {
+ $text .= ' ' . $publication;
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderTitle($data) {
+ $text = $data->get('title') . '.';
+
+ if ($url = $data->get('url')) {
+ $text = '[[' . $url . '|' . $text . ']]';
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderAuthors($data) {
+ $text = $data->get('authors', 'author');
+
+ if ($text != '') {
+ if ($published = $this->renderPublished($data)) {
+ $text .= ', ' . $published;
+ }
+
+ $text .= '.';
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderPublished($data, $useMonth = true) {
+ $text = $data->get('published');
+
+ if ($text == '') {
+ if ($text = $data->get('year')) {
+ if ($useMonth && $month = $data->get('month')) {
+ $text = $month . ' ' . $text;
+ }
+ }
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderPublication($data, $authors) {
+ $part = array();
+
+ $address = $data->get('address');
+ $publisher = $data->get('publisher');
+
+ if ($address && $publisher) {
+ $part[] = $address . ': ' . $publisher;
+ }
+ else {
+ if ($address || $publisher) {
+ $part[] = $address . $publisher;
+ }
+ }
+
+ if (!$authors && ($published = $this->renderPublished($data))) {
+ $part[] = $published;
+ }
+
+ if ($pages = $this->renderPages($data, array('note-pages', 'note-page', 'pages', 'page'))) {
+ $part[] = $pages;
+ }
+
+ if ($isbn = $data->get('isbn')) {
+ $part[] = 'ISBN ' . $isbn;
+ }
+ elseif ($issn = $data->get('issn')) {
+ $part[] = 'ISSN ' . $issn;
+ }
+
+ $text = implode(', ', $part);
+
+ if ($text != '') {
+ $text = rtrim($text, '.') . '.';
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderPages($data, $key) {
+ $text = '';
+
+ foreach ($key as $k) {
+ if ($text = $data->get($k)) {
+ if (preg_match("/^[0-9]/", $text)) {
+ $abbr_key = (substr($k, -1) == 's') ? 'txt_pages_abbr' : 'txt_page_abbr';
+ $text = refnotes_localization::getInstance()->getLang($abbr_key) . $text;
+ }
+ break;
+ }
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderJournal($data) {
+ $text = '//' . $data->get('journal') . '//';
+
+ if ($volume = $data->get('volume')) {
+ $text .= ', ' . $volume;
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderBook($data, $title) {
+ $text = '//' . $title . '//';
+
+ if ($chapter = $data->get('chapter')) {
+ $text = $chapter . '. ' . refnotes_localization::getInstance()->getLang('txt_in_cap') . ' ' . $text;
+ }
+
+ if ($edition = $data->get('edition')) {
+ $text .= ' ' . $edition . '.';
+ }
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ protected function renderBookTitle($data) {
+ return '//' . $data->get('booktitle') . '//';
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceId($reference) {
+ $data = new refnotes_renderer_data($reference->getData());
+
+ if (!$this->checkReferenceData($data)) {
+ return $this->renderBasicReferenceId($reference);
+ }
+
+ $authors = $data->get('ref-authors', 'ref-author', 'authors', 'author');
+ $html = $this->renderReferenceExtra($data);
+
+ list($formatOpen, $formatClose) = $this->renderReferenceParentheses();
+
+ if ($data->isPositive('direct')) {
+ $html = $authors . ' ' . $formatOpen . $html . $formatClose;
+
+ if ($this->getReferenceGrouping($reference)) {
+ switch ($reference->getAttribute('group')) {
+ case 'open':
+ case 'hold':
+ $html .= $this->renderReferenceGroupSeparator();
+ break;
+ }
+ }
+ }
+ else {
+ if ($this->getReferenceGrouping($reference)) {
+ switch ($reference->getAttribute('group')) {
+ case 'open':
+ $formatClose = $this->renderReferenceGroupSeparator();
+ break;
+
+ case 'hold':
+ $formatOpen = '';
+ $formatClose = $this->renderReferenceGroupSeparator();
+ break;
+
+ case 'close':
+ $formatOpen = '';
+ break;
+ }
+ }
+
+ $html = $formatOpen . $authors . ', ' . $html . $formatClose;
+ }
+
+ return htmlspecialchars($html);
+ }
+
+ /**
+ *
+ */
+ protected function renderBasicReferenceId($reference) {
+ list($formatOpen, $formatClose) = parent::renderReferenceFormat($reference);
+
+ return $formatOpen . parent::renderReferenceId($reference) . $formatClose;
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceExtra($data) {
+ $html = '';
+
+ if ($published = $this->renderPublished($data, false)) {
+ $html .= $published;
+ }
+
+ if ($pages = $this->renderPages($data, array('page', 'pages'))) {
+ if ($html != '') {
+ $html .= ', ';
+ }
+
+ $html .= $pages;
+ }
+
+ return $html;
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceParentheses() {
+ $style = $this->getStyle('reference-format');
+ $style = (($style == '[]') || ($style == ']')) ? '[]' : '()';
+
+ return $this->renderFormat($style);
+ }
+
+ /**
+ *
+ */
+ protected function renderReferenceFormat($reference) {
+ return array('', '');
+ }
+
+ /**
+ *
+ */
+ protected function checkReferenceData($data) {
+ $authors = $data->has('ref-authors', 'ref-author', 'authors', 'author');
+ $year = $data->has('published', 'year');
+ $page = $data->has('page', 'pages');
+
+ return $authors && ($year || $page);
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/scope.php b/platform/www/lib/plugins/refnotes/scope.php
new file mode 100644
index 0000000..b955635
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/scope.php
@@ -0,0 +1,190 @@
+<?php
+
+/**
+ * Plugin RefNotes: Scope
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_scope_limits {
+ public $start;
+ public $end;
+
+ /**
+ * Constructor
+ */
+ public function __construct($start, $end = -1000) {
+ $this->start = $start;
+ $this->end = $end;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_scope_mock {
+
+ /**
+ *
+ */
+ public function getLimits() {
+ return new refnotes_scope_limits(-1, -1);
+ }
+
+ /**
+ *
+ */
+ public function isOpen() {
+ return false;
+ }
+
+ /**
+ *
+ */
+ public function getRenderer() {
+ return new refnotes_renderer_mock();
+ }
+
+ /**
+ *
+ */
+ public function getReferenceId() {
+ return 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_scope {
+
+ private $namespace;
+ private $id;
+ private $limits;
+ private $note;
+ private $notes;
+ private $references;
+
+ /**
+ * Constructor
+ */
+ public function __construct($namespace, $id, $start = -1, $end = -1000) {
+ $this->namespace = $namespace;
+ $this->id = $id;
+ $this->limits = new refnotes_scope_limits($start, $end);
+ $this->note = array();
+ $this->notes = 0;
+ $this->references = 0;
+ }
+
+ /**
+ *
+ */
+ public function getName() {
+ return $this->namespace->getName() . $this->id;
+ }
+
+ /**
+ *
+ */
+ public function getLimits() {
+ return $this->limits;
+ }
+
+ /**
+ *
+ */
+ public function isOpen() {
+ return $this->limits->end == -1000;
+ }
+
+ /**
+ *
+ */
+ public function getRenderer() {
+ return $this->namespace->getRenderer();
+ }
+
+ /**
+ *
+ */
+ public function getNoteId() {
+ return ++$this->notes;
+ }
+
+ /**
+ *
+ */
+ public function getReferenceId() {
+ return ++$this->references;
+ }
+
+ /**
+ *
+ */
+ public function addNote($note) {
+ $this->note[] = $note;
+ }
+
+ /**
+ *
+ */
+ public function rewriteReferences($limit) {
+ $block = new refnotes_note_block_iterator($this->note, $limit);
+
+ foreach ($block as $note) {
+ $note->rewriteReferences();
+ }
+ }
+
+ /**
+ *
+ */
+ public function renderNotes($mode, $limit) {
+ $minReferenceId = array();
+
+ foreach ($this->note as $note) {
+ $minReferenceId[] = $note->getMinReferenceId();
+ }
+
+ array_multisort($minReferenceId, $this->note);
+
+ $block = new refnotes_note_block_iterator($this->note, $limit);
+ $doc = '';
+
+ foreach ($block as $note) {
+ $doc .= $note->render($mode);
+ }
+
+ if ($mode == 'xhtml' && $doc != '') {
+ $open = $this->getRenderer()->renderNotesSeparator() . '<div class="notes">' . DOKU_LF;
+ $close = '</div>' . DOKU_LF;
+ $doc = $open . $doc . $close;
+ }
+
+ return $doc;
+ }
+
+ /**
+ * Finds a note given it's name or id
+ */
+ public function findNote($namespaceName, $noteName) {
+ $result = NULL;
+
+ if ($noteName != '') {
+ if (is_int($noteName)) {
+ $getter = 'getId';
+ }
+ else {
+ $getter = 'getName';
+ }
+
+ foreach ($this->note as $note) {
+ if (($note->getNamespaceName() == $namespaceName) && ($note->$getter() == $noteName)) {
+ $result = $note;
+ break;
+ }
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/script.js b/platform/www/lib/plugins/refnotes/script.js
new file mode 100644
index 0000000..79e3482
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/script.js
@@ -0,0 +1,114 @@
+(function () {
+ let floater = null;
+ let tracking = false;
+ let timer = null;
+
+ function createFloater() {
+ return jQuery('<div id="insitu__fn" />')
+ .addClass('insitu-footnote JSpopup')
+ .css({ visibility : 'hidden', left : '0px', top : '0px' })
+ .mouseleave(function () { jQuery(this).hide(); })
+ .appendTo('.dokuwiki:first');
+ }
+
+ function getFloater() {
+ if (!floater) {
+ floater = jQuery('#insitu__fn');
+ if (floater.length == 0) {
+ floater = createFloater();
+ }
+ }
+
+ return floater;
+ }
+
+ let preview = {
+ setNoteId(id) {
+ // locate the note span element
+ let note = jQuery('#' + id.replace(/:/g, '\\:') + '\\:text');
+ if (note.length == 0) {
+ return false;
+ }
+
+ // remove any element ids from the content to ensure that they remain unique
+ // and display hidden tooltip so we can move it around
+ getFloater()
+ .html(note.html().replace(/\bid\s*=\s*".*?"/gi, ''))
+ .css('visibility', 'hidden')
+ .show();
+
+ return true;
+ },
+
+ show() {
+ getFloater()
+ .css('visibility', 'visible')
+ .show();
+ },
+
+ hide() {
+ // prevent creation of the floater and re-hiding it on window.scroll()
+ if (floater && floater.is(':visible')) {
+ floater.hide();
+ }
+ },
+
+ move(event, dx, dy) {
+ getFloater().position({
+ my : 'left top',
+ of : event,
+ offset : dx + ' ' + dy,
+ collision : 'flip'
+ });
+ }
+ };
+
+ function getNoteId(event) {
+ return event.target.href.replace(/^.*?#([\w:]+)$/gi, '$1');
+ }
+
+ plugin_refnotes = {
+ popup : {
+ show(event) {
+ plugin_refnotes.tooltip.hide(event);
+ if (preview.setNoteId(getNoteId(event))) {
+ preview.move(event, 2, 2);
+ preview.show();
+ }
+ }
+ },
+
+ tooltip : {
+ show(event) {
+ plugin_refnotes.tooltip.hide(event);
+ if (preview.setNoteId(getNoteId(event))) {
+ timer = setTimeout(function () { preview.show(); }, 500);
+ tracking = true;
+ }
+ },
+
+ hide(event) {
+ if (tracking) {
+ clearTimeout(timer);
+ tracking = false;
+ }
+ preview.hide();
+ },
+
+ track(event) {
+ if (tracking) {
+ preview.move(event, 10, 12);
+ }
+ }
+ }
+ };
+})();
+
+jQuery(function () {
+ jQuery('a.refnotes-ref.note-popup').mouseenter(plugin_refnotes.popup.show);
+ jQuery('a.refnotes-ref.note-tooltip')
+ .mouseenter(plugin_refnotes.tooltip.show)
+ .mouseleave(plugin_refnotes.tooltip.hide);
+ jQuery(document).mousemove(plugin_refnotes.tooltip.track);
+ jQuery(window).scroll(plugin_refnotes.tooltip.hide);
+});
diff --git a/platform/www/lib/plugins/refnotes/style.css b/platform/www/lib/plugins/refnotes/style.css
new file mode 100644
index 0000000..1aba434
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/style.css
@@ -0,0 +1,48 @@
+div.dokuwiki a.refnotes-ref {
+}
+
+div.dokuwiki div.refnotes {
+ clear: both;
+ margin: 0 0 1em 0;
+}
+
+div.dokuwiki div.refnotes hr {
+ text-align: left;
+ margin-bottom: 0.2em;
+}
+
+div.dokuwiki div.refnotes div.notes {
+ padding-left: 1em;
+ margin-bottom: 1em;
+}
+
+div.dokuwiki div.refnotes div.note {
+ font-size: 90%;
+}
+
+div.dokuwiki div.refnotes div.note.small {
+ font-size: 70%;
+}
+
+div.dokuwiki div.refnotes div.note.justify {
+ text-align: justify;
+}
+
+div.dokuwiki div.refnotes div.note.left {
+ text-align: left;
+}
+
+div.dokuwiki div.refnotes a.nolink {
+}
+
+div.dokuwiki div.refnotes a.backref {
+}
+
+/* HACK: Fix compatibility problem with Sidebar plugin (issue 6) */
+.sidebar_inside_left div.insitu-footnote,
+.sidebar_inside_right div.insitu-footnote,
+.sidebar_outside_left div.insitu-footnote,
+.sidebar_outside_right div.insitu-footnote {
+ background: __background_other__;
+ padding: 4px;
+}
diff --git a/platform/www/lib/plugins/refnotes/syntax/notes.php b/platform/www/lib/plugins/refnotes/syntax/notes.php
new file mode 100644
index 0000000..32263ac
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/syntax/notes.php
@@ -0,0 +1,221 @@
+<?php
+
+/**
+ * Plugin RefNotes: Note renderer
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+require_once(DOKU_PLUGIN . 'refnotes/core.php');
+
+class syntax_plugin_refnotes_notes extends DokuWiki_Syntax_Plugin {
+
+ private $mode;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->mode = substr(get_class($this), 7);
+ }
+
+ /**
+ * What kind of syntax are we?
+ */
+ public function getType() {
+ return 'substition';
+ }
+
+ public function getPType() {
+ return 'block';
+ }
+
+ /**
+ * Where to sort in?
+ */
+ public function getSort() {
+ return 150;
+ }
+
+ public function connectTo($mode) {
+ $this->Lexer->addSpecialPattern('~~REFNOTES.*?~~', $mode, $this->mode);
+ $this->Lexer->addSpecialPattern('<refnotes[^>]*?\/>', $mode, $this->mode);
+ $this->Lexer->addSpecialPattern('<refnotes(?:[^>]*?[^/>])?>.*?<\/refnotes>', $mode, $this->mode);
+ }
+
+ /**
+ * Handle the match
+ */
+ public function handle($match, $state, $pos, Doku_Handler $handler) {
+ switch ($match[0]) {
+ case '~':
+ return $this->handleBasic($match);
+
+ case '<':
+ return $this->handleExtended($match);
+ }
+
+ return false;
+ }
+
+ /**
+ * Create output
+ */
+ public function render($mode, Doku_Renderer $renderer, $data) {
+ try {
+ if($mode == 'xhtml') {
+ switch ($data[0]) {
+ case 'style':
+ refnotes_renderer_core::getInstance()->styleNamespace($data[1]['ns'], $data[2]);
+ break;
+
+ case 'map':
+ refnotes_renderer_core::getInstance()->setNamespaceMapping($data[1]['ns'], $data[2]);
+ break;
+
+ case 'render':
+ $this->renderNotes($mode, $renderer, $data[1]);
+ break;
+ }
+
+ return true;
+ }
+ elseif ($mode == 'odt') {
+ switch ($data[0]) {
+ case 'render':
+ $this->renderNotes($mode, $renderer, $data[1]);
+ break;
+ }
+
+ return true;
+ }
+ }
+ catch (Exception $error) {
+ msg($error->getMessage(), -1);
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ */
+ private function handleBasic($syntax) {
+ preg_match('/~~REFNOTES(.*?)~~/', $syntax, $match);
+
+ return array('render', $this->parseAttributes($match[1]));
+ }
+
+ /**
+ *
+ */
+ private function handleExtended($syntax) {
+ preg_match('/<refnotes(.*?)(?:\/>|>(.*?)<\/refnotes>)/s', $syntax, $match);
+ $attribute = $this->parseAttributes($match[1]);
+ $style = array();
+
+ if ($match[2] != '') {
+ $style = $this->parseStyles($match[2]);
+ }
+
+ if (count($style) > 0) {
+ return array('split', $attribute, $style);
+ }
+ else {
+ return array('render', $attribute);
+ }
+ }
+
+ /**
+ *
+ */
+ private function parseAttributes($syntax) {
+ $propertyMatch = array(
+ 'ns' => '/^' . refnotes_namespace::getNamePattern('required') . '$/',
+ 'limit' => '/^\/?\d+$/'
+ );
+
+ $attribute = array();
+ $token = preg_split('/\s+/', $syntax, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($token as $t) {
+ foreach ($propertyMatch as $name => $pattern) {
+ if (preg_match($pattern, $t) == 1) {
+ $attribute[$name][] = $t;
+ break;
+ }
+ }
+ }
+
+ if (array_key_exists('ns', $attribute)) {
+ /* Ensure that namespaces are in canonic form */
+ $attribute['ns'] = array_map('refnotes_namespace::canonizeName', $attribute['ns']);
+
+ if (count($attribute['ns']) > 1) {
+ $attribute['map'] = array_slice($attribute['ns'], 1);
+ }
+
+ $attribute['ns'] = $attribute['ns'][0];
+ }
+ else {
+ $attribute['ns'] = ':';
+ }
+
+ if (array_key_exists('limit', $attribute)) {
+ $attribute['limit'] = end($attribute['limit']);
+ }
+
+ return $attribute;
+ }
+
+ /**
+ *
+ */
+ private function parseStyles($syntax) {
+ $style = array();
+ preg_match_all('/([-\w]+)\s*:[ \t]*([^\s\n;].*?)[ \t]*?(?:[\n;]|$)/', $syntax, $match, PREG_SET_ORDER);
+ foreach ($match as $m) {
+ $style[$m[1]] = $m[2];
+ }
+
+ /* Validate direct-to-html styles */
+ if (array_key_exists('notes-separator', $style)) {
+ if (preg_match('/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/', $style['notes-separator'], $match) == 1) {
+ $style['notes-separator'] = $match[0];
+ }
+ else {
+ $style['notes-separator'] = '';
+ }
+ }
+
+ /* Ensure that namespaces are in canonic form */
+ if (array_key_exists('inherit', $style)) {
+ $style['inherit'] = refnotes_namespace::canonizeName($style['inherit']);
+ }
+
+ return $style;
+ }
+
+ /**
+ *
+ */
+ private function renderNotes($mode, $renderer, $attribute) {
+ $limit = array_key_exists('limit', $attribute) ? $attribute['limit'] : '';
+ $doc = refnotes_renderer_core::getInstance()->renderNotes($mode, $attribute['ns'], $limit);
+
+ if ($doc != '') {
+ if ($mode == 'xhtml') {
+ $open = '<div class="refnotes">' . DOKU_LF;
+ $close = '</div>' . DOKU_LF;
+ }
+ else {
+ $open = '';
+ $close = '';
+ }
+
+ $renderer->doc .= $open;
+ $renderer->doc .= $doc;
+ $renderer->doc .= $close;
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/refnotes/syntax/references.php b/platform/www/lib/plugins/refnotes/syntax/references.php
new file mode 100644
index 0000000..d4f8931
--- /dev/null
+++ b/platform/www/lib/plugins/refnotes/syntax/references.php
@@ -0,0 +1,348 @@
+<?php
+
+/**
+ * Plugin RefNotes: Reference collector/renderer
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Mykola Ostrovskyy <dwpforge@gmail.com>
+ */
+
+require_once(DOKU_PLUGIN . 'refnotes/core.php');
+require_once(DOKU_PLUGIN . 'refnotes/bibtex.php');
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class syntax_plugin_refnotes_references extends DokuWiki_Syntax_Plugin {
+ use refnotes_localization_plugin;
+
+ private $mode;
+ private $entryPattern;
+ private $exitPattern;
+ private $handlePattern;
+ private $noteCapture;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ refnotes_localization::initialize($this);
+
+ $this->mode = substr(get_class($this), 7);
+ $this->noteCapture = new refnotes_note_capture();
+
+ $this->initializePatterns();
+ }
+
+ /**
+ *
+ */
+ private function initializePatterns() {
+ /* Introduces changes to achive the format. Yet not perfect but similar to Pandoc (https://pandoc.org/MANUAL.html#footnotes):
+
+ This is the text[^n01].
+
+ [^n01:] this is the note.]
+
+ */
+ if (refnotes_configuration::getSetting('replace-footnotes')) {
+ $entry = '(?:\(\(|\[\()';
+ $exit = '(?:\)\)|\)\])';
+ $id = '@@FNT\d+|#\d+';
+ }
+ else {
+ $entry = '\[\^';
+ $exit = '\]';
+ $exit2 = '\.';
+ $id = '#\d+';
+ }
+
+ $strictName = refnotes_note::getNamePattern('strict');
+ $extendedName = refnotes_note::getNamePattern('extended');
+ $namespace = refnotes_namespace::getNamePattern('optional');
+
+ $text = '.*?';
+
+ $strictName = '(?:' . $id . '|' . $strictName . ')';
+ $fullName = '\s*(?:' . $namespace . $strictName . '|:' . $namespace . $extendedName . ')\s*';
+ $lookaheadExit = '(?=' . $exit . ')';
+ $nameEntry = $fullName . $lookaheadExit;
+
+ $extendedName = '(?:' . $id . '|' . $extendedName . ')';
+ $optionalFullName = $extendedName . '?';
+ $structuredEntry = '\s*' . $optionalFullName . '\s*>>' . $text . $lookaheadExit;
+
+ $define = '\s*' . $optionalFullName . '\s*:]\s*';
+ $optionalDefine = '(?:' . $define . ')?';
+ $lookaheadExit = '(?=' . $text . $exit . ')';
+ $defineEntry = $optionalDefine . $lookaheadExit;
+
+ $this->entryPattern = $entry . '(?:' . $nameEntry . '|' . $structuredEntry . '|' . $defineEntry . ')';
+ $this->exitPattern = $exit;
+ $this->handlePattern = '/' . $entry . '\s*(' . $optionalFullName . ')\s*(?:>>(.*))?(.*)/s';
+ }
+
+
+ /**
+ * What kind of syntax are we?
+ */
+ public function getType() {
+ return 'formatting';
+ }
+
+ /**
+ * What modes are allowed within our mode?
+ */
+ public function getAllowedTypes() {
+ return array (
+ 'formatting',
+ 'substition',
+ 'protected',
+ 'disabled'
+ );
+ }
+
+ /**
+ * Where to sort in?
+ */
+ public function getSort() {
+ return 145;
+ }
+
+ public function connectTo($mode) {
+ refnotes_parser_core::getInstance()->registerLexer($this->Lexer);
+
+ $this->Lexer->addEntryPattern($this->entryPattern, $mode, $this->mode);
+ }
+
+ public function postConnect() {
+ $this->Lexer->addExitPattern($this->exitPattern, $this->mode);
+ }
+
+ /**
+ * Handle the match
+ */
+ public function handle($match, $state, $pos, Doku_Handler $handler) {
+ $result = refnotes_parser_core::getInstance()->canHandle($state);
+
+ if ($result) {
+ switch ($state) {
+ case DOKU_LEXER_ENTER:
+ $result = $this->handleEnter($match);
+ break;
+
+ case DOKU_LEXER_EXIT:
+ $result = $this->handleExit();
+ break;
+ }
+ }
+
+ if ($result === false) {
+ $handler->addCall('cdata', array($match), $pos);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Create output
+ */
+ public function render($mode, Doku_Renderer $renderer, $data) {
+ $result = false;
+
+ try {
+ switch ($mode) {
+ case 'xhtml':
+ case 'odt':
+ $result = $this->renderReferences($mode, $renderer, $data);
+ break;
+
+ case 'metadata':
+ $result = $this->renderMetadata($renderer, $data);
+ break;
+ }
+ }
+ catch (Exception $error) {
+ msg($error->getMessage(), -1);
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ */
+ private function handleEnter($syntax) {
+ if (preg_match($this->handlePattern, $syntax, $match) == 0) {
+ return false;
+ }
+
+ refnotes_parser_core::getInstance()->enterReference($match[1], $match[2]);
+
+ return array('start');
+ }
+
+ /**
+ *
+ */
+ private function handleExit() {
+ $reference = refnotes_parser_core::getInstance()->exitReference();
+
+ if ($reference->hasData()) {
+ return array('render', $reference->getAttributes(), $reference->getData());
+ }
+ else {
+ return array('render', $reference->getAttributes());
+ }
+ }
+
+ /**
+ *
+ */
+ public function renderReferences($mode, $renderer, $data) {
+ switch ($data[0]) {
+ case 'start':
+ $this->noteCapture->start($renderer);
+ break;
+
+ case 'render':
+ $this->renderReference($mode, $renderer, $data[1], (count($data) > 2) ? $data[2] : array());
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Stops renderer output capture and renders the reference link
+ */
+ private function renderReference($mode, $renderer, $attributes, $data) {
+ $reference = refnotes_renderer_core::getInstance()->addReference($attributes, $data);
+ $text = $this->noteCapture->stop();
+
+ if ($text != '') {
+ $reference->getNote()->setText($text);
+ }
+
+ $renderer->doc .= $reference->render($mode);
+ }
+
+ /**
+ *
+ */
+ public function renderMetadata($renderer, $data) {
+ if ($data[0] == 'render') {
+ $source = '';
+
+ if (array_key_exists('source', $data[1])) {
+ $source = $data[1]['source'];
+ }
+
+ if (($source != '') && ($source != '{configuration}')) {
+ $renderer->meta['plugin']['refnotes']['dbref'][wikiFN($source)] = true;
+ }
+ }
+
+ return true;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_note_capture {
+
+ private $renderer;
+ private $note;
+ private $doc;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ $this->initialize();
+ }
+
+ /**
+ *
+ */
+ private function initialize() {
+ $this->renderer = NULL;
+ $this->doc = '';
+ }
+
+ /**
+ *
+ */
+ private function resetCapture() {
+ $this->renderer->doc = '';
+ }
+
+ /**
+ *
+ */
+ public function start($renderer) {
+ $this->renderer = $renderer;
+ $this->doc = $renderer->doc;
+
+ $this->resetCapture();
+ }
+
+ /**
+ *
+ */
+ public function restart() {
+ $text = trim($this->renderer->doc);
+
+ $this->resetCapture();
+
+ return $text;
+ }
+
+ /**
+ *
+ */
+ public function stop() {
+ $text = trim($this->renderer->doc);
+
+ $this->renderer->doc = $this->doc;
+
+ $this->initialize();
+
+ return $text;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+class refnotes_nested_call_writer extends \dokuwiki\Parsing\Handler\Nest {
+
+ private $handler;
+ private $callWriterBackup;
+
+ /**
+ * Constructor
+ *
+ * HACK: Fix compatibility with PHP versions before 7.2 by passing handler as second optional
+ * argument. This makes constructor signature compatible with one defined in ReWriterInterface.
+ * Starting from PHP 7.2 this is not needed because arguments without type hint are compatible
+ * with any type since they have a wider type (any type).
+ * https://wiki.php.net/rfc/parameter-no-type-variance
+ */
+ public function __construct(\dokuwiki\Parsing\Handler\CallWriterInterface $callWriter, $handler = NULL) {
+ $this->handler = $handler;
+
+ parent::__construct($this->handler->getCallWriter());
+ }
+
+ /**
+ *
+ */
+ public function connect() {
+ $this->callWriterBackup = $this->handler->getCallWriter();
+
+ $this->handler->setCallWriter($this);
+ }
+
+ /**
+ *
+ */
+ public function disconnect() {
+ $this->handler->setCallWriter($this->callWriterBackup);
+ }
+}
diff --git a/platform/www/lib/tpl/acervus/css/basic.less b/platform/www/lib/tpl/acervus/css/basic.less
index 9bce960..2497249 100644
--- a/platform/www/lib/tpl/acervus/css/basic.less
+++ b/platform/www/lib/tpl/acervus/css/basic.less
@@ -262,7 +262,7 @@ samp,
kbd {
font-family: Consolas, "Andale Mono WT", "Andale Mono", "Bitstream Vera Sans Mono", "Nimbus Mono L", Monaco, "Courier New", monospace;
/* same font stack should be used for ".dokuwiki table.diff td" in _diff.css */
- font-size: 1em;
+ font-size: 10pt;
padding: 0 4px;
border: 1px solid @ini_border;
direction: ltr;
diff --git a/platform/www/lib/tpl/acervus/css/hacks.css b/platform/www/lib/tpl/acervus/css/hacks.css
index 3349974..9abdcdf 100644
--- a/platform/www/lib/tpl/acervus/css/hacks.css
+++ b/platform/www/lib/tpl/acervus/css/hacks.css
@@ -185,3 +185,29 @@ text-decoration:none !important;
content: counter(level1) "." counter(level2) "." counter(level3) "." counter(level4) "." counter(level5) ". ";
counter-increment: level5;
}
+
+.date {
+ float: right;
+ text-align: center;
+ margin: 1.5em;
+}
+
+.date .date-dm {
+ font-size: 19pt;
+}
+
+.date .date-y {
+ font-size: 14pt;
+ line-height: 5pt;
+}
+
+.date-frontpage {
+ margin: 0.3em;
+ opacity: 0.7;
+}
+
+.bloglist h2::before,
+.bloglist h3::before {
+ display: none !important;
+
+}
diff --git a/platform/www/lib/tpl/acervus/images/apple-touch-icon.png b/platform/www/lib/tpl/acervus/images/apple-touch-icon.png
index 73d2601..fe6efba 100644
--- a/platform/www/lib/tpl/acervus/images/apple-touch-icon.png
+++ b/platform/www/lib/tpl/acervus/images/apple-touch-icon.png
Binary files differ
diff --git a/platform/www/lib/tpl/acervus/images/favicon.ico b/platform/www/lib/tpl/acervus/images/favicon.ico
index ecbf22f..6e4ee53 100644
--- a/platform/www/lib/tpl/acervus/images/favicon.ico
+++ b/platform/www/lib/tpl/acervus/images/favicon.ico
Binary files differ
diff --git a/platform/www/lib/tpl/acervus/images/logo.png b/platform/www/lib/tpl/acervus/images/logo.png
new file mode 100644
index 0000000..24b0f48
--- /dev/null
+++ b/platform/www/lib/tpl/acervus/images/logo.png
Binary files differ
diff --git a/platform/www/lib/tpl/acervus/main.php b/platform/www/lib/tpl/acervus/main.php
index 27f35b2..20f48ab 100644
--- a/platform/www/lib/tpl/acervus/main.php
+++ b/platform/www/lib/tpl/acervus/main.php
@@ -144,6 +144,7 @@ if ($lang2 != '') {
<div class="wrapper group">
<!-- ********** CONTENT ********** -->
+
<div id="dokuwiki__content"><div class="group">
<?php tpl_flush() ?>
<?php tpl_includeFile('pageheader.html') ?>
@@ -179,6 +180,17 @@ if ($lang2 != '') {
}
+ // $id = $INFO['meta']['id'];
+ // echo 'algooo';
+ // print_r(pageinfo('id'));
+ $ns = $INFO['namespace'];
+ $creation_date = $INFO['meta']['date']['created'];
+ if (strpos($ns, 'blog') !== false) {
+ $d = strftime("%d", $creation_date);
+ $m = strftime("%m", $creation_date);
+ $y = strftime("%Y", $creation_date);
+ echo "<div class='date'><div class='date-dm'>$d/$m</div><div class='date-y'>$y</div></div>";
+ }
?>
@@ -210,7 +222,6 @@ if ($lang2 != '') {
if ($translation) echo $translation->showTranslations();
?></center>
</div><!-- /footer -->
-
<?php tpl_includeFile('footer.html') ?>
</div><!-- /wrapper -->
@@ -226,9 +237,7 @@ function getAnchor() {
}
if (document.URL.toLowerCase().indexOf("index") === -1) { // not show on index
- if (document.URL.includes(':en') ||
- document.URL.includes(':es') ||
- document.URL.includes(':fr') ||
+ if (document.URL.includes(':book') ||
document.URL.includes(':script') ||
document.URL.includes(':article')
) { // only shows number of paragraph in books, articles and scripts pages