diff --git a/composer.json b/composer.json
index 8cdec39..e4dc4a5 100644
--- a/composer.json
+++ b/composer.json
@@ -16,9 +16,10 @@
"league/plates": "~3.1",
"guzzlehttp/guzzle": "~5.3",
"league/commonmark": "^0.13",
- "symfony/console": "~2.7",
- "symfony/finder": "~2.7",
- "webuni/commonmark-table-extension": "0.4.*"
+ "symfony/console": "~3.0",
+ "symfony/finder": "~3.0",
+ "webuni/commonmark-table-extension": "0.4.*",
+ "myclabs/deep-copy": "^1.5"
},
"autoload": {
"psr-4": {
diff --git a/composer.lock b/composer.lock
index acf48fb..5fc0053 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1,10 +1,11 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "9be46791fa9d61c2ded921a54980712f",
+ "hash": "5d99c57e9efe49df55a765026a15f586",
+ "content-hash": "88197b6eaf8fc4b266eb8c72b115580a",
"packages": [
{
"name": "guzzlehttp/guzzle",
@@ -167,16 +168,16 @@
},
{
"name": "league/commonmark",
- "version": "0.13.0",
+ "version": "0.13.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
- "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484"
+ "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484",
- "reference": "a4e93bc4fd1a8ff8f534040c4a07371ea5f4b484",
+ "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/35ac362082ca983a8123df2ee2cdfcf456ab6295",
+ "reference": "35ac362082ca983a8123df2ee2cdfcf456ab6295",
"shasum": ""
},
"require": {
@@ -188,12 +189,12 @@
},
"require-dev": {
"erusev/parsedown": "~1.0",
- "jgm/commonmark": "0.24",
+ "jgm/commonmark": "0.25",
"michelf/php-markdown": "~1.4",
- "mikehaertl/php-shellcommand": "~1.1.0",
+ "mikehaertl/php-shellcommand": "~1.2.0",
"phpunit/phpunit": "~4.3|~5.0",
- "scrutinizer/ocular": "^1.1",
- "symfony/finder": "~2.3"
+ "scrutinizer/ocular": "~1.1",
+ "symfony/finder": "~2.3|~3.0"
},
"suggest": {
"league/commonmark-extras": "Library of useful extensions including smart punctuation"
@@ -220,7 +221,7 @@
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
- "homepage": "http://www.colinodell.com",
+ "homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
@@ -231,7 +232,7 @@
"markdown",
"parser"
],
- "time": "2016-01-14 04:29:54"
+ "time": "2016-03-27 19:10:13"
},
{
"name": "league/plates",
@@ -286,17 +287,59 @@
"time": "2015-07-09 02:14:40"
},
{
- "name": "react/promise",
- "version": "v2.2.1",
+ "name": "myclabs/deep-copy",
+ "version": "1.5.0",
"source": {
"type": "git",
- "url": "https://github.com/reactphp/promise.git",
- "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627"
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "e3abefcd7f106677fd352cd7c187d6c969aa9ddc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627",
- "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e3abefcd7f106677fd352cd7c187d6c969aa9ddc",
+ "reference": "e3abefcd7f106677fd352cd7c187d6c969aa9ddc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "doctrine/collections": "1.*",
+ "phpunit/phpunit": "~4.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "homepage": "https://github.com/myclabs/DeepCopy",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "time": "2015-11-07 22:20:37"
+ },
+ {
+ "name": "react/promise",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "f942da7b505d1a294284ab343d05df42d02ad6d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/f942da7b505d1a294284ab343d05df42d02ad6d9",
+ "reference": "f942da7b505d1a294284ab343d05df42d02ad6d9",
"shasum": ""
},
"require": {
@@ -327,30 +370,30 @@
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
- "time": "2015-07-03 13:48:55"
+ "time": "2016-03-31 13:10:33"
},
{
"name": "symfony/console",
- "version": "v2.8.2",
+ "version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d"
+ "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
- "reference": "d0239fb42f98dd02e7d342f793c5d2cdee0c478d",
+ "url": "https://api.github.com/repos/symfony/console/zipball/6b1175135bc2a74c08a28d89761272de8beed8cd",
+ "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd",
"shasum": ""
},
"require": {
- "php": ">=5.3.9",
+ "php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"psr/log": "~1.0",
- "symfony/event-dispatcher": "~2.1|~3.0.0",
- "symfony/process": "~2.1|~3.0.0"
+ "symfony/event-dispatcher": "~2.8|~3.0",
+ "symfony/process": "~2.8|~3.0"
},
"suggest": {
"psr/log": "For using the console logger",
@@ -360,7 +403,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.8-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -387,29 +430,29 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2016-01-14 08:33:16"
+ "time": "2016-03-16 17:00:50"
},
{
"name": "symfony/finder",
- "version": "v2.8.2",
+ "version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "c90fabdd97e431ee19b6383999cf35334dff27da"
+ "reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/c90fabdd97e431ee19b6383999cf35334dff27da",
- "reference": "c90fabdd97e431ee19b6383999cf35334dff27da",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
+ "reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
"shasum": ""
},
"require": {
- "php": ">=5.3.9"
+ "php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.8-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -436,11 +479,11 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2016-01-14 08:26:52"
+ "time": "2016-03-10 11:13:05"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.1.0",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -658,22 +701,24 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.5.0",
+ "version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7"
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7",
- "reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
+ "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0",
- "sebastian/comparator": "~1.1"
+ "sebastian/comparator": "~1.1",
+ "sebastian/recursion-context": "~1.0"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
@@ -681,7 +726,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.4.x-dev"
+ "dev-master": "1.5.x-dev"
}
},
"autoload": {
@@ -714,7 +759,7 @@
"spy",
"stub"
],
- "time": "2015-08-13 10:07:40"
+ "time": "2016-02-15 07:46:21"
},
{
"name": "phpunit/php-code-coverage",
@@ -958,16 +1003,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "4.8.21",
+ "version": "4.8.24",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "ea76b17bced0500a28098626b84eda12dbcf119c"
+ "reference": "a1066c562c52900a142a0e2bbf0582994671385e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c",
- "reference": "ea76b17bced0500a28098626b84eda12dbcf119c",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
+ "reference": "a1066c562c52900a142a0e2bbf0582994671385e",
"shasum": ""
},
"require": {
@@ -1026,7 +1071,7 @@
"testing",
"xunit"
],
- "time": "2015-12-12 07:45:58"
+ "time": "2016-03-14 06:16:08"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -1202,16 +1247,16 @@
},
{
"name": "sebastian/environment",
- "version": "1.3.3",
+ "version": "1.3.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "6e7133793a8e5a5714a551a8324337374be209df"
+ "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e7133793a8e5a5714a551a8324337374be209df",
- "reference": "6e7133793a8e5a5714a551a8324337374be209df",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
+ "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"shasum": ""
},
"require": {
@@ -1248,7 +1293,7 @@
"environment",
"hhvm"
],
- "time": "2015-12-02 08:37:27"
+ "time": "2016-02-26 18:40:46"
},
{
"name": "sebastian/exporter",
@@ -1457,16 +1502,16 @@
},
{
"name": "symfony/yaml",
- "version": "v3.0.1",
+ "version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691"
+ "reference": "0047c8366744a16de7516622c5b7355336afae96"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691",
- "reference": "3df409958a646dad2bc5046c3fb671ee24a1a691",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96",
+ "reference": "0047c8366744a16de7516622c5b7355336afae96",
"shasum": ""
},
"require": {
@@ -1502,7 +1547,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2015-12-26 13:39:53"
+ "time": "2016-03-04 07:55:57"
}
],
"aliases": [],
diff --git a/daux.phar b/daux.phar
index 9f6a55c..f49b399 100755
Binary files a/daux.phar and b/daux.phar differ
diff --git a/docs/00_Getting_Started.md b/docs/00_Getting_Started.md
index e6915e5..5f383f5 100644
--- a/docs/00_Getting_Started.md
+++ b/docs/00_Getting_Started.md
@@ -1,5 +1,7 @@
**Daux.io** is an documentation generator that uses a simple folder structure and Markdown files to create custom documentation on the fly. It helps you create great looking documentation in a developer friendly way.
+[TOC]
+
## Features
### For Authors
@@ -12,6 +14,7 @@
* [Multiple Languages Support](!Features/Multilanguage)
* [No Build Step](!Features/Live_mode)
* [Static Output Generation](!Features/Static_Site_Generation)
+* [Table of Contents](!Features/Table_of_contents)
### For Developers
@@ -34,13 +37,11 @@
This is a list of sites using Daux.io:
* [Daux.io](http://daux.io)
-* [Gltn - An open-source word processor webapp](http://felkerdigitalmedia.com/gltn/docs/)
+* [jDrupal](http://jdrupal.easystreet3.com/8/docs/)
+* [DrupalGap](http://docs.drupalgap.org/8/)
* [Invade & Annex 3 - An Arma 3 Co-operative Mission](http://ia3.ahoyworld.co.uk/)
* [Munee: Standalone PHP 5.3 Asset Optimisation & Manipulation](http://mun.ee)
* [ICADMIN: An admin panel powered by CodeIgniter.](http://istocode.com/shared/ic-admin/)
-* [TrackJs](http://docs.trackjs.com) (uses a customized theme)
-* [wallabag](http://doc.wallabag.org/index)
-* [Ultimo Docs](http://docs.ultimogroup.co.nz/)
Do you use Daux.io? Send us a pull request or open an [issue](https://github.com/justinwalsh/daux.io/issues) and I will add you to the list.
diff --git a/docs/01_Features/Search.md b/docs/01_Features/Search.md
new file mode 100644
index 0000000..5fb99e3
--- /dev/null
+++ b/docs/01_Features/Search.md
@@ -0,0 +1,13 @@
+Searching in a Daux.io documentation is possible, but only in static mode.
+
+We don't provide this feature in live rendering as it would be too slow.
+
+To enable the generated search, you can set `search` to true in the `html` section of your configuration
+
+```json
+{
+ "html": {
+ "search": true
+ }
+}
+```
diff --git a/docs/01_Features/Table_of_contents.md b/docs/01_Features/Table_of_contents.md
new file mode 100644
index 0000000..682f27f
--- /dev/null
+++ b/docs/01_Features/Table_of_contents.md
@@ -0,0 +1,19 @@
+Adding a table of contents becomes very easy with Daux.io
+
+## Automatic
+
+A table of contents can be added automatically to all pages.
+
+If `[TOC]` isn't present it will add it at the beginning of the page.
+
+You can enable this feature in your configuration
+
+```json
+{
+ "auto_toc": true
+}
+```
+
+## Manual
+
+Add `[TOC]` anywhere in your document and it will be replaced by a table of contents
diff --git a/docs/10_For_Developers/Creating_a_Processor.md b/docs/10_For_Developers/Creating_a_Processor.md
index 60f6c9e..19ed4b6 100644
--- a/docs/10_For_Developers/Creating_a_Processor.md
+++ b/docs/10_For_Developers/Creating_a_Processor.md
@@ -62,6 +62,12 @@ Two helpers from the class `Todaymade\Daux\Tree\Builder` will greatly help you d
Both methods `getOrCreateDir` and `getOrCreatePage` take two parameters : `parent` and `title`
+The page will automatically be treated as markdown and converted like a normal page.
+
+If you create a new ContentType, like let's say LaTeX, you would set the title `My Page.tex` it will keep the title `My Page` and use your renderer.
+
+If the extension is not mapped to a Generator, it will simply create the file as-is without manipulation.
+
### Extend the Markdown Generator
You can extend the Markdown Parser in any way wou want with this method.
diff --git a/docs/_index.md b/docs/_index.md
index 573719c..746f558 100644
--- a/docs/_index.md
+++ b/docs/_index.md
@@ -18,6 +18,7 @@
* [Multiple Languages Support](!Features/Multilanguage)
* [No Build Step](!Features/Live_mode)
* [Static Output Generation](!Features/Static_Site_Generation)
+* [Table of Contents](!Features/Table_of_contents)
diff --git a/generate b/generate
index face21b..0ec2d21 100755
--- a/generate
+++ b/generate
@@ -64,7 +64,14 @@ software, even if advised of the possibility of such damage.
*/
-require_once("vendor/autoload.php");
+if (file_exists('vendor/autoload.php')) {
+ require_once('vendor/autoload.php');
+} elseif (file_exists('daux.phar')) {
+ define('PHAR_DIR', __DIR__);
+ require_once("phar://" . __DIR__ . "/daux.phar/vendor/autoload.php");
+} else {
+ throw new Exception("Impossible to load Daux, missing vendor/ or daux.phar");
+}
$application = new \Todaymade\Daux\Console\Application();
$application->run();
diff --git a/global.json b/global.json
index 617e56f..78b1df6 100644
--- a/global.json
+++ b/global.json
@@ -18,6 +18,8 @@
"timezone": "America/Los_Angeles",
+ "auto_toc": false,
+
"live": {
"inherit_index": false,
"clean_urls": false
@@ -30,6 +32,7 @@
"date_modified": false,
"float": false,
"auto_landing": true,
+ "search": true,
"repo": "",
"twitter": [],
diff --git a/gulpfile.js b/gulpfile.js
index d952b7d..89401c8 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -19,9 +19,13 @@ var unusedRules = [
//We only use one glyphicon ...
".glyphicon-",
"!.glyphicon-chevron-right",
+ "!.glyphicon-search",
//we dont need all buttons
".btn-",
+ "!.btn-group",
+ "!.btn-default",
+ "!.btn-sm",
"!.btn-primary",
"!.btn-secondary",
"!.btn-hero",
diff --git a/index.php b/index.php
index 350e1f4..cbdbef6 100644
--- a/index.php
+++ b/index.php
@@ -81,7 +81,7 @@ if (file_exists('vendor/autoload.php')) {
define('PHAR_DIR', __DIR__);
require_once("phar://" . __DIR__ . "/daux.phar/vendor/autoload.php");
} else {
- throw new Exception("Impossible to load Daux, missing vendor and phar");
+ throw new Exception("Impossible to load Daux, missing vendor/ or daux.phar");
}
\Todaymade\Daux\Server\Server::serve($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], $_REQUEST);
diff --git a/libs/Console/Generate.php b/libs/Console/Generate.php
old mode 100644
new mode 100755
index 4e058c0..7ca1c1c
--- a/libs/Console/Generate.php
+++ b/libs/Console/Generate.php
@@ -20,7 +20,8 @@ class Generate extends SymfonyCommand
->addOption('processor', 'p', InputOption::VALUE_REQUIRED, 'Manipulations on the tree')
->addOption('source', 's', InputOption::VALUE_REQUIRED, 'Where to take the documentation from')
->addOption('delete', null, InputOption::VALUE_NONE, 'Delete pages not linked to a documentation page (confluence)')
- ->addOption('destination', 'd', InputOption::VALUE_REQUIRED, $description, 'static');
+ ->addOption('destination', 'd', InputOption::VALUE_REQUIRED, $description, 'static')
+ ->addOption('search', null, InputOption::VALUE_NONE, 'Generate full text search');
}
protected function execute(InputInterface $input, OutputInterface $output)
diff --git a/libs/ContentTypes/Markdown/CommonMarkConverter.php b/libs/ContentTypes/Markdown/CommonMarkConverter.php
index 140b93c..395326f 100644
--- a/libs/ContentTypes/Markdown/CommonMarkConverter.php
+++ b/libs/ContentTypes/Markdown/CommonMarkConverter.php
@@ -3,6 +3,8 @@
use League\CommonMark\DocParser;
use League\CommonMark\Environment;
use League\CommonMark\HtmlRenderer;
+use Todaymade\Daux\ContentTypes\Markdown\TOC\Parser;
+use Todaymade\Daux\ContentTypes\Markdown\TOC\TOCProcessor;
use Webuni\CommonMark\TableExtension\TableExtension;
class CommonMarkConverter extends \League\CommonMark\CommonMarkConverter
@@ -18,6 +20,10 @@ class CommonMarkConverter extends \League\CommonMark\CommonMarkConverter
$environment->mergeConfig($config);
$environment->addExtension(new TableExtension());
+ // Table of Contents
+ $environment->addBlockParser(new Parser());
+ $environment->addDocumentProcessor(new TOCProcessor($config['daux']));
+
$this->extendEnvironment($environment);
if (array_key_exists('processor_instance', $config['daux'])) {
diff --git a/libs/ContentTypes/Markdown/TOC/Element.php b/libs/ContentTypes/Markdown/TOC/Element.php
new file mode 100644
index 0000000..b8467b4
--- /dev/null
+++ b/libs/ContentTypes/Markdown/TOC/Element.php
@@ -0,0 +1,50 @@
+content = $content;
+ $this->level = $content->getLevel();
+ }
+
+ /**
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->content->data['attributes']['id'];
+ }
+
+ /**
+ * @return int
+ */
+ public function getLevel()
+ {
+ return $this->level;
+ }
+
+ /**
+ * @return Entry
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * @return Heading
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * @return Entry[]
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
+
+ /**
+ * @param Entry $parent
+ * @param bool $addChild
+ */
+ public function setParent(Entry $parent, $addChild = true)
+ {
+ $this->parent = $parent;
+ if ($addChild) {
+ $parent->addChild($this);
+ }
+ }
+
+ /**
+ * @param Entry $child
+ */
+ public function addChild(Entry $child)
+ {
+ $child->setParent($this, false);
+ $this->children[] = $child;
+ }
+
+ public function toString()
+ {
+ return $this->getLevel() . " - " . $this->getId();
+ }
+}
diff --git a/libs/ContentTypes/Markdown/TOC/Parser.php b/libs/ContentTypes/Markdown/TOC/Parser.php
new file mode 100644
index 0000000..3325546
--- /dev/null
+++ b/libs/ContentTypes/Markdown/TOC/Parser.php
@@ -0,0 +1,44 @@
+isIndented()) {
+ return false;
+ }
+
+ $previousState = $cursor->saveState();
+ $cursor->advanceToFirstNonSpace();
+ $fence = $cursor->match('/^\[TOC\]/');
+ if (is_null($fence)) {
+ $cursor->restoreState($previousState);
+
+ return false;
+ }
+
+ $context->addBlock(new Element());
+
+ return true;
+ }
+}
diff --git a/libs/ContentTypes/Markdown/TOC/RootEntry.php b/libs/ContentTypes/Markdown/TOC/RootEntry.php
new file mode 100644
index 0000000..cd2c4b5
--- /dev/null
+++ b/libs/ContentTypes/Markdown/TOC/RootEntry.php
@@ -0,0 +1,18 @@
+content = null;
+ $this->level = 0;
+ }
+
+ /**
+ * @return Entry
+ */
+ public function getParent()
+ {
+ throw new \RuntimeException("No Parent Exception");
+ }
+}
diff --git a/libs/ContentTypes/Markdown/TOC/TOCProcessor.php b/libs/ContentTypes/Markdown/TOC/TOCProcessor.php
new file mode 100644
index 0000000..2271144
--- /dev/null
+++ b/libs/ContentTypes/Markdown/TOC/TOCProcessor.php
@@ -0,0 +1,203 @@
+config = $config;
+ }
+
+ public function hasAutoTOC()
+ {
+ return array_key_exists('auto_toc', $this->config) && $this->config['auto_toc'];
+ }
+
+ /**
+ * @param Document $document
+ *
+ * @return void
+ */
+ public function processDocument(Document $document)
+ {
+ /** @var Element[] $tocs */
+ $tocs = [];
+
+ $headings = [];
+
+ $walker = $document->walker();
+ while ($event = $walker->next()) {
+ $node = $event->getNode();
+
+ if ($node instanceof Element && !$event->isEntering()) {
+ $tocs[] = $node;
+ continue;
+ }
+
+ if (!($node instanceof Heading) || !$event->isEntering()) {
+ continue;
+ }
+
+ $id = $this->addId($node);
+
+ $headings[] = new Entry($node, $id);
+ }
+
+ if (count($headings) && (count($tocs) || $this->hasAutoTOC())) {
+ $generated = $this->generate($headings);
+
+ if (count($tocs)) {
+ foreach ($tocs as $toc) {
+ $toc->replaceWith($this->render($generated->getChildren()));
+ }
+ } else {
+ $document->prependChild($this->render($generated->getChildren()));
+ }
+
+ }
+ }
+
+ protected function addId(Heading $node)
+ {
+ // If the node has an ID, no need to generate it
+ $attributes = $node->getData('attributes', []);
+ if (array_key_exists('id', $attributes) && !empty($attributes['id'])) {
+ // TODO :: check for uniqueness
+
+ return $attributes['id'];
+ }
+
+ // Well, seems we have to generate an ID
+
+ $walker = $node->walker();
+ $inside = [];
+ while ($event = $walker->next()) {
+ $insideNode = $event->getNode();
+
+ if ($insideNode instanceof Heading) {
+ continue;
+ }
+
+ $inside[] = $insideNode;
+ }
+
+ $text = '';
+ foreach ($inside as $other) {
+ if ($other instanceof Text) {
+ $text .= ' ' . $other->getContent();
+ }
+ }
+
+ $text = 'page_' . DauxHelper::slug(trim($text));
+
+ // TODO :: check for uniqueness
+ $node->data['attributes']['id'] = $text;
+ }
+
+ /**
+ * @param Entry[] $headings
+ * @return RootEntry
+ */
+ public function generate($headings)
+ {
+ /** @var Entry $previous */
+ $root = $previous = new RootEntry();
+ foreach ($headings as $heading) {
+ if ($heading->getLevel() < $previous->getLevel()) {
+ $parent = $previous;
+ do {
+ $parent = $parent->getParent();
+ } while ($heading->getLevel() <= $parent->getLevel() || $parent->getLevel() != 0);
+
+ $parent->addChild($heading);
+ $previous = $heading;
+ continue;
+ }
+
+
+ if ($heading->getLevel() > $previous->getLevel()) {
+ $previous->addChild($heading);
+ $previous = $heading;
+ continue;
+ }
+
+ //if ($heading->getLevel() == $previous->getLevel()) {
+ $previous->getParent()->addChild($heading);
+ $previous = $heading;
+ continue;
+ //}
+ }
+
+ return $root;
+ }
+
+ /**
+ * @param Entry[] $entries
+ * @return ListBlock
+ */
+ protected function render(array $entries)
+ {
+ $data = new ListData();
+ $data->type = ListBlock::TYPE_UNORDERED;
+
+ $list = new ListBlock($data);
+ $list->data['attributes']['class'] = 'TableOfContents';
+
+ foreach ($entries as $entry) {
+ $item = new ListItem($data);
+
+ $a = new Link('#' . $entry->getId());
+
+ foreach ($this->cloneChildren($entry->getContent()) as $node) {
+ $a->appendChild($node);
+ }
+
+ $p = new Paragraph();
+ $p->appendChild($a);
+
+ $item->appendChild($p);
+
+ if (!empty($entry->getChildren())) {
+ $item->appendChild($this->render($entry->getChildren()));
+ }
+
+ $list->appendChild($item);
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param Heading $node
+ * @return Node[]
+ */
+ protected function cloneChildren(Heading $node)
+ {
+ $deepCopy = new DeepCopy();
+
+ $firstClone = clone $node;
+
+ // We have no choice but to hack into the system to reset the parent, to avoid cloning the complete tree
+ $method = new ReflectionMethod(get_class($firstClone), 'setParent');
+ $method->setAccessible(true);
+ $method->invoke($firstClone, null);
+
+ return $deepCopy->copy($firstClone)->children();
+ }
+}
diff --git a/libs/Daux.php b/libs/Daux.php
index 5d480e6..11a0c19 100644
--- a/libs/Daux.php
+++ b/libs/Daux.php
@@ -306,7 +306,9 @@ class Daux
throw new \RuntimeException("Class '$class' not found. We cannot use it as a Processor");
}
- //TODO :: check that it implements processor
+ if (!array_key_exists("Todaymade\\Daux\\Processor", class_parents($class))) {
+ throw new \RuntimeException("Class '$class' invalid, should extend '\\Todaymade\\Daux\\Processor'");
+ }
return $class;
}
diff --git a/libs/Format/Base/ComputedRawPage.php b/libs/Format/Base/ComputedRawPage.php
new file mode 100644
index 0000000..b9e141e
--- /dev/null
+++ b/libs/Format/Base/ComputedRawPage.php
@@ -0,0 +1,23 @@
+raw = $content;
+ }
+
+ public function getContent()
+ {
+ return $this->raw->getContent();
+ }
+
+ public function getPureContent()
+ {
+ return $this->raw->getContent();
+ }
+}
diff --git a/libs/Format/Base/ContentPage.php b/libs/Format/Base/ContentPage.php
index 585e756..7641085 100644
--- a/libs/Format/Base/ContentPage.php
+++ b/libs/Format/Base/ContentPage.php
@@ -21,6 +21,8 @@ abstract class ContentPage extends SimplePage
*/
protected $contentType;
+ protected $generatedContent;
+
public function __construct($title, $content)
{
$this->initializePage($title, $content);
@@ -49,14 +51,18 @@ abstract class ContentPage extends SimplePage
$this->contentType = $contentType;
}
- protected function convertPage($content)
+ public function getPureContent()
{
- return $this->contentType->convert($content, $this->getFile());
+ if (!$this->generatedContent) {
+ $this->generatedContent = $this->contentType->convert($this->content, $this->getFile());
+ }
+
+ return $this->generatedContent;
}
protected function generatePage()
{
- return $this->convertPage($this->content);
+ return $this->getPureContent();
}
public static function fromFile(Content $file, $params, ContentType $contentType)
diff --git a/libs/Format/Base/Page.php b/libs/Format/Base/Page.php
index 3ee5d23..a7fd4c9 100644
--- a/libs/Format/Base/Page.php
+++ b/libs/Format/Base/Page.php
@@ -2,5 +2,17 @@
interface Page
{
+ /**
+ * Get the converted content, without any template
+ *
+ * @return string
+ */
+ public function getPureContent();
+
+ /**
+ * Get the full content
+ *
+ * @return mixed
+ */
public function getContent();
}
diff --git a/libs/Format/Base/RawPage.php b/libs/Format/Base/RawPage.php
index 3d8f8a3..bb0009e 100644
--- a/libs/Format/Base/RawPage.php
+++ b/libs/Format/Base/RawPage.php
@@ -16,6 +16,11 @@ abstract class RawPage implements Page
return $this->file;
}
+ public function getPureContent()
+ {
+ throw new Exception("you should not use this method to show a raw content");
+ }
+
public function getContent()
{
throw new Exception("you should not use this method to show a raw content");
diff --git a/libs/Format/Base/SimplePage.php b/libs/Format/Base/SimplePage.php
index 6e783a4..bc7660a 100644
--- a/libs/Format/Base/SimplePage.php
+++ b/libs/Format/Base/SimplePage.php
@@ -11,6 +11,11 @@ abstract class SimplePage implements Page
$this->initializePage($title, $content);
}
+ public function getPureContent()
+ {
+ return $this->content;
+ }
+
public function getContent()
{
if (is_null($this->generated)) {
diff --git a/libs/Format/HTML/ComputedRawPage.php b/libs/Format/HTML/ComputedRawPage.php
new file mode 100644
index 0000000..72ddfc4
--- /dev/null
+++ b/libs/Format/HTML/ComputedRawPage.php
@@ -0,0 +1,6 @@
+ filemtime($this->file->getPath()),
'markdown' => $this->content,
'request' => $params['request'],
- 'content' => $this->convertPage($this->content),
+ 'content' => $this->getPureContent(),
'breadcrumbs' => $params['html']['breadcrumbs'],
'prev' => $this->file->getPrevious(),
'next' => $this->file->getNext(),
diff --git a/libs/Format/HTML/Generator.php b/libs/Format/HTML/Generator.php
old mode 100644
new mode 100755
index d024e6e..292ed89
--- a/libs/Format/HTML/Generator.php
+++ b/libs/Format/HTML/Generator.php
@@ -9,7 +9,7 @@ use Todaymade\Daux\Daux;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Format\Base\LiveGenerator;
use Todaymade\Daux\GeneratorHelper;
-use Todaymade\Daux\Tree\Content;
+use Todaymade\Daux\Tree\ComputedRaw;
use Todaymade\Daux\Tree\Directory;
use Todaymade\Daux\Tree\Entry;
use Todaymade\Daux\Tree\Raw;
@@ -21,6 +21,8 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
/** @var Daux */
protected $daux;
+ protected $indexed_pages = [];
+
/**
* @param Daux $daux
*/
@@ -58,7 +60,61 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
);
$output->writeLn("Generating ...");
- $this->generateRecursive($this->daux->tree, $destination, $params, $output, $width);
+
+ $params['html']['search'] = $input->getOption('search');
+ $this->generateRecursive($this->daux->tree, $destination, $params, $output, $width, $params['html']['search']);
+
+ if ($params['html']['search']) {
+ GeneratorHelper::copyRecursive(
+ $this->daux->local_base . DIRECTORY_SEPARATOR . 'tipuesearch' . DIRECTORY_SEPARATOR,
+ $destination . DIRECTORY_SEPARATOR . 'tipuesearch'
+ );
+ file_put_contents(
+ $destination . DIRECTORY_SEPARATOR . 'tipuesearch' . DIRECTORY_SEPARATOR . 'tipuesearch_content.json',
+ json_encode(['pages' => $this->indexed_pages])
+ );
+ }
+
+ }
+
+ /**
+ * Remove HTML tags, including invisible text such as style and
+ * script code, and embedded objects. Add line breaks around
+ * block-level tags to prevent word joining after tag removal.
+ * Also collapse whitespace to single space and trim result.
+ * modified from: http://nadeausoftware.com/articles/2007/09/php_tip_how_strip_html_tags_web_page
+ */
+ private function strip_html_tags($text)
+ {
+ $text = preg_replace(
+ array(
+ // Remove invisible content
+ '@]*?>.*?@siu',
+ '@@siu',
+ '@@siu',
+ '@
@siu',
+ '@
@siu',
+ '@
@siu',
+ '@
]*?.*?@siu',
+ '@
@siu',
+ '@
]*?.*?@siu',
+ // Add line breaks before and after blocks
+ '@?((address)|(blockquote)|(center)|(del))@iu',
+ '@?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
+ '@?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
+ '@?((table)|(th)|(td)|(caption))@iu',
+ '@?((form)|(button)|(fieldset)|(legend)|(input))@iu',
+ '@?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
+ '@?((frameset)|(frame)|(iframe))@iu',
+ ),
+ array(
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
+ "\n\$0", "\n\$0",
+ ),
+ $text
+ );
+ return trim(preg_replace('/\s+/', ' ', strip_tags($text)));
}
/**
@@ -69,10 +125,11 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
* @param \Todaymade\Daux\Config $params
* @param OutputInterface $output
* @param integer $width
+ * @param boolean $index_pages
* @param string $base_url
* @throws \Exception
*/
- private function generateRecursive(Directory $tree, $output_dir, $params, $output, $width, $base_url = '')
+ private function generateRecursive(Directory $tree, $output_dir, $params, $output, $width, $index_pages, $base_url = '')
{
DauxHelper::rebaseConfiguration($params, $base_url);
@@ -84,7 +141,7 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
if ($node instanceof Directory) {
$new_output_dir = $output_dir . DIRECTORY_SEPARATOR . $key;
mkdir($new_output_dir);
- $this->generateRecursive($node, $new_output_dir, $params, $output, $width, '../' . $base_url);
+ $this->generateRecursive($node, $new_output_dir, $params, $output, $width, $index_pages, '../' . $base_url);
// Rebase configuration again as $params is a shared object
DauxHelper::rebaseConfiguration($params, $base_url);
@@ -93,14 +150,22 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
"- " . $node->getUrl(),
$output,
$width,
- function() use ($node, $output_dir, $key, $params) {
- if (!$node instanceof Content) {
+ function() use ($node, $output_dir, $key, $params, $index_pages) {
+ if ($node instanceof Raw) {
copy($node->getPath(), $output_dir . DIRECTORY_SEPARATOR . $key);
return;
}
$generated = $this->generateOne($node, $params);
file_put_contents($output_dir . DIRECTORY_SEPARATOR . $key, $generated->getContent());
+ if ($index_pages) {
+ $this->indexed_pages[] =[
+ 'title' => $node->getTitle(),
+ 'text' => utf8_encode($this->strip_html_tags($generated->getPureContent())),
+ 'tags' => "",
+ 'url' => $node->getUrl()
+ ];
+ }
}
);
}
@@ -118,6 +183,10 @@ class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
return new RawPage($node->getPath());
}
+ if ($node instanceof ComputedRaw) {
+ return new ComputedRawPage($node);
+ }
+
$params['request'] = $node->getUrl();
return ContentPage::fromFile($node, $params, $this->daux->getContentTypeHandler()->getType($node));
}
diff --git a/libs/Format/HTML/Template.php b/libs/Format/HTML/Template.php
index 5bb40ab..01d13b5 100644
--- a/libs/Format/HTML/Template.php
+++ b/libs/Format/HTML/Template.php
@@ -78,10 +78,13 @@ class Template
$nav = "";
foreach ($entries as $entry) {
if (array_key_exists('children', $entry)) {
+
+ $icon = '
';
+
if (array_key_exists('href', $entry)) {
- $link = '
' . $entry['title'] . '';
+ $link = '
' . $icon . $entry['title'] . '';
} else {
- $link = '
' . $entry['title'] . '';
+ $link = '
' . $icon . $entry['title'] . '';
}
$link .= $this->renderNavigation($entry['children']);
@@ -110,7 +113,7 @@ class Template
$nav[] = [
'title' => $node->getTitle(),
'href' => $base_page . $link,
- 'class' => ($current_url === $link) ? 'active' : ''
+ 'class' => $current_url === $link ? 'active' : '',
];
} elseif ($node instanceof Directory) {
if (!$node->hasContent()) {
@@ -121,7 +124,7 @@ class Template
$folder = [
'title' => $node->getTitle(),
- 'class' => (strpos($current_url, $link) === 0) ? 'open' : '',
+ 'class' => strpos($current_url, $link) === 0 ? 'open' : '',
];
if ($mode === Daux::STATIC_MODE) {
@@ -136,6 +139,10 @@ class Template
$new_path = ($path === '') ? $url : $path . '/' . $url;
$folder['children'] = $this->buildNavigation($node, $new_path, $current_url, $base_page, $mode);
+ if (!empty($folder['children'])) {
+ $folder['class'] .= ' has-children';
+ }
+
$nav[] = $folder;
}
}
diff --git a/libs/GeneratorHelper.php b/libs/GeneratorHelper.php
old mode 100644
new mode 100755
index 9e81e95..a5b99eb
--- a/libs/GeneratorHelper.php
+++ b/libs/GeneratorHelper.php
@@ -50,7 +50,7 @@ class GeneratorHelper
* @param string $source
* @param string $destination
*/
- protected static function copyRecursive($source, $destination)
+ public static function copyRecursive($source, $destination)
{
if (!is_dir($destination)) {
mkdir($destination);
diff --git a/libs/Server/ErrorPage.php b/libs/Server/ErrorPage.php
index 5311e64..1d034a3 100644
--- a/libs/Server/ErrorPage.php
+++ b/libs/Server/ErrorPage.php
@@ -33,7 +33,7 @@ class ErrorPage extends SimplePage
$params = $this->params;
$page = [
'title' => $this->title,
- 'content' => $this->content,
+ 'content' => $this->getPureContent(),
'language' => '',
];
diff --git a/libs/Server/Server.php b/libs/Server/Server.php
old mode 100644
new mode 100755
index 3440178..1d305b8
--- a/libs/Server/Server.php
+++ b/libs/Server/Server.php
@@ -99,6 +99,9 @@ class Server
$params['base_page'] .= 'index.php/';
}
+ // Text search would be too slow on live server
+ $params['html']['search'] = false;
+
return $params;
}
diff --git a/libs/Tree/Builder.php b/libs/Tree/Builder.php
index 7af752e..ed52ed4 100644
--- a/libs/Tree/Builder.php
+++ b/libs/Tree/Builder.php
@@ -169,32 +169,35 @@ class Builder
*/
public static function getOrCreatePage(Directory $parent, $path)
{
- $title = static::getName($path);
-
+ $extension = pathinfo($path, PATHINFO_EXTENSION);
// If the file doesn't have an extension, set .md as a default
- if (pathinfo($path, PATHINFO_EXTENSION) == '') {
+ if ($extension == '') {
+ $extension = 'md';
$path .= '.md';
}
- $uri = $slug = DauxHelper::slug($title);
- if ($parent->getConfig()['mode'] === Daux::STATIC_MODE) {
- $uri = $slug . ".html";
+ $raw = !in_array($extension, $parent->getConfig()['valid_content_extensions']);
+
+ $title = $uri = $path;
+ if (!$raw) {
+ $title = static::getName($path);
+ $uri = DauxHelper::slug($title);
+ if ($parent->getConfig()['mode'] === Daux::STATIC_MODE) {
+ $uri .= ".html";
+ }
}
if (array_key_exists($uri, $parent->getEntries())) {
return $parent->getEntries()[$uri];
}
- $page = new Content($parent, $uri);
+ $page = $raw? new ComputedRaw($parent, $uri) : new Content($parent, $uri);
$page->setContent("-"); //set an almost empty content to avoid problems
+ $page->setName($path);
+ $page->setTitle($title);
- if ($title == 'index') {
- // TODO :: clarify the difference between 'index' and '_index'
- $page->setName('_index.' . pathinfo($path, PATHINFO_EXTENSION));
+ if ($title == 'index' || $title == '_index') {
$page->setTitle($parent->getTitle());
- } else {
- $page->setName($path);
- $page->setTitle($title);
}
return $page;
diff --git a/libs/Tree/ComputedRaw.php b/libs/Tree/ComputedRaw.php
new file mode 100644
index 0000000..ca76319
--- /dev/null
+++ b/libs/Tree/ComputedRaw.php
@@ -0,0 +1,23 @@
+content;
+ }
+
+ /**
+ * @param string $content
+ */
+ public function setContent($content)
+ {
+ $this->content = $content;
+ }
+}
diff --git a/libs/Tree/Content.php b/libs/Tree/Content.php
index 5d29f51..77e910e 100644
--- a/libs/Tree/Content.php
+++ b/libs/Tree/Content.php
@@ -72,6 +72,10 @@ class Content extends Entry
public function isIndex()
{
+ // At some point, it was recommended that
+ // an index page starts with an underscore.
+ // This is not mandatory anymore, both with
+ // and without underscore are supported.
return $this->name == 'index' || $this->name == '_index';
}
diff --git a/package.json b/package.json
index 8e8ad37..125764e 100644
--- a/package.json
+++ b/package.json
@@ -5,12 +5,12 @@
"devDependencies": {
"grunt": "^0.4.1",
"grunt-php": "^1.0.0",
- "cssnano": "^3.4.0",
- "gulp": "^3.9.0",
- "gulp-connect-php": "^0.0.5",
+ "cssnano": "^3.5.2",
+ "gulp": "^3.9.1",
+ "gulp-connect-php": "^0.0.7",
"gulp-less": "^3.0.3",
- "gulp-plumber": "^1.0.1",
- "gulp-postcss": "^6.0.0",
+ "gulp-plumber": "^1.1.0",
+ "gulp-postcss": "^6.1.0",
"gulp-rename": "^1.2.2"
}
}
diff --git a/templates/content.php b/templates/content.php
index 07da0b2..2febe38 100644
--- a/templates/content.php
+++ b/templates/content.php
@@ -2,31 +2,17 @@
diff --git a/templates/home.php b/templates/home.php
old mode 100644
new mode 100755
index b9dc80d..b4dda1d
--- a/templates/home.php
+++ b/templates/home.php
@@ -45,7 +45,13 @@
- = $page['content']; ?>
+
+
+
+
+
+ = $page['content']; ?>
+
diff --git a/templates/layout/00_layout.php b/templates/layout/00_layout.php
old mode 100644
new mode 100755
index 2f5a4b6..868dd05
--- a/templates/layout/00_layout.php
+++ b/templates/layout/00_layout.php
@@ -23,6 +23,11 @@
echo "";
} ?>
+
+
+
+
+
@@ -39,9 +44,8 @@
}
?>
-
- = '' ?>
+
@@ -53,5 +57,23 @@
} ?>
+
+
+
+
+
+
+
+
+