Merge branch 'development' of https://github.com/justinwalsh/daux.io into development

* 'development' of https://github.com/justinwalsh/daux.io:
  Add Table Of Contents feature
  Compile latest version
  Fix floating value read
  Improve toggle usability
  Generate can fall back to daux.phar, fixes #354
  Add an arrow to open sub-trees, fixes #277
  Updates
  Finalize search feature for merge
  Add `getPureContent` to Page to be able to get content without template
  Update the list of demos
  Fix dynamic website
  First checkin of search for static websites
  Compile latest version
  Add computed raw pages, to create special content at any time
  Small tweaks
This commit is contained in:
Stéphane Goetz 2016-04-13 17:48:05 +02:00
commit fb7343c109
54 changed files with 1306 additions and 168 deletions

View File

@ -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": {

161
composer.lock generated
View File

@ -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": [],

BIN
daux.phar

Binary file not shown.

View File

@ -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.

View File

@ -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
}
}
```

View File

@ -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

View File

@ -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.

View File

@ -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)
</div>
<div class="col-sm-4">

View File

@ -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();

View File

@ -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": [],

View File

@ -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",

View File

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

3
libs/Console/Generate.php Normal file → Executable file
View File

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

View File

@ -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'])) {

View File

@ -0,0 +1,50 @@
<?php namespace Todaymade\Daux\ContentTypes\Markdown\TOC;
use League\CommonMark\Block\Element\AbstractBlock;
use League\CommonMark\Cursor;
class Element extends AbstractBlock
{
/**
* Returns true if this block can contain the given block as a child node
*
* @param AbstractBlock $block
*
* @return bool
*/
public function canContain(AbstractBlock $block)
{
return false;
}
/**
* Returns true if block type can accept lines of text
*
* @return bool
*/
public function acceptsLines()
{
return false;
}
/**
* Whether this is a code block
*
* @return bool
*/
public function isCode()
{
return false;
}
/**
* @param Cursor $cursor
*
* @return bool
*/
public function matchesNextLine(Cursor $cursor)
{
return false;
}
}

View File

@ -0,0 +1,83 @@
<?php namespace Todaymade\Daux\ContentTypes\Markdown\TOC;
use League\CommonMark\Block\Element\Heading;
class Entry
{
protected $content;
protected $level;
protected $parent = null;
protected $children = [];
public function __construct(Heading $content)
{
$this->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();
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: onigoetz
* Date: 09/04/16
* Time: 23:03
*/
namespace Todaymade\Daux\ContentTypes\Markdown\TOC;
use League\CommonMark\Block\Parser\AbstractBlockParser;
use League\CommonMark\ContextInterface;
use League\CommonMark\Cursor;
class Parser extends AbstractBlockParser
{
/**
* @param ContextInterface $context
* @param Cursor $cursor
*
* @return bool
*/
public function parse(ContextInterface $context, Cursor $cursor)
{
if ($cursor->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;
}
}

View File

@ -0,0 +1,18 @@
<?php namespace Todaymade\Daux\ContentTypes\Markdown\TOC;
class RootEntry extends Entry
{
public function __construct()
{
$this->content = null;
$this->level = 0;
}
/**
* @return Entry
*/
public function getParent()
{
throw new \RuntimeException("No Parent Exception");
}
}

View File

@ -0,0 +1,203 @@
<?php namespace Todaymade\Daux\ContentTypes\Markdown\TOC;
use DeepCopy\DeepCopy;
use League\CommonMark\Block\Element\Document;
use League\CommonMark\Block\Element\Heading;
use League\CommonMark\Block\Element\ListBlock;
use League\CommonMark\Block\Element\ListData;
use League\CommonMark\Block\Element\ListItem;
use League\CommonMark\Block\Element\Paragraph;
use League\CommonMark\DocumentProcessorInterface;
use League\CommonMark\Inline\Element\Link;
use League\CommonMark\Inline\Element\Text;
use League\CommonMark\Node\Node;
use ReflectionMethod;
use Todaymade\Daux\Config;
use Todaymade\Daux\DauxHelper;
class TOCProcessor implements DocumentProcessorInterface
{
protected $config;
public function __construct(Config $config)
{
$this->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();
}
}

View File

@ -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;
}

View File

@ -0,0 +1,23 @@
<?php namespace Todaymade\Daux\Format\Base;
use Todaymade\Daux\Tree\ComputedRaw;
abstract class ComputedRawPage implements Page
{
protected $raw;
public function __construct(ComputedRaw $content)
{
$this->raw = $content;
}
public function getContent()
{
return $this->raw->getContent();
}
public function getPureContent()
{
return $this->raw->getContent();
}
}

View File

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

View File

@ -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();
}

View File

@ -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");

View File

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

View File

@ -0,0 +1,6 @@
<?php namespace Todaymade\Daux\Format\HTML;
class ComputedRawPage extends \Todaymade\Daux\Format\Base\ComputedRawPage
{
}

View File

@ -81,7 +81,7 @@ class ContentPage extends \Todaymade\Daux\Format\Base\ContentPage
'modified_time' => 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(),

81
libs/Format/HTML/Generator.php Normal file → Executable file
View File

@ -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
'@<head[^>]*?>.*?</head>@siu',
'@<style[^>]*?>.*?</style>@siu',
'@<script[^>]*?.*?</script>@siu',
'@<object[^>]*?.*?</object>@siu',
'@<embed[^>]*?.*?</embed>@siu',
'@<applet[^>]*?.*?</applet>@siu',
'@<noframes[^>]*?.*?</noframes>@siu',
'@<noscript[^>]*?.*?</noscript>@siu',
'@<noembed[^>]*?.*?</noembed>@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));
}

View File

@ -78,10 +78,13 @@ class Template
$nav = "";
foreach ($entries as $entry) {
if (array_key_exists('children', $entry)) {
$icon = '<i class="arrow">&nbsp;</i>';
if (array_key_exists('href', $entry)) {
$link = '<a href="' . $entry['href'] . '" class="folder">' . $entry['title'] . '</a>';
$link = '<a href="' . $entry['href'] . '" class="folder">' . $icon . $entry['title'] . '</a>';
} else {
$link = '<a href="#" class="aj-nav folder">' . $entry['title'] . '</a>';
$link = '<a href="#" class="aj-nav folder">' . $icon . $entry['title'] . '</a>';
}
$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;
}
}

2
libs/GeneratorHelper.php Normal file → Executable file
View File

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

View File

@ -33,7 +33,7 @@ class ErrorPage extends SimplePage
$params = $this->params;
$page = [
'title' => $this->title,
'content' => $this->content,
'content' => $this->getPureContent(),
'language' => '',
];

3
libs/Server/Server.php Normal file → Executable file
View File

@ -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;
}

View File

@ -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);
$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 = $slug . ".html";
$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
if ($title == 'index') {
// TODO :: clarify the difference between 'index' and '_index'
$page->setName('_index.' . pathinfo($path, PATHINFO_EXTENSION));
$page->setTitle($parent->getTitle());
} else {
$page->setName($path);
$page->setTitle($title);
if ($title == 'index' || $title == '_index') {
$page->setTitle($parent->getTitle());
}
return $page;

23
libs/Tree/ComputedRaw.php Normal file
View File

@ -0,0 +1,23 @@
<?php namespace Todaymade\Daux\Tree;
class ComputedRaw extends Entry
{
/** @var string */
protected $content;
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @param string $content
*/
public function setContent($content)
{
$this->content = $content;
}
}

View File

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

View File

@ -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"
}
}

View File

@ -2,14 +2,7 @@
<article>
<?php if ($params['html']['date_modified']) { ?>
<div class="page-header sub-header clearfix">
<h1><?php
if ($page['breadcrumbs']) {
echo $this->get_breadcrumb_title($page, $base_page);
} else {
echo $page['title'];
}
?>
</h1>
<h1><?= $page['breadcrumbs']? $this->get_breadcrumb_title($page, $base_page) : $page['title'] ?></h1>
<span style="float: left; font-size: 10px; color: gray;">
<?= date("l, F j, Y", $page['modified_time']); ?>
</span>
@ -19,14 +12,7 @@
</div>
<?php } else { ?>
<div class="page-header">
<h1><?php
if ($page['breadcrumbs']) {
echo $this->get_breadcrumb_title($page, $base_page);
} else {
echo $page['title'];
}
?>
</h1>
<h1><?= $page['breadcrumbs']? $this->get_breadcrumb_title($page, $base_page) : $page['title'] ?></h1>
</div>
<?php } ?>

6
templates/home.php Normal file → Executable file
View File

@ -45,11 +45,17 @@
<div class="container">
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
<?php if ($params['html']['search']) { ?>
<div id="tipue_search_content" style="display:none"></div>
<?php } ?>
<div class="doc_content">
<?= $page['content']; ?>
</div>
</div>
</div>
</div>
</div>
<div class="homepage-footer container-fluid">
<div class="container">

26
templates/layout/00_layout.php Normal file → Executable file
View File

@ -23,6 +23,11 @@
echo "<link href='$css' rel='stylesheet' type='text/css'>";
} ?>
<?php if ($params['html']['search']) { ?>
<!-- Tipue Search -->
<link href="<?= $base_url; ?>tipuesearch/tipuesearch.css" rel="stylesheet">
<?php } ?>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
@ -39,9 +44,8 @@
}
?>
<!-- jQuery -->
<?= '<script src="' . $base_url . 'themes/daux/js/jquery-1.11.3.min.js' . '"></script>' ?>
<script src="<?= $base_url; ?>themes/daux/js/jquery-1.11.3.min.js"></script>
<!-- hightlight.js -->
<script src="<?= $base_url; ?>themes/daux/js/highlight.pack.js"></script>
@ -53,5 +57,23 @@
} ?>
<script src="<?= $base_url; ?>themes/daux/js/daux.js"></script>
<?php if ($params['html']['search']) { ?>
<!-- Tipue Search -->
<script type="text/javascript" src="<?php echo $base_url; ?>tipuesearch/tipuesearch_set.js"></script>
<script type="text/javascript" src="<?php echo $base_url; ?>tipuesearch/tipuesearch.min.js"></script>
<script>
window.onunload = function(){}; // force $(document).ready to be called on back/forward navigation in firefox
$(document).ready(function() {
$('#tipue_search_input').tipuesearch({
'show': 10,
'mode': 'json',
'base_url': '<?php echo $base_url?>'
});
});
</script>
<?php } ?>
</body>
</html>

28
templates/layout/05_page.php Normal file → Executable file
View File

@ -37,11 +37,21 @@
<?php
foreach ($params['html']['links'] as $name => $url) {
echo '<a href="' . $url . '" target="_blank">' . $name . '</a><br>';
}
if ($params['html']['toggle_code']) {
echo '<a href="#" id="toggleCodeBlockBtn" onclick="toggleCodeBlocks();">Show Code Blocks Inline</a><br>';
}
?>
} ?>
<div id="toggleCodeBlock">
<?php if ($params['html']['toggle_code'] && $params['html']['float']) { ?>
<br />
<span class="code-buttons-text">Code blocks</span>
<div class="btn-group" role="group">
<button id="code-hide" class="btn btn-sm btn-default">No</button>
<button id="code-below" class="btn btn-sm btn-default">Below</button>
<button id="code-float" class="btn btn-sm btn-default">Inline</button>
</div>
<?php } else if ($params['html']['toggle_code']) { ?>
<a id="toggleCodeBlockBtn" href="#" onclick="toggleCodeBlocks();">Show Code Blocks Inline</a><br>
<?php } ?>
</div>
<!-- Twitter -->
<?php foreach ($params['html']['twitter'] as $handle) { ?>
@ -54,14 +64,20 @@
<hr/>
<?php } ?>
<p><small>Documentation generated by <a href="http://daux.io">Daux.io</a></small></p>
</div>
</div>
</div>
<div class="right-column <?= $params['html']['float'] ? 'float-view' : ''; ?> content-area col-sm-9">
<div class="content-page">
<?php if ($params['html']['search']) { ?>
<div id="tipue_search_content" style="display:none"></div>
<?php } ?>
<div class="doc_content">
<?= $this->section('content'); ?>
</div>
</div>
</div>
</div>
</div>

7
templates/partials/navbar_content.php Normal file → Executable file
View File

@ -1 +1,8 @@
<a class="brand navbar-brand pull-left" href="<?= $params['base_page'] . $params['index']->getUri(); ?>"><?= $params['title']; ?></a>
<?php if ($params['html']['search']) { ?>
<div class="navbar-right navbar-form search">
<i class="glyphicon glyphicon-search search__icon">&nbsp;</i>
<input type="search" id="tipue_search_input" class="form-control search__field" placeholder="Search..." autocomplete="on" results=25 autosave=text_search>
</div>
<?php } ?>

View File

@ -1,6 +1,9 @@
<?php namespace Todaymade\Daux\Tree;
use Todaymade\Daux\Config;
use Todaymade\Daux\Daux;
class BuilderTest extends \PHPUnit_Framework_TestCase
{
public function providerRemoveSorting()
@ -34,4 +37,104 @@ class BuilderTest extends \PHPUnit_Framework_TestCase
{
$this->assertEquals($expected, Builder::removeSortingInformations($value));
}
public function testGetOrCreateDirNew() {
$root = new Root(new Config(), '');
$dir = Builder::getOrCreateDir($root, 'directory');
$this->assertSame($root, $dir->getParent());
$this->assertEquals('directory', $dir->getTitle());
$this->assertEquals('directory', $dir->getUri());
}
public function testGetOrCreateDirExisting() {
$root = new Root(new Config(), '');
$directory = new Directory($root, 'directory');
$directory->setTitle('directory');
$dir = Builder::getOrCreateDir($root, 'directory');
$this->assertSame($root, $dir->getParent());
$this->assertEquals('directory', $dir->getTitle());
$this->assertEquals('directory', $dir->getUri());
$this->assertSame($directory, $dir);
}
public function getStaticRoot() {
$config = new Config();
$config['mode'] = Daux::STATIC_MODE;
$config['index_key'] = 'index.html';
$config['valid_content_extensions'] = ['md'];
return new Root($config, '');
}
public function testGetOrCreatePage()
{
$directory = new Directory($this->getStaticRoot(), 'dir');
$entry = Builder::getOrCreatePage($directory, 'A Page.md');
$this->assertSame($directory, $entry->getParent());
$this->assertEquals('dir/A_Page.html', $entry->getUrl());
$this->assertEquals('A_Page.html', $entry->getUri());
$this->assertEquals('A Page', $entry->getTitle());
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
}
public function testGetOrCreatePageAutoMarkdown()
{
$directory = new Directory($this->getStaticRoot(), 'dir');
$entry = Builder::getOrCreatePage($directory, 'A Page');
$this->assertSame($directory, $entry->getParent());
$this->assertEquals('dir/A_Page.html', $entry->getUrl());
$this->assertEquals('A_Page.html', $entry->getUri());
$this->assertEquals('A Page', $entry->getTitle());
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
}
public function testGetOrCreateIndexPage()
{
$directory = new Directory($this->getStaticRoot(), 'dir');
$directory->setTitle('Tutorials');
$entry = Builder::getOrCreatePage($directory, 'index.md');
$this->assertSame($directory, $entry->getParent());
$this->assertEquals('dir/index.html', $entry->getUrl());
$this->assertEquals('Tutorials', $entry->getTitle());
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
}
public function testGetOrCreatePageExisting()
{
$directory = new Directory($this->getStaticRoot(), 'dir');
$existingEntry = new Content($directory, 'A_Page.html');
$existingEntry->setContent('-');
$entry = Builder::getOrCreatePage($directory, 'A Page.md');
$this->assertSame($directory, $entry->getParent());
$this->assertSame($existingEntry, $entry);
$this->assertEquals('dir/A_Page.html', $entry->getUrl());
$this->assertEquals('A_Page.html', $entry->getUri());
$this->assertInstanceOf('Todaymade\Daux\Tree\Content', $entry);
}
public function testGetOrCreateRawPage()
{
$directory = new Directory($this->getStaticRoot(), 'dir');
$entry = Builder::getOrCreatePage($directory, 'file.json');
$this->assertSame($directory, $entry->getParent());
$this->assertEquals('dir/file.json', $entry->getUrl());
$this->assertEquals('file.json', $entry->getUri());
$this->assertInstanceOf('Todaymade\Daux\Tree\ComputedRaw', $entry);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -37,16 +37,15 @@ _.debounce = function(func, wait, immediate) {
};
};
var codeBlocks, codeBlockView, toggleCodeBlockBtn, codeBlockState;
var codeBlocks, codeBlockView, toggleCodeBlockBtn, toggleCodeSection, codeBlockState;
function toggleCodeBlocks() {
var hasFloat = $(document.body).hasClass("with-float")? 3 : 2;
codeBlockState = (codeBlockState + 1) % hasFloat;
localStorage.setItem("codeBlockState", codeBlockState);
setCodeBlockStyle(codeBlockState);
setCodeBlockStyle(codeBlocks.hasClass('hidden') ? 1 : 0);
}
function setCodeBlockStyle(x) {
switch (x) {
function setCodeBlockStyle(codeBlockState) {
localStorage.setItem("codeBlockState", codeBlockState);
switch (codeBlockState) {
default:
case 0:
toggleCodeBlockBtn.html("Show Code Blocks");
@ -69,22 +68,35 @@ function setCodeBlockStyle(x) {
//Initialize CodeBlock Visibility Settings
$(function () {
codeBlocks = $('.content-page article > pre');
toggleCodeSection = $('#toggleCodeBlock');
toggleCodeBlockBtn = $('#toggleCodeBlockBtn');
// If there is no code block we hide the link
if (!codeBlocks.size()) {
toggleCodeBlockBtn.addClass('hidden');
toggleCodeSection.addClass('hidden');
return;
}
$('#code-hide').click(function() { setCodeBlockStyle(0); });
$('#code-below').click(function() { setCodeBlockStyle(1); });
$('#code-float').click(function() { setCodeBlockStyle(2); });
codeBlockView = $('.right-column');
if (!codeBlockView.size()) return;
var floating = $(document.body).hasClass("with-float");
codeBlockState = localStorage.getItem("codeBlockState");
if (!codeBlockState) {
codeBlockState = 2;
localStorage.setItem("codeBlockState", codeBlockState);
} else codeBlockState = parseInt(codeBlockState);
codeBlockState = floating? 2 : 1;
} else {
codeBlockState = parseInt(codeBlockState);
}
if (!floating && codeBlockState == 2) {
codeBlockState = 1;
}
setCodeBlockStyle(codeBlockState);
});
@ -98,6 +110,12 @@ $(function () {
$(this).next().slideToggle();
});
// New Tree navigation
$('ul.nav.nav-list > li.has-children > a > .arrow').click(function() {
$(this).parent().parent().toggleClass('open');
return false;
});
// Responsive navigation
$('#menu-spinner-button').click(function () {
$('#sub-nav-collapse').slideToggle();

View File

@ -19,13 +19,13 @@
@import "code.less";
@import "grid.less";
//@import "tables.less";
//@import "forms.less";
@import "forms.less";
@import "buttons.less";
// Components
//@import "component-animations.less";
//@import "dropdowns.less";
//@import "button-groups.less";
@import "button-groups.less";
//@import "input-groups.less";
@import "navs.less";
@import "navbar.less";

View File

@ -284,8 +284,7 @@
// Extension of the `.form-inline` with some extra flavor for optimum display in
// our navbars.
//DAUX.io / onigoetz; removed so we can safely remove forms.less
/*.navbar-form {
.navbar-form {
margin-left: -@navbar-padding-horizontal;
margin-right: -@navbar-padding-horizontal;
padding: 10px @navbar-padding-horizontal;
@ -320,7 +319,7 @@
padding-bottom: 0;
.box-shadow(none);
}
}*/
}
// Dropdown menus

View File

@ -68,21 +68,54 @@ code {
}
}
.code-buttons-text {
font-size: 12px;
line-height: 1.5;
padding: 6px 10px 6px 0;
display: inline-block;
vertical-align: middle;
}
//Sidebar Nav List
.nav.nav-list {
padding-left: 0px;
padding-right: 0px;
padding-left: 0;
padding-right: 0;
li {
a {
margin: 0px;
padding: 6px 15px;
margin: 0;
padding: 6px 15px 6px 20px;
.roboto-slab.regular;
color: @dark;
font-size: 15px;
text-shadow: none;
border-color: @lines;
.arrow {
display: inline-block;
position: relative;
width: 16px;
margin-left: -16px;
&:before {
position:absolute;
display:block;
content:"";
margin:-.25em 0 0 -.4em;
left:50%;
top: 50%;
width: 0.5em;
height: 0.5em;
border-right: 0.15em solid @dark;
border-top: 0.15em solid @dark;
transform: rotate(45deg);
transition-duration:.3s;
}
}
&:hover {
color: @dark;
text-shadow: none;
@ -100,11 +133,16 @@ code {
> ul {
display: block;
}
> a {
&, &:focus, &:hover {
background-color:transparent;
}
&:last-child {
&.open {
//border-bottom: none;
> .arrow:before {
margin-left:-.25em;
transform: rotate(135deg);
}
}
}
@ -128,15 +166,13 @@ code {
}
}
&.active {
a {
&.active a {
color: @dark;
}
}
}
}
}
}
.page-header {
margin: 10px 0px;
@ -325,3 +361,34 @@ table {
}
}
}
.search {
position: relative;
&__field {
padding-right: 30px;
}
&__icon {
position: absolute;
right: 12px;
top: 10px;
}
}
.TableOfContents {
font-size:16px;
padding-left:30px;
border-left:6px solid #efefef;
p {
margin-bottom:0;
}
.TableOfContents {
border-left-width:0;
padding-left:20px;
}
}

206
tipuesearch/tipuesearch.css Executable file
View File

@ -0,0 +1,206 @@
/*
Tipue Search 5.0
Copyright (c) 2015 Tipue
Tipue Search is released under the MIT License
http://www.tipue.com/search
*/
/* bootstrap overrides the search field so let's undo that */
input[type="search"] {
-webkit-appearance: searchfield;
}
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: searchfield-cancel-button;
}
#tipue_search_input {
width: 170px;
font-size: medium;
}
#tipue_search_content {
background: #fff;
max-width: 650px;
padding: 15px;
margin: 0;
}
#tipue_search_warning {
font-weight:300;
font-size:15px;
line-height: 1.6;
color: #555;
margin: 7px 0;
}
#tipue_search_warning a {
color: #396;
text-decoration: none;
}
#tipue_search_warning a:hover {
color: #555;
}
#tipue_search_results_count {
font-weight:300;
font-size:15px;
line-height: 1.7;
color: #555;
}
.tipue_search_content_title {
font-weight:300;
font-size:21px;
line-height: 1.7;
margin-top: 23px;
}
.tipue_search_content_title a {
color: #333;
text-decoration: none;
}
.tipue_search_content_title a:hover {
color: #555;
}
.tipue_search_content_url {
font-weight:300;
font-size:14px;
line-height: 1.9;
word-wrap: break-word;
hyphens: auto;
}
.tipue_search_content_url a {
color: #396;
text-decoration: none;
}
.tipue_search_content_url a:hover {
color: #555;
}
.tipue_search_content_text {
font-weight:300;
font-size:15px;
line-height: 1.6;
color: #555;
word-wrap: break-word;
hyphens: auto;
margin-top: 3px;
}
.tipue_search_content_debug {
font-weight:300;
font-size:13px;
line-height: 1.6;
color: #555;
margin: 5px 0;
}
.h01 {
color: #333;
font-weight: 400;
}
#tipue_search_foot {
margin: 51px 0 21px 0;
padding: 0 10px;
}
#tipue_search_foot_boxes {
padding: 0;
margin: 0;
font-size: 12px;
width: auto;
float: none;
}
#tipue_search_foot_boxes li {
list-style: none;
margin: 0;
padding: 0;
display: inline;
}
#tipue_search_foot_boxes li a {
padding: 10px 17px 11px 17px;
background-color: #fff;
border: 1px solid #e2e2e2;
border-radius: 1px;
color: #333;
margin-right: 7px;
text-decoration: none;
text-align: center;
}
#tipue_search_foot_boxes li.current {
padding: 10px 17px 11px 17px;
background: #f6f6f6;
border: 1px solid #e2e2e2;
border-radius: 1px;
color: #333;
margin-right: 7px;
text-align: center;
}
#tipue_search_foot_boxes li a:hover {
background: #f6f6f6;
}
/* spinner */
.tipue_search_spinner {
padding: 31px 0;
width: 50px;
height: 28px;
}
.tipue_search_spinner > div {
background-color: #777;
height: 100%;
width: 3px;
display: inline-block;
margin-right: 2px;
-webkit-animation: stretchdelay 1.2s infinite ease-in-out;
animation: stretchdelay 1.2s infinite ease-in-out;
}
.tipue_search_spinner .tipue_search_rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.tipue_search_spinner .tipue_search_rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
@-webkit-keyframes stretchdelay {
0%, 40%, 100% {
-webkit-transform: scaleY(0.4)
}
20% {
-webkit-transform: scaleY(1.0)
}
}
@keyframes stretchdelay {
0%, 40%, 100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}

1
tipuesearch/tipuesearch.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,34 @@
/*
Tipue Search 5.0
Copyright (c) 2015 Tipue
Tipue Search is released under the MIT License
http://www.tipue.com/search
*/
// Stop words (list from http://www.ranks.nl/stopwords)
var tipuesearch_stop_words = ["a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "aren't", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by", "can't", "cannot", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "don't", "down", "during", "each", "few", "for", "from", "further", "had", "hadn't", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him", "himself", "his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "isn't", "it", "it's", "its", "itself", "let's", "me", "more", "most", "mustn't", "my", "myself", "no", "nor", "not", "of", "off", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", "same", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "so", "some", "such", "than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's", "these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "to", "too", "under", "until", "up", "very", "was", "wasn't", "we", "we'd", "we'll", "we're", "we've", "were", "weren't", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's", "whom", "why", "why's", "with", "won't", "would", "wouldn't", "you", "you'd", "you'll", "you're", "you've", "your", "yours", "yourself", "yourselves"];
// Word replace
var tipuesearch_replace = {'words': []};
// Weighting
var tipuesearch_weight = {'weight': []};
// Stemming
var tipuesearch_stem = {'words': []};
// Internal strings
var tipuesearch_string_1 = 'No title';
var tipuesearch_string_2 = 'Showing results for';
var tipuesearch_string_3 = 'Search instead for';
var tipuesearch_string_4 = '1 result';
var tipuesearch_string_5 = 'results';
var tipuesearch_string_6 = 'Prev';
var tipuesearch_string_7 = 'Next';
var tipuesearch_string_8 = 'Nothing found';
var tipuesearch_string_9 = 'Common words are largely ignored';
var tipuesearch_string_10 = 'Search too short';
var tipuesearch_string_11 = 'Should be one character or more';
var tipuesearch_string_12 = 'Should be';
var tipuesearch_string_13 = 'characters or more';