Merge pull request #273 from onigoetz/master

Big reorganisation
This commit is contained in:
Stéphane Goetz 2015-07-21 10:30:01 +02:00
commit c6d6634857
206 changed files with 4743 additions and 3899 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ node_modules
.DS_Store .DS_Store
/sftp-config.json /sftp-config.json
static static
vendor

View File

@ -3,4 +3,4 @@ RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(gif|jpg|png|css|js|html|ico|zip|rar|pdf|xml|mp4|mpg|flv|swf|mkv|ogg|avi|woff|svg|eot|ttf|jar)$ index.php [L,QSA] RewriteRule . index.php [L,QSA]

View File

@ -11,7 +11,8 @@ module.exports = function (grunt) {
options: { options: {
keepalive: true, keepalive: true,
open: true, open: true,
port: 8085 port: 8085,
router: "index.php"
} }
} }
}, },
@ -22,16 +23,16 @@ module.exports = function (grunt) {
report: 'min' report: 'min'
}, },
files: { files: {
"css/daux-blue.min.css": "less/daux-blue.less", "resources/themes/daux-blue/css/theme.min.css": "resources/themes/daux-blue/less/theme.less",
"css/daux-green.min.css": "less/daux-green.less", "resources/themes/daux-green/css/theme.min.css": "resources/themes/daux-green/less/theme.less",
"css/daux-navy.min.css": "less/daux-navy.less", "resources/themes/daux-navy/css/theme.min.css": "resources/themes/daux-navy/less/theme.less",
"css/daux-red.min.css": "less/daux-red.less" "resources/themes/daux-red/css/theme.min.css": "resources/themes/daux-red/less/theme.less"
} }
} }
}, },
watch: { watch: {
scripts: { scripts: {
files: ['less/**/*.less'], files: ['templates/default/theme/**/*.less'],
tasks: ['less'], tasks: ['less'],
options: { options: {
nospawn: true nospawn: true

View File

@ -74,7 +74,7 @@ If you want to create a beautiful landing page for your project, simply create a
{ {
"title": "Daux.io", "title": "Daux.io",
"tagline": "The Easiest Way To Document Your Project", "tagline": "The Easiest Way To Document Your Project",
"image": "<base_url>img/app.png" "image": "app.png"
} }
``` ```
@ -170,17 +170,6 @@ Include custom links in the sidebar.
} }
``` ```
###File editor:
![File editor](https://f.cloud.github.com/assets/1788727/1954191/44358884-81d1-11e3-859d-254b9fb81808.png)
Enable front-end Markdown editor. _Disabled by default_.
```json
{
"file_editor": true
}
```
###Google Analytics: ###Google Analytics:
This will embed the google analytics tracking code. This will embed the google analytics tracking code.

17
bin/compile Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
require __DIR__.'/../vendor/autoload.php';
use Todaymade\Daux\Compiler;
error_reporting(-1);
ini_set('display_errors', 1);
try {
$compiler = new Compiler();
$compiler->compile();
} catch (\Exception $e) {
echo 'Failed to compile phar: ['.get_class($e).'] '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine();
exit(1);
}

View File

@ -12,7 +12,17 @@
} }
], ],
"require": { "require": {
"php": ">=5.3", "php": ">=5.4",
"erusev/parsedown": "~1.0" "league/plates": "~3.1",
"guzzlehttp/guzzle": "~5.3",
"league/commonmark": "0.8.*",
"symfony/console": "~2.7",
"symfony/finder": "~2.7"
},
"autoload": {
"psr-4": {
"Todaymade\\Daux\\Extension\\": "daux/",
"Todaymade\\Daux\\": "libs/"
}
} }
} }

436
composer.lock generated
View File

@ -1,28 +1,43 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "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 http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
], ],
"hash": "21bea6f01fcb0695632cbacb5a3988a1", "hash": "7cb7ddabbb3aaa33e7504afc4c7150b9",
"packages": [ "packages": [
{ {
"name": "erusev/parsedown", "name": "guzzlehttp/guzzle",
"version": "1.0.0", "version": "5.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/erusev/parsedown.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "2da10d277b086372f17b96df6cdc903829e1dde0" "reference": "f3c8c22471cb55475105c14769644a49c3262b93"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/2da10d277b086372f17b96df6cdc903829e1dde0", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f3c8c22471cb55475105c14769644a49c3262b93",
"reference": "2da10d277b086372f17b96df6cdc903829e1dde0", "reference": "f3c8c22471cb55475105c14769644a49c3262b93",
"shasum": "" "shasum": ""
}, },
"require": {
"guzzlehttp/ringphp": "^1.1",
"php": ">=5.4.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0",
"psr/log": "^1.0"
},
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Parsedown": "" "GuzzleHttp\\": "src/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -31,34 +46,397 @@
], ],
"authors": [ "authors": [
{ {
"name": "Emanuil Rusev", "name": "Michael Dowling",
"email": "hello@erusev.com", "email": "mtdowling@gmail.com",
"homepage": "http://erusev.com" "homepage": "https://github.com/mtdowling"
} }
], ],
"description": "Parser for Markdown.", "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
"homepage": "http://parsedown.org", "homepage": "http://guzzlephp.org/",
"keywords": [ "keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2015-05-20 03:47:55"
},
{
"name": "guzzlehttp/ringphp",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/RingPHP.git",
"reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
"reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
"shasum": ""
},
"require": {
"guzzlehttp/streams": "~3.0",
"php": ">=5.4.0",
"react/promise": "~2.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0"
},
"suggest": {
"ext-curl": "Guzzle will use specific adapters if cURL is present"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Ring\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
"time": "2015-05-20 03:37:09"
},
{
"name": "guzzlehttp/streams",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/streams.git",
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Stream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Provides a simple abstraction over streams of data",
"homepage": "http://guzzlephp.org/",
"keywords": [
"Guzzle",
"stream"
],
"time": "2014-10-12 19:18:40"
},
{
"name": "league/commonmark",
"version": "0.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "91696c88df298f75fdd2075e4bb19c6dbd7338ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/91696c88df298f75fdd2075e4bb19c6dbd7338ca",
"reference": "91696c88df298f75fdd2075e4bb19c6dbd7338ca",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.4.8"
},
"replace": {
"colinodell/commonmark-php": "*"
},
"require-dev": {
"erusev/parsedown": "~1.0",
"jgm/commonmark": "0.19",
"michelf/php-markdown": "~1.4",
"phpunit/phpunit": "~4.3",
"phpunit/phpunit-mock-objects": "2.3.0",
"symfony/finder": "~2.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.8-dev"
}
},
"autoload": {
"psr-4": {
"League\\CommonMark\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "http://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "Markdown parser for PHP based on the CommonMark spec",
"homepage": "https://github.com/thephpleague/commonmark",
"keywords": [
"commonmark",
"markdown", "markdown",
"parser" "parser"
], ],
"time": "2014-05-14 10:14:49" "time": "2015-04-29 18:01:46"
},
{
"name": "league/plates",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/plates.git",
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802",
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802",
"shasum": ""
},
"require-dev": {
"mikey179/vfsstream": "~1.4.0",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~1.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"League\\Plates\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Reinink",
"email": "jonathan@reinink.ca",
"role": "Developer"
}
],
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
"homepage": "http://platesphp.com",
"keywords": [
"league",
"package",
"templates",
"templating",
"views"
],
"time": "2015-07-09 02:14:40"
},
{
"name": "react/promise",
"version": "v2.2.1",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise.git",
"reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627",
"reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"React\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com"
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
"time": "2015-07-03 13:48:55"
},
{
"name": "symfony/console",
"version": "v2.7.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "8cf484449130cabfd98dcb4694ca9945802a21ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/8cf484449130cabfd98dcb4694ca9945802a21ed",
"reference": "8cf484449130cabfd98dcb4694ca9945802a21ed",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1",
"symfony/phpunit-bridge": "~2.7",
"symfony/process": "~2.1"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2015-07-09 16:07:40"
},
{
"name": "symfony/finder",
"version": "v2.7.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
"reference": "ae0f363277485094edc04c9f3cbe595b183b78e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Finder/zipball/ae0f363277485094edc04c9f3cbe595b183b78e4",
"reference": "ae0f363277485094edc04c9f3cbe595b183b78e4",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2015-07-09 16:07:40"
} }
], ],
"packages-dev": [ "packages-dev": [],
"aliases": [],
],
"aliases": [
],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [ "stability-flags": [],
"prefer-stable": false,
], "prefer-lowest": false,
"platform": { "platform": {
"php": ">=5.3" "php": ">=5.4"
}, },
"platform-dev": [ "platform-dev": []
]
} }

BIN
daux.phar Executable file

Binary file not shown.

10
daux/Processor.php Normal file
View File

@ -0,0 +1,10 @@
<?php namespace Todaymade\Daux\Extension;
use Todaymade\Daux\Tree\Root;
class Processor extends \Todaymade\Daux\Processor {
public function manipulateTree(Root $root)
{
}
}

View File

@ -1,27 +0,0 @@
{
"title": "My Project",
"tagline": "My Stylish Documentation",
"author": "I, Me & Myself",
"image": "",
"theme": "daux-blue",
"breadcrumbs": false,
"template": "default",
"clean_urls": false,
"toggle_code": false,
"date_modified": false,
"float": false,
"file_editor": false,
"repo": "",
"twitter": [],
"google_analytics": "",
"timezone": "America/Los_Angeles",
"piwik_analytics": false,
"piwik_analytics_id": "0",
"languages": {},
"ignore": {
"files": [],
"folders": []
},
"links": {
}
}

View File

@ -16,6 +16,9 @@
* Supports Google Analytics and Piwik Analytics * Supports Google Analytics and Piwik Analytics
* Optional code float layout * Optional code float layout
* Static Output Generation * Static Output Generation
* Internal documentation links
* Multiple Output Formats
* Extend Daux.io with Processors
## Demos ## Demos
@ -27,14 +30,70 @@ This is a list of sites using Daux.io:
* [Munee: Standalone PHP 5.3 Asset Optimisation & Manipulation](http://mun.ee) * [Munee: Standalone PHP 5.3 Asset Optimisation & Manipulation](http://mun.ee)
* [ICADMIN: An admin panel powered by CodeIgniter.](http://istocode.com/shared/ic-admin/) * [ICADMIN: An admin panel powered by CodeIgniter.](http://istocode.com/shared/ic-admin/)
* [TrackJs](http://docs.trackjs.com) (uses a customized theme) * [TrackJs](http://docs.trackjs.com) (uses a customized theme)
* [Sugoi](http://doc.sugoi.ventrux.com/)
* [wallabag](http://doc.wallabag.org/index) * [wallabag](http://doc.wallabag.org/index)
Do you use Daux.io? Send me a pull request or open an [issue](https://github.com/justinwalsh/daux.io/issues) and I will add you to the list. Do you use Daux.io? Send me a pull request or open an [issue](https://github.com/justinwalsh/daux.io/issues) and I will add you to the list.
## Download ## Download
Download this repository as a zip, and unpack. Copy the files to a web server that can run PHP 5.3 or greater. You can also run the documentation locally using Grunt.js, which is covered at the end of this readme. Download this repository as a zip, and unpack. Copy the files to a web server that can run PHP 5.3 or greater.
You can also run the documentation locally using Grunt.js, which is covered at the end of this readme.
If you don't intend to modify Daux.io and just want to use it, you only need to copy `resources`, `daux.phar`, `global.json`, `generate`, `serve` and `index.php` With these, you're ready to create your documentation.
If however you wish to do some advanced modifications, I recommend you use the raw version and run `composer install` to get started.
## Generating a set of static files
These can be uploaded to a static site hosting service such as pages.github.com
Generating a complete set of pages, with navigation
```bash
./generate --destination=[Output Directory Relative Direction]
```
For more options, run
```bash
./generate --help
```
## Formats
Daux.io is extendable and comes by default with two export formats:
- Export to HTML
- Upload to your Atlassian Confluence server
## Feature Matrix
<table>
<tr>
<th>Feature</th><th>HTML</th><th>Confluence</th>
</tr>
<tr>
<td>Landing Pages</td><td></td><td>X</td>
</tr>
<tr>
<td>Index Pages</td><td></td><td></td>
</tr>
<tr>
<td>Internal Links</td><td></td><td></td>
</tr>
<tr>
<td>Code Highlight</td><td></td><td>√ (Using macros)</td>
</tr>
<tr>
<td>Live Mode</td><td></td><td>X</td>
</tr>
<tr>
<td>Ordering Pages</td><td></td><td>X (API Limitation)</td>
</tr>
<tr>
<td>Google / Piwik analytics</td><td></td><td>X</td>
</tr>
</table>
## Folders ## Folders
@ -69,37 +128,38 @@ You might also wish to stick certain links to the bottom of a page. You can do s
## Landing page ## Landing page
If you want to create a beautiful landing page for your project, simply create a `_index.md` file in the root of the `/docs` folder. This file will then be used to create a landing page. You can also add a tagline and image to this page using the config file like this: If you want to create a beautiful landing page for your project, create a `_index.md` file in the root of the `/docs` folder. This file will then be used to create a landing page. You can also add a tagline and image to this page using the config file like this:
```json ```json
{ {
"title": "Daux.io", "title": "Daux.io",
"tagline": "The Easiest Way To Document Your Project", "tagline": "The Easiest Way To Document Your Project",
"image": "<base_url>img/app.png" "image": "app.png"
} }
``` ```
Note: The image can be a local or remote image. Use the convention `<base_url>` to refer to the root directory of the Daux instance. Note: The image can be a local or remote image. By default, the path is relative to the root of the documentation
## Section landing page ## Section Index page
If you are interested in having a landing page for a subsection of your docs, all you need to do is add an `index.md` file to the folder. For example, `/docs/01_Examples` has a landing page for that section since there exists a `/docs/01_Examples/index.md` file. If you wish to have an landing page for a section sans the document format, use the name `_index.md` By default, a folder will have no index page. if you wish to have one defined all you need to do is add an `index.md` file to the folder. For example, `/docs/01_Examples` has a landing page for that section since there exists a `/docs/01_Examples/index.md` file.
## Clean URLs ## Internal links
Daux provides native support for Clean URLs provided the webserver has its URL Rewrite module enabled. To enable the same, simply set the toggle in the `config.json` file in the `/docs` folder. You can create links from a page to an other, the link is then resolved to the real page.
Creating a link to another page is done exactly like a normal markdown link. In the url part, start with `!` and set the absolute path to the file, omitting the numbering and file extension
A link to `01_Examples/05_Code_Highlighting.md` Would be written like this: `[Code Highlight Examples](!Examples/Code_Highlighting)`
The page generation will fail if a link is wrong.
```json
{
"clean_urls": true
}
```
## Configuration ## Configuration
To customize the look and feel of your documentation, you can create a `config.json` file in the of the `/docs` folder. The `config.json` file is a simple JSON object that you can use to change some of the basic settings of the documentation. To customize the look and feel of your documentation, you can create a `config.json` file in the of the `/docs` folder. The `config.json` file is a JSON object that you can use to change some of the basic settings of the documentation.
###Title: ### Title
Change the title bar in the docs Change the title bar in the docs
```json ```json
@ -108,117 +168,25 @@ Change the title bar in the docs
} }
``` ```
###Themes: ### Tagline
We have 4 built-in Bootstrap themes. To use one of the themes, just set the `theme` option to one of the following: Change the tagline bar in the docs
* daux-blue
* daux-green
* daux-navy
* daux-red
```json ```json
{ {
"theme": "daux-blue" "tagline": "The Easiest Way To Document Your Project"
} }
``` ```
###Custom Theme: ### Author
To use a custom theme, just copy over the theme folder as well as the `.thm` file for that theme into the `themes` directory and set its value in the `theme` param in config.json Change the documentation's author
```json ```json
{ {
"theme": "new-theme", "author": "Stéphane Goetz"
} }
``` ```
###Code Floating: ### Ignore
By default your code blocks will be floated to a column on the right side of your content. To disable this feature, set the `float` property to `false`.
```json
{
"float": false
}
```
###Toggling Code Blocks
Some users might wish to hide the code blocks & view just the documentation. By setting the `toggle_code` property to `true`, you can offer a toggle button on the page.
```json
{
"toggle_code": true
}
```
###GitHub Repo:
Add a 'Fork me on GitHub' ribbon.
```json
{
"repo": "justinwalsh/daux.io"
}
```
###Twitter:
Include twitter follow buttons in the sidebar.
```json
{
"twitter": ["justin_walsh", "todaymade"]
}
```
###Links:
Include custom links in the sidebar.
```json
{
"links": {
"GitHub Repo": "https://github.com/justinwalsh/daux.io",
"Help/Support/Bugs": "https://github.com/justinwalsh/daux.io/issues",
"Made by Todaymade": "http://todaymade.com"
}
}
```
###File editor:
![File editor](https://f.cloud.github.com/assets/1788727/1954191/44358884-81d1-11e3-859d-254b9fb81808.png)
Enable front-end Markdown editor. _Disabled by default_.
```json
{
"file_editor": true
}
```
###Google Analytics:
This will embed the google analytics tracking code.
```json
{
"google_analytics": "UA-XXXXXXXXX-XX"
}
```
###Piwik Analytics:
This will embed the piwik tracking code.
```json
{
"piwik_analytics": "my-url-for-piwik.com"
}
```
You can Also give a specific Piwik ID as well.
```json
{
"piwik_analytics_id": "43"
}
```
###Ignore:
Set custom files and entire folders to ignore within your `/docs` folder. For files make sure to include the file extension in the name. For both files and folders, names are case-sensitive. Set custom files and entire folders to ignore within your `/docs` folder. For files make sure to include the file extension in the name. For both files and folders, names are case-sensitive.
```json ```json
@ -230,40 +198,21 @@ Set custom files and entire folders to ignore within your `/docs` folder. For fi
} }
``` ```
###Breadcrumb titles ### Timezone
Daux.io provides the option to present page titles as breadcrumb navigation. You can *optionally* specify the separator used for breadcrumbs.
```json
{
"breadcrumbs": true,
"breadcrumb_separator" : " > "
}
```
###Date Modified
By default, daux.io will display the last modified time as reported by the system underneath the title for each document. To disable this, change the option in your config.json to false.
```json
{
"date_modified": false
}
```
###Timezone
If your server does not have a default timezone set in php.ini, it may return errors when it tries to generate the last modified date/time for docs. To fix these errors, specify a timezone in your config file. Valid options are available in the [PHP Manual](http://php.net/manual/en/timezones.php). If your server does not have a default timezone set in php.ini, it may return errors when it tries to generate the last modified date/time for docs. To fix these errors, specify a timezone in your config file. Valid options are available in the [PHP Manual](http://php.net/manual/en/timezones.php).
```json ```json
{ {
"timezone": "America/Los_Angeles" "timezone": "America/Los_Angeles"
} }
``` ```
###Multi-language ### Multi-language
Enables multi-language support which needs seperate directories for each language in `docs/` folder. Enables multi-language support which needs seperate directories for each language in `docs/` folder.
```json ```json
{ {
"languages": { "en": "English", "de": "German" } "languages": { "en": "English", "de": "German" }
} }
``` ```
@ -289,43 +238,234 @@ Directory structure:
│ │ │ ├── 05_Code_Highlighting.md │ │ │ ├── 05_Code_Highlighting.md
``` ```
## Running Remotely ### Format
Change the output format. It is recommended you set only formats that support the live mode as this will also
be read by the integrated web server. And you set the other formats (like confluence) only by command line
```json
{
"format": "html"
}
```
### Processor
You can set the processor in the documentation or as an option to the command line. If you need it when running the server, you should add it to the configuration.
More information on how to create a Processor can be found [here](!For_Developers/Creating_a_Processor).
```json
{
"processor": "MyProcessor"
}
```
### HTML Export Configuration
#### Themes
We have 4 built-in Bootstrap themes. To use one of the themes, just set the `theme` option to one of the following:
* daux-blue
* daux-green
* daux-navy
* daux-red
```json
{
"html": { "theme": "daux-blue" }
}
```
#### Custom Theme
To use a custom theme, just copy over the theme folder into the `themes` directory and set its value in the `theme` param in config.json
```json
{
"html": { "theme": "new-theme" }
}
```
#### Code Floating
By default your code blocks will be floated to a column on the right side of your content. To disable this feature, set the `float` property to `false`.
```json
{
"html": { "float": false }
}
```
#### Toggling Code Blocks
Some users might wish to hide the code blocks & view just the documentation. By setting the `toggle_code` property to `true`, you can offer a toggle button on the page.
```json
{
"html": { "toggle_code": true }
}
```
#### GitHub Repo
Add a 'Fork me on GitHub' ribbon.
```json
{
"html": { "repo": "justinwalsh/daux.io" }
}
```
#### Twitter
Include twitter follow buttons in the sidebar.
```json
{
"html": { "twitter": ["justin_walsh", "todaymade"] }
}
```
#### Links
Include custom links in the sidebar.
```json
{
"html": {
"links": {
"GitHub Repo": "https://github.com/justinwalsh/daux.io",
"Help/Support/Bugs": "https://github.com/justinwalsh/daux.io/issues",
"Made by Todaymade": "http://todaymade.com"
}
}
}
```
#### Google Analytics
This will embed the google analytics tracking code.
```json
{
"html": { "google_analytics": "UA-XXXXXXXXX-XX" }
}
```
#### Piwik Analytics
This will embed the piwik tracking code.
```json
{
"html": { "piwik_analytics": "my-url-for-piwik.com" }
}
```
You can Also give a specific Piwik ID as well.
```json
{
"html": { "piwik_analytics_id": "43" }
}
```
#### Breadcrumb titles
Daux.io provides the option to present page titles as breadcrumb navigation. You can *optionally* specify the separator used for breadcrumbs.
```json
{
"html": {
"breadcrumbs": true,
"breadcrumb_separator" : " > "
}
}
```
#### Date Modified
By default, daux.io will display the last modified time as reported by the system underneath the title for each document. To disable this, change the option in your config.json to false.
```json
{
"html": { "date_modified": false }
}
```
### Confluence Upload Configuration
#### Configuring the connection
The connection requires three parameters `base_url`, `user` and `pass`. While `user` and `pass` don't really need an explanation, for `base_url` you need to set the path to the server without `rest/api`, this will be added automatically.
```json
{
"confluence": {
"base_url": "http://my_confluence_server.com/,
"user" : "my_username",
"pass" : "my_password",
}
}
```
#### Where to upload
Now that the connection is defined, you need to tell it where you want your documentation to be uploaded.
For that you need a `space_id` (name that appears at the beginning of the urls) and an `ancestor_id`; the id of the page that will be the parent of the documentation's homepage.
You can obtain the `ancestor_id` id by editing the page you want to define as a parent: the ID is at the end of the URL
```json
{
"confluence": {
"space_id": "my_space",
"ancestor_id": 50370632
}
}
```
#### Prefix
Because confluence can't have two pages with the same name in a space, I recommend you define a prefix for your pages.
```json
{
"confluence": { "prefix": "[DAUX]" }
}
```
## Live mode
Keep in mind, this mode can be used for production, but it is not recommended.
The whole directory must be scanned on each request. This might not make a big impact on small documentations but can be a bottleneck on bigger ones.
### Running Locally
There are several ways to run the docs locally. You can use something like <a href="http://www.mamp.info/en/index.html" target="_blank">MAMP</a> or <a href="http://www.wampserver.com/en/" target="_blank">WAMP</a>.
The easiest is to use PHP 5.4's built-in server.
For that i've included a short command, run `./serve` in the projects folder to start the local web server. By default the server will run at: <a href="http://localhost:8085" target="_blank">http://localhost:8085</a>
### Running Remotely
Copy the files from the repo to a web server that can run PHP 5.3 or greater. Copy the files from the repo to a web server that can run PHP 5.3 or greater.
## Running Locally There is an included `.htaccess` for Apache web server.
There are several ways to run the docs locally. You can use something like <a href="http://www.mamp.info/en/index.html" target="_blank">MAMP</a> or <a href="http://www.wampserver.com/en/" target="_blank">WAMP</a>. If you are like me and use alot of Node.js and <a href="http://gruntjs.com/" target="_blank">Grunt.js</a>, then you can use the optional grunt command I have packaged with the project which will start a PHP web server for you in the project folder. ### Clean URLs configuration
The Grunt.js task uses the built in web server in PHP 5.4 to host the docs on your local machine. This is really only intended be used when you are writing/updating a ton of docs and want to preview the changes locally. Daux provides native support for Clean URLs provided the webserver has its URL Rewrite module enabled. To enable the same, set the toggle in the `config.json` file in the `/docs` folder.
**To use the optional Grunt command you will need:** ```json
{
* Node.js "live": {
* npm "clean_urls": true
* Grunt.js }
* PHP 5.4 or greater (This is because of the built-in web server packaged in 5.4) }
This project contains a package.json file, so once you have the requirements installed, you can simply run a `npm install` and then `grunt` in the projects folder to start the local web server. By default the server will run at: <a href="http://localhost:8085" target="_blank">http://localhost:8085</a>
## Generating a set of static files
These can be uploaded to a static site hosting service such as pages.github.com
Generating a complete set of pages, with navigation
```bash
php generate.php [global.json Relative Location] [Output Directory Relative Direction]
``` ```
## Running on IIS ### Running on IIS
If you have set up a local or remote IIS web site, you may need a `web.config` with: If you have set up a local or remote IIS web site, you may need a `web.config` with:
* A rewrite configuration, for handling clean urls. * A rewrite configuration, for handling clean urls.
* A mime type handler for less files, if using a custom theme. * A mime type handler for less files, if using a custom theme.
### Clean URLs #### Clean URLs
The `web.config` needs an entry for `<rewrite>` under `<system.webServer>`: The `web.config` needs an entry for `<rewrite>` under `<system.webServer>`:
@ -350,20 +490,6 @@ The `web.config` needs an entry for `<rewrite>` under `<system.webServer>`:
To use clean URLs on IIS 6, you will need to use a custom URL rewrite module, such as [URL Rewriter](http://urlrewriter.net/). To use clean URLs on IIS 6, you will need to use a custom URL rewrite module, such as [URL Rewriter](http://urlrewriter.net/).
### Less Mime Type
The `web.config` needs a new `<mimeMap>` entry, under `<staticContent>` in `<system.webServer>`:
```xml
<staticContent>
<mimeMap fileExtension=".less" mimeType="text/css" />
</staticContent>
```
You will only need the mime map entry if you are using a custom theme and receive 404s for `.less` files.
If you have a global mime map entry for `.less` files set for the server, you will receive an internal server (500) error for having duplicate mime map entries.
## Support ## Support
If you need help using Daux.io, or have found a bug, please create an issue on the <a href="https://github.com/justinwalsh/daux.io/issues" target="_blank">GitHub repo</a>. If you need help using Daux.io, or have found a bug, please create an issue on the <a href="https://github.com/justinwalsh/daux.io/issues" target="_blank">GitHub repo</a>.

View File

@ -1,38 +1,3 @@
Let's get the whole "linebreak" thing out of the way. The next paragraph contains two phrases separated by a single newline character:
Roses are red
Violets are blue
The next paragraph has the same phrases, but now they are separated by two spaces and a newline character:
Roses are red
Violets are blue
Oh, and one thing I cannot stand is the mangling of words with multiple underscores in them like perform_complicated_task or do_this_and_do_that_and_another_thing.
A bit of the GitHub spice
-------------------------
In addition to the changes in the previous section, certain references are auto-linked:
* SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
* User@SHA ref: mojombo@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
* User/Project@SHA: mojombo/god@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2
* \#Num: #1
* User/#Num: mojombo#1
* User/Project#Num: mojombo/god#1
These are dangerous goodies though, and we need to make sure email addresses don't get mangled:
My email addy is tom@github.com.
Math is hard, let's go shopping
-------------------------------
In first grade I learned that 5 > 3 and 2 < 7. Maybe some arrows. 1 -> 2 -> 3. 9 <- 8 <- 7.
Triangles man! a^2 + b^2 = c^2
We all like making lists We all like making lists
------------------------ ------------------------

View File

@ -1,5 +1,8 @@
Highlight.js highlights syntax in code examples on blogs, forums and in fact on any web pages. It's very easy to use because it works automatically: finds blocks of code, detects a language, highlights it. [Learn more.](http://softwaremaniacs.org/soft/highlight/en/) Highlight.js highlights syntax in code examples on blogs, forums and in fact on any web pages. It's very easy to use because it works automatically: finds blocks of code, detects a language, highlights it. [Learn more.](http://softwaremaniacs.org/soft/highlight/en/)
You can even use [Github Flavored Markdown](!Examples/GitHub_Flavored_Markdown)
**Python** **Python**
@requires_authorization @requires_authorization

View File

@ -0,0 +1,89 @@
The recommended way to extend Daux is through Processors.
The main advantage, is that you can run it with the source or with `daux.phar` independently. You don't need to hack in the core.
## Adding classes
At the same level as your `daux.phar` file, you will see a `daux` directory, you can create all your classes here.
The classes must respect the PSR-4 Naming convention. And have `\Todaymade\Daux\Extension` as a base namespace.
By default, we created a `daux/Processor.php` file to get you started.
## A quick test ?
For the example we're just going to dump the tree and exit.
```php
public function manipulateTree(Root $root)
{
print_r($root->dump());
exit;
}
```
also, add this at the beginning of the file:
```php
use Todaymade\Daux\Tree\Root;
```
Let's just try if it works by running `./generate --processor=Processor`
Yes, you get a big array dump! You're good to go.
## What can I achieve ?
There are a few methods that you can override to add some
### Change the parsed tree.
By default, Daux.io parses your directory to find pages. but, for a reason or another, you might want to programmatically add some pages.
This can be done with:
```php
public function manipulateTree(Root $root)
{
}
```
Two helpers from the class `Todaymade\Daux\Tree\Builder` will greatly help you doing that:
```php
$new = Builder::getOrCreateDir($root, 'New Pages');
$page = Builder::getOrCreatePage($new, 'index');
$page->setContent('The index page for the new folder');
$page = Builder::getOrCreatePage($new, 'A New Hope');
$page->setContent('A long time ago in a galaxy far away');
```
Both methods `getOrCreateDir` and `getOrCreatePage` take two parameters : `parent` and `title`
### Extend the Markdown Generator
You can extend the Markdown Parser in any way wou want with this method.
```php
public function extendCommonMarkEnvironment(Environment $environment)
{
}
```
See the details on [CommonMark's website](http://commonmark.thephpleague.com/customization/overview/).
### Add new generators
You can add new generators to Daux.io and use them right away, they must implement the
`\Todaymade\Daux\Format\Base\Generator` interface and if you want to use the live mode with your generator
you have to implement `\Todaymade\Daux\Format\Base\LiveGenerator`.
```php
public function addGenerators()
{
return ['custom_generator' => '\Todaymade\Daux\Extension\MyNewGenerator'];
}
```

View File

@ -6,7 +6,7 @@
<h3>Features</h3> <h3>Features</h3>
<hr/> <hr/>
<img src="img/app-thumbs.png" alt="alt text" class="img-responsive pull-right" style="margin-bottom:20px;"> <img src="app-thumbs.png" alt="alt text" class="img-responsive pull-right" style="margin-bottom:20px;">
* 100% Mobile Responsive * 100% Mobile Responsive
* Supports GitHub Flavored Markdown * Supports GitHub Flavored Markdown
@ -19,8 +19,12 @@
* Built On Bootstrap * Built On Bootstrap
* No Build Step * No Build Step
* Git/SVN Friendly * Git/SVN Friendly
* Google Analytics * Supports Google Analytics and Piwik Analytics
* Optional code float layout * Optional code float layout
* Static Output Generation
* Internal documentation links
* Multiple Output Formats
* Extend Daux.io with Processors
<div class="clear"></div> <div class="clear"></div>
<hr/> <hr/>

View File

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 235 KiB

View File

@ -2,27 +2,30 @@
"title": "DAUX.IO", "title": "DAUX.IO",
"tagline": "The Easiest Way To Document Your Project", "tagline": "The Easiest Way To Document Your Project",
"author": "Justin Walsh", "author": "Justin Walsh",
"image": "<base_url>img/app.png", "image": "app.png",
"theme": "daux-blue",
"template": "default",
"clean_urls": true,
"toggle_code": true,
"breadcrumbs": true,
"breadcrumb_separator": "Chevrons",
"date_modified": true,
"float": true,
"file_editor": false,
"repo": "justinwalsh/daux.io",
"ignore": { "ignore": {
"files": ["Work_In_Progress.md"], "files": ["Work_In_Progress.md"],
"folders": ["99_Not_Ready"] "folders": ["99_Not_Ready"]
}, },
"twitter": ["justin_walsh", "todaymade"], "live": {
"google_analytics": "UA-12653604-10", "clean_urls": true
"links": { },
"Download": "https://github.com/justinwalsh/daux.io/archive/master.zip", "html": {
"GitHub Repo": "https://github.com/justinwalsh/daux.io", "theme": "daux-blue",
"Help/Support/Bugs": "https://github.com/justinwalsh/daux.io/issues", "breadcrumbs": true,
"Made by Todaymade": "http://todaymade.com" "breadcrumb_separator": "Chevrons",
"toggle_code": true,
"date_modified": true,
"float": true,
"repo": "justinwalsh/daux.io",
"twitter": ["justin_walsh", "todaymade"],
"google_analytics": "UA-12653604-10",
"links": {
"Download": "https://github.com/justinwalsh/daux.io/archive/master.zip",
"GitHub Repo": "https://github.com/justinwalsh/daux.io",
"Help/Support/Bugs": "https://github.com/justinwalsh/daux.io/issues",
"Made by Todaymade": "http://todaymade.com"
}
} }
} }

14
generate.php → generate Normal file → Executable file
View File

@ -1,6 +1,5 @@
#!/usr/bin/env php
<?php <?php
require_once("libs/daux.php");
/* /*
Daux.io Daux.io
@ -64,9 +63,8 @@ negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage. software, even if advised of the possibility of such damage.
*/ */
if (isset($argv[1])) $Daux = new \Todaymade\Daux\Daux($argv[1]);
else $Daux = new \Todaymade\Daux\Daux(); require_once("vendor/autoload.php");
$Daux->initialize();
if (isset($argv[2])) $Daux->generate_static($argv[2]); $application = new \Todaymade\Daux\Generator\Application();
else $Daux->generate_static(); $application->run();
?>

View File

@ -1,4 +1,45 @@
{ {
"docs_directory": "docs", "docs_directory": "docs",
"valid_markdown_extensions": ["md", "markdown"] "valid_content_extensions": ["md", "markdown"],
"title": "My Project",
"tagline": "My Stylish Documentation",
"author": "I, Me & Myself",
"image": "",
"languages": {},
"format": "html",
"processor": "",
"ignore": {
"files": [],
"folders": []
},
"timezone": "America/Los_Angeles",
"live": {
"clean_urls": false
},
"html": {
"theme": "daux-blue",
"breadcrumbs": false,
"toggle_code": false,
"date_modified": false,
"float": false,
"repo": "",
"twitter": [],
"links": {
},
"google_analytics": false,
"piwik_analytics": false,
"piwik_analytics_id": "0"
},
"confluence": {
"prefix": ""
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,6 +1,4 @@
<?php <?php
require_once("libs/daux.php");
/* /*
Daux.io Daux.io
@ -64,8 +62,26 @@ negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage. software, even if advised of the possibility of such damage.
*/ */
$Daux = new \Todaymade\Daux\Daux();
$Daux->initialize(); if (php_sapi_name() === 'cli-server') {
$page = $Daux->handle_request($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], $_REQUEST); // This file allows us to emulate Apache's "mod_rewrite"
$page->display(); // functionality from the built-in PHP web server.
?> $uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
if ($uri !== '/' && file_exists(__DIR__ . $uri)) {
return false;
}
// When the built in server is used
// the script name is the file called
$_SERVER['SCRIPT_NAME'] = '/index.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 and phar");
}
\Todaymade\Daux\Server\Server::serve($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], $_REQUEST);

View File

@ -1,53 +0,0 @@
$(document).ready(function() {
var markdown_editor = $("#markdown_editor"),
save_editor = $(".save_editor"),
editor = $(".editor");
$("#editThis").click(function() {
editor.css({"display":"block"});
markdown_editor.autosize().val();
});
$(".closeEditor").click(function() {
editor.css({"display":"none"});
});
save_editor.click(function() {
var original_text = save_editor.text();
save_editor.text("Saving...").addClass("disabled");
$.post(window.location.href, {markdown: markdown_editor.val(), method: 'DauxEdit' }, function() {
save_editor.text("Done! Reloading page in 5 seconds. You can cancel it with ESC key");
var timeout = setTimeout(function() {
location.reload()
}, 5000); // lie
$(document).keyup(function(e) {
if (e.keyCode == 27) { // esc key
clearTimeout(timeout);
save_editor.text("Page reload cancelled");
setTimeout(function() {
save_editor.text(original_text).removeClass('disabled');
}, 2000);
}
});
}).fail(function() {
save_editor.removeClass('disabled').addClass("btn-danger").text("Failed :( - try checking your read/write permissions");
setTimeout(function() {
save_editor.text(original_text).removeClass('btn-danger');
},5000);
});
});
});
/*!
Autosize v1.18.4 - 2014-01-11
Automatically adjust textarea height based on user input.
(c) 2014 Jack Moore - http://www.jacklmoore.com/autosize
license: http://www.opensource.org/licenses/mit-license.php
*/
!function(a){var b,c={className:"autosizejs",append:"",callback:!1,resizeDelay:10,placeholder:!0},d='<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>',e=["fontFamily","fontSize","fontWeight","fontStyle","letterSpacing","textTransform","wordSpacing","textIndent"],f=a(d).data("autosize",!0)[0];f.style.lineHeight="99px","99px"===a(f).css("lineHeight")&&e.push("lineHeight"),f.style.lineHeight="",a.fn.autosize=function(d){return this.length?(d=a.extend({},c,d||{}),f.parentNode!==document.body&&a(document.body).append(f),this.each(function(){function c(){var b,c=window.getComputedStyle?window.getComputedStyle(m,null):!1;c?(b=m.getBoundingClientRect().width,0===b&&(b=parseInt(c.width,10)),a.each(["paddingLeft","paddingRight","borderLeftWidth","borderRightWidth"],function(a,d){b-=parseInt(c[d],10)})):b=Math.max(n.width(),0),f.style.width=b+"px"}function g(){var g={};if(b=m,f.className=d.className,j=parseInt(n.css("maxHeight"),10),a.each(e,function(a,b){g[b]=n.css(b)}),a(f).css(g),c(),window.chrome){var h=m.style.width;m.style.width="0px";{m.offsetWidth}m.style.width=h}}function h(){var e,h;b!==m?g():c(),f.value=!m.value&&d.placeholder?(a(m).attr("placeholder")||"")+d.append:m.value+d.append,f.style.overflowY=m.style.overflowY,h=parseInt(m.style.height,10),f.scrollTop=0,f.scrollTop=9e4,e=f.scrollTop,j&&e>j?(m.style.overflowY="scroll",e=j):(m.style.overflowY="hidden",k>e&&(e=k)),e+=o,h!==e&&(m.style.height=e+"px",p&&d.callback.call(m,m))}function i(){clearTimeout(l),l=setTimeout(function(){var a=n.width();a!==r&&(r=a,h())},parseInt(d.resizeDelay,10))}var j,k,l,m=this,n=a(m),o=0,p=a.isFunction(d.callback),q={height:m.style.height,overflow:m.style.overflow,overflowY:m.style.overflowY,wordWrap:m.style.wordWrap,resize:m.style.resize},r=n.width();n.data("autosize")||(n.data("autosize",!0),("border-box"===n.css("box-sizing")||"border-box"===n.css("-moz-box-sizing")||"border-box"===n.css("-webkit-box-sizing"))&&(o=n.outerHeight()-n.height()),k=Math.max(parseInt(n.css("minHeight"),10)-o||0,n.height()),n.css({overflow:"hidden",overflowY:"hidden",wordWrap:"break-word",resize:"none"===n.css("resize")||"vertical"===n.css("resize")?"none":"horizontal"}),"onpropertychange"in m?"oninput"in m?n.on("input.autosize keyup.autosize",h):n.on("propertychange.autosize",function(){"value"===event.propertyName&&h()}):n.on("input.autosize",h),d.resizeDelay!==!1&&a(window).on("resize.autosize",i),n.on("autosize.resize",h),n.on("autosize.resizeIncludeStyle",function(){b=null,h()}),n.on("autosize.destroy",function(){b=null,clearTimeout(l),a(window).off("resize",i),n.off("autosize").off(".autosize").css(q).removeData("autosize")}),h())})):this}}(window.jQuery||window.$);

View File

@ -1,35 +0,0 @@
/* ===========================================================================================
Markdown editor
============================================================================================== */
.editor {
position: absolute;
top: 0;
left: 0;
right: 0;
background: white;
padding: 20px;
padding-bottom: 100px;
min-height: 100%;
height: auto;
display: none;
h3 {
width: 100% !important;
}
&.paddingTop {
padding-top: 50px;
}
}
#markdown_editor {
width: 85%;
margin: 0 auto;
padding: 10px;
height: auto;
font-size: 16px;
min-height: 100px;
font-family: "Ubuntu Mono", "Consolas", monospace;
display: block;
}

174
libs/Compiler.php Normal file
View File

@ -0,0 +1,174 @@
<?php
/*
* This class is inspired from Composer's compiler
* @see https://github.com/composer/composer/blob/master/src/Composer/Compiler.php
*/
namespace Todaymade\Daux;
use Symfony\Component\Finder\Finder;
/**
* The Compiler class compiles daux into a phar
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Stéphane Goetz <stephane.goetz@onigoetz.ch>
*/
class Compiler
{
/**
* Compiles composer into a single phar file
*
* @throws \RuntimeException
* @param string $pharFile The full path to the file to create
*/
public function compile($pharFile = 'daux.phar')
{
if (file_exists($pharFile)) {
unlink($pharFile);
}
$phar = new \Phar($pharFile, 0, 'daux.phar');
$phar->setSignatureAlgorithm(\Phar::SHA1);
$phar->startBuffering();
// Daux
$finder = new Finder();
$finder->files()
->ignoreVCS(true)
->name('*.php')
->notName('Compiler.php')
->in(__DIR__ . '/../templates')
->in(__DIR__);
foreach ($finder as $file) {
$this->addFile($phar, $file);
}
// Composer libraries
$finder = new Finder();
$finder->files()
->ignoreVCS(true)
->exclude('Tests')
->in(__DIR__ . '/../vendor/symfony/console')
->in(__DIR__ . '/../vendor/guzzlehttp/guzzle/src/')
->in(__DIR__ . '/../vendor/guzzlehttp/ringphp/src/')
->in(__DIR__ . '/../vendor/guzzlehttp/streams/src/')
->in(__DIR__ . '/../vendor/league/commonmark/src/')
->in(__DIR__ . '/../vendor/league/plates/src/')
->in(__DIR__ . '/../vendor/react/promise/src/');
foreach ($finder as $file) {
$this->addFile($phar, $file);
}
// Composer autoload
$this->addComposer($phar);
$this->addBinary($phar);
// Stubs
$phar->setStub($this->getStub());
$phar->stopBuffering();
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../LICENSE'), false);
unset($phar);
}
private function addFile($phar, $file, $strip = true)
{
$path = strtr(str_replace(dirname(__DIR__) . DIRECTORY_SEPARATOR, '', $file->getRealPath()), '\\', '/');
$content = file_get_contents($file);
if ($strip) {
$content = $this->stripWhitespace($content);
} elseif ('LICENSE' === basename($file)) {
$content = "\n" . $content . "\n";
}
$phar->addFromString($path, $content);
}
private function addComposer($phar)
{
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_classmap.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_files.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_real.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/ClassLoader.php'));
$content = file_get_contents(__DIR__ . '/../vendor/composer/autoload_psr4.php');
$content = str_replace('$baseDir . \'/daux\'', 'PHAR_DIR . \'/daux\'', $content);
$phar->addFromString('vendor/composer/autoload_psr4.php', $content);
}
private function addBinary($phar)
{
$content = file_get_contents(__DIR__ . '/../generate');
$content = preg_replace('{^#!/usr/bin/env php\s*}', '', $content);
$phar->addFromString('generate', $content);
}
/**
* Removes whitespace from a PHP source string while preserving line numbers.
*
* @param string $source A PHP string
* @return string The PHP string with the whitespace removed
*/
private function stripWhitespace($source)
{
if (!function_exists('token_get_all')) {
return $source;
}
$output = '';
foreach (token_get_all($source) as $token) {
if (is_string($token)) {
$output .= $token;
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
$output .= str_repeat("\n", substr_count($token[1], "\n"));
} elseif (T_WHITESPACE === $token[0]) {
// reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
// normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
// trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
$output .= $whitespace;
} else {
$output .= $token[1];
}
}
return $output;
}
private function getStub()
{
return <<<'EOF'
#!/usr/bin/env php
<?php
/*
* This file is part of Daux.
*
* (c) Stéphane Goetz <onigoetz@onigoetz.ch>
*
* For the full copyright and license information, please view
* the license that is located at the bottom of this file.
*/
define('PHAR_DIR', dirname(__FILE__));
Phar::mapPhar('daux.phar');
require 'phar://daux.phar/generate';
__HALT_COMPILER();
EOF;
}
}

49
libs/Config.php Normal file
View File

@ -0,0 +1,49 @@
<?php namespace Todaymade\Daux;
use ArrayObject;
class Config extends ArrayObject
{
/**
* Merge an array into the object
*
* @param array $newValues
* @param bool $override
*/
public function merge($newValues, $override = true)
{
foreach ($newValues as $key => $value) {
// If the key doesn't exist yet,
// we can simply set it.
if (!array_key_exists($key, $this)) {
$this[$key] = $value;
continue;
}
// We already know this value exists
// so if we're in conservative mode
// we can skip this key
if ($override === false) {
continue;
}
// Merge the values only if
// both values are arrays
if (is_array($this[$key]) && is_array($value)) {
$this[$key] = array_replace_recursive($this[$key], $value);
} else {
$this[$key] = $value;
}
}
}
/**
* Merge an array into the object, ignore already added keys.
*
* @param $newValues
*/
public function conservativeMerge($newValues)
{
$this->merge($newValues, false);
}
}

280
libs/Daux.php Normal file
View File

@ -0,0 +1,280 @@
<?php namespace Todaymade\Daux;
use Symfony\Component\Console\Output\NullOutput;
use Todaymade\Daux\Tree\Builder;
use Todaymade\Daux\Tree\Root;
class Daux
{
const STATIC_MODE = 'DAUX_STATIC';
const LIVE_MODE = 'DAUX_LIVE';
/** @var string */
public $local_base;
/** @var string */
public $internal_base;
/** @var string */
private $docs_path;
/** @var Processor */
protected $processor;
/** @var Tree\Root */
public $tree;
/** @var Config */
public $options;
/** @var string */
private $mode;
/** @var bool */
private $merged_defaults = false;
/** @var bool */
private $merged_tree = false;
/**
* @param string $mode
*/
public function __construct($mode)
{
$this->mode = $mode;
$this->local_base = $this->internal_base = dirname(__DIR__);
// In case we're inside the phar archive
// we save the path to the directory
// in which it is contained
if (defined('PHAR_DIR')) {
$this->local_base = PHAR_DIR;
}
}
/**
* @param string $override_file
* @throws Exception
*/
public function initialize($override_file = 'config.json')
{
// global.json
$this->loadBaseConfiguration();
// Check the documentation path
$this->docs_path = $this->options['docs_directory'];
if (!is_dir($this->docs_path) &&
!is_dir($this->docs_path = $this->local_base . DIRECTORY_SEPARATOR . $this->docs_path)
) {
throw new Exception('The Docs directory does not exist. Check the path again : ' . $this->docs_path);
}
// <docs>/config.json, <overrides.json>
$this->loadConfigurationOverrides($override_file);
// Set a valid default timezone
if (isset($this->options['timezone'])) {
date_default_timezone_set($this->options['timezone']);
} elseif (!ini_get('date.timezone')) {
date_default_timezone_set('GMT');
}
}
/**
* Load and validate the global configuration
*
* @throws Exception
*/
protected function loadBaseConfiguration()
{
$this->options = new Config();
// Set the default configuration
$this->options->merge([
'docs_directory' => 'docs',
'valid_content_extensions' => ['md', 'markdown']
]);
// Load the global configuration
$this->loadConfiguration($this->local_base . DIRECTORY_SEPARATOR . 'global.json', false);
}
/**
* Load the configuration files, first, "config.json"
* in the documentation and then the file specified
* when running the configuration
*
* @param string $override_file
* @throws Exception
*/
protected function loadConfigurationOverrides($override_file)
{
// Read documentation overrides
$this->loadConfiguration($this->docs_path . DIRECTORY_SEPARATOR . 'config.json');
// Read command line overrides
if (!is_null($override_file)) {
$this->loadConfiguration($this->local_base . DIRECTORY_SEPARATOR . $override_file);
}
}
/**
* @param string $config_file
* @param bool $optional
* @throws Exception
*/
protected function loadConfiguration($config_file, $optional = true)
{
if (!file_exists($config_file)) {
if ($optional) {
return;
}
throw new Exception('The configuration file is missing. Check path : ' . $config_file);
}
$config = json_decode(file_get_contents($config_file), true);
if (!isset($config)) {
throw new Exception('The configuration file "' . $config_file . '" is corrupt. Is your JSON well-formed ?');
}
$this->options->merge($config);
}
/**
* Generate the tree that will be used
*/
public function generateTree()
{
$this->tree = new Root($this->getParams(), $this->docs_path);
Builder::build($this->tree, $this->options['ignore']);
if (!empty($this->options['languages'])) {
foreach ($this->options['languages'] as $key => $node) {
$this->tree->getEntries()[$key]->setTitle($node);
}
}
}
/**
* @return Config
*/
public function getParams()
{
if (!$this->merged_defaults) {
$default = [
//Features
'multilanguage' => !empty($this->options['languages']),
//Paths and tree
'mode' => $this->mode,
'local_base' => $this->local_base,
'docs_path' => $this->docs_path,
'templates' => $this->internal_base . DIRECTORY_SEPARATOR . 'templates',
];
$this->options->conservativeMerge($default);
$this->options['index_key'] = 'index.html';
$this->options['base_page'] = $this->options['base_url'] = '';
$this->merged_defaults = true;
}
if ($this->tree && !$this->merged_tree) {
$this->options['tree'] = $this->tree;
$this->options['index'] = $this->tree->getIndexPage() ?: $this->tree->getFirstPage();
if ($this->options['multilanguage']) {
foreach ($this->options['languages'] as $key => $name) {
$this->options['entry_page'][$key] = $this->tree->getEntries()[$key]->getFirstPage();
}
} else {
$this->options['entry_page'] = $this->tree->getFirstPage();
}
$this->merged_tree = true;
}
return $this->options;
}
/**
* @return Processor
*/
public function getProcessor()
{
if (!$this->processor) {
$this->processor = new Processor($this, new NullOutput(), 0);
}
return $this->processor;
}
/**
* @param Processor $processor
*/
public function setProcessor(Processor $processor)
{
$this->processor = $processor;
// This is not the cleanest but it's
// the best i've found to use the
// processor in very remote places
$this->options['processor_instance'] = $processor;
}
public function getGenerators()
{
$default = [
'confluence' => '\Todaymade\Daux\Format\Confluence\Generator',
'html' => '\Todaymade\Daux\Format\HTML\Generator',
];
$extended = $this->getProcessor()->addGenerators();
return array_replace($default, $extended);
}
public function getProcessorClass()
{
$processor = $this->getParams()['processor'];
if (empty($processor)) {
return null;
}
$class = "\\Todaymade\\Daux\\Extension\\" . $processor;
if (!class_exists($class)) {
throw new \RuntimeException("Class '$class' not found. We cannot use it as a Processor");
}
//TODO :: check that it implements processor
return $class;
}
/**
* @return \Todaymade\Daux\Format\Base\Generator
*/
public function getGenerator()
{
$generators = $this->getGenerators();
$format = $this->getParams()['format'];
if (!array_key_exists($format, $generators)) {
throw new \RuntimeException("The format '$format' doesn't exist, did you forget to set your processor ?");
}
$class = $generators[$format];
if (!class_exists($class)) {
throw new \RuntimeException("Class '$class' not found. We cannot use it as a Generator");
}
$interface = 'Todaymade\Daux\Format\Base\Generator';
if (!in_array('Todaymade\Daux\Format\Base\Generator', class_implements($class))) {
throw new \RuntimeException("The class '$class' does not implement the '$interface' interface");
}
return new $class($this);
}
}

331
libs/DauxHelper.php Normal file
View File

@ -0,0 +1,331 @@
<?php namespace Todaymade\Daux;
use Todaymade\Daux\Tree\Directory;
class DauxHelper
{
/**
* Set a new base_url for the configuration
*
* @param Config $config
* @param string $base_url
*/
public static function rebaseConfiguration(Config $config, $base_url)
{
// Avoid changing the url if it is already correct
if ($config['base_url'] == $base_url && !empty($config['theme'])) {
return;
}
// Change base url for all links on the pages
$config['base_url'] = $config['base_page'] = $base_url;
$config['theme'] = static::getTheme($config, $base_url);
$config['image'] = str_replace('<base_url>', $base_url, $config['image']);
}
/**
* @param Config $params
* @param string $current_url
* @return array
*/
public static function getTheme($params, $current_url)
{
$theme_folder = $params['local_base'] . DIRECTORY_SEPARATOR . 'resources' .
DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $params['html']['theme'];
$theme_url = $params['base_url'] . "resources/themes/" . $params['html']['theme'] . '/';
$theme = array();
if (is_file($theme_folder . DIRECTORY_SEPARATOR . "config.json")) {
$theme = json_decode(file_get_contents($theme_folder . DIRECTORY_SEPARATOR . "config.json"), true);
if (!$theme) {
$theme = array();
}
}
//Default parameters for theme
$theme += [
'name' => $params['html']['theme'],
'css' => [],
'js' => [],
'fonts' => [],
'require-jquery' => false,
'bootstrap-js' => false,
'favicon' => '<base_url>resources/img/favicon.png',
'templates' => $theme_folder . DIRECTORY_SEPARATOR . 'templates',
];
$substitutions = [
'<local_base>' => $params['local_base'],
'<base_url>' => $current_url,
'<theme_url>' => $theme_url
];
// Substitute some placeholders
$theme['templates'] = strtr($theme['templates'], $substitutions);
$theme['favicon'] = utf8_encode(strtr($theme['favicon'], $substitutions));
foreach (['css', 'js', 'fonts'] as $element) {
foreach ($theme[$element] as $key => $value) {
$theme[$element][$key] = utf8_encode(strtr($value, $substitutions));
}
}
return $theme;
}
/**
* @param string $path
* @return string
*/
public static function getCleanPath($path)
{
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach ($parts as $part) {
if ('.' == $part) {
continue;
}
if ('..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
return implode(DIRECTORY_SEPARATOR, $absolutes);
}
/**
* Get pathinfo for a file
*
* @param string $path
* @return array
*/
public static function pathinfo($path)
{
preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $m);
$ret = [];
foreach (['dir' => 1, 'basename' => 2, 'filename' => 3, 'extension' => 5] as $key => $group) {
if (isset($m[$group])) {
$ret[$key] = $m[$group];
}
}
return $ret;
}
/**
* Locate a file in the tree. Returns the file if found or false
*
* @param Directory $tree
* @param string $request
* @return Tree\Content|Tree\Raw|false
*/
public static function getFile($tree, $request)
{
$request = explode('/', $request);
foreach ($request as $node) {
// If the element we're in currently is not a
// directory, we failed to find the requested file
if (!$tree instanceof Directory) {
return false;
}
// if the node exists in the current request tree,
// change the $tree variable to reference the new
// node and proceed to the next url part
if (isset($tree->getEntries()[$node])) {
$tree = $tree->getEntries()[$node];
continue;
}
// At this stage, we're in a directory, but no
// sub-item matches, so the current node must
// be an index page or we failed
if ($node !== 'index' && $node !== 'index.html') {
return false;
}
return $tree->getIndexPage();
}
// If the entry we found is not a directory, we're done
if (!$tree instanceof Directory) {
return $tree;
}
if ($index = $tree->getIndexPage()) {
return $index;
}
return false;
}
/**
* Generate a URL friendly "slug" from a given string.
*
* Taken from Stringy
*
* @param string $title
* @return string
*/
public static function slug($title)
{
foreach (static::charsArray() as $key => $value) {
$title = str_replace($value, $key, $title);
}
$title = preg_replace('/[^\x20-\x7E]/u', '', $title);
$separator = '_';
// Convert all dashes into underscores
$title = preg_replace('![' . preg_quote("-") . ']+!u', $separator, $title);
// Remove all characters that are not the separator, letters, numbers, or whitespace.
$title = preg_replace('![^' . preg_quote($separator) . '\pL\pN\s]+!u', '', $title);
// Replace all separator characters and whitespace by a single separator
$title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
return trim($title, $separator);
}
/**
* Returns the replacements for the slug() method.
*
* Taken from Stringy
*
* @return array An array of replacements.
*/
public static function charsArray()
{
static $charsArray;
if (isset($charsArray)) {
return $charsArray;
}
return $charsArray = array(
'a' => array(
'à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ',
'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ä', 'ā', 'ą',
'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ',
'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ',
'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ'),
'b' => array('б', 'β', 'Ъ', 'Ь', 'ب'),
'c' => array('ç', 'ć', 'č', 'ĉ', 'ċ'),
'd' => array('ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ',
'д', 'δ', 'د', 'ض'),
'e' => array('é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ',
'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ',
'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э',
'є', 'ə'),
'f' => array('ф', 'φ', 'ف'),
'g' => array('ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ج'),
'h' => array('ĥ', 'ħ', 'η', 'ή', 'ح', 'ه'),
'i' => array('í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į',
'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ',
'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ',
'ῗ', 'і', 'ї', 'и'),
'j' => array('ĵ', 'ј', 'Ј'),
'k' => array('ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك'),
'l' => array('ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل'),
'm' => array('м', 'μ', 'م'),
'n' => array('ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن'),
'o' => array('ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ',
'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő',
'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό',
'ö', 'о', 'و', 'θ'),
'p' => array('п', 'π'),
'r' => array('ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر'),
's' => array('ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص'),
't' => array('ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط'),
'u' => array('ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ',
'ự', 'ü', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у'),
'v' => array('в'),
'w' => array('ŵ', 'ω', 'ώ'),
'x' => array('χ'),
'y' => array('ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ',
'ϋ', 'ύ', 'ΰ', 'ي'),
'z' => array('ź', 'ž', 'ż', 'з', 'ζ', 'ز'),
'aa' => array('ع'),
'ae' => array('æ'),
'ch' => array('ч'),
'dj' => array('ђ', 'đ'),
'dz' => array('џ'),
'gh' => array('غ'),
'kh' => array('х', 'خ'),
'lj' => array('љ'),
'nj' => array('њ'),
'oe' => array('œ'),
'ps' => array('ψ'),
'sh' => array('ш'),
'shch' => array('щ'),
'ss' => array('ß'),
'th' => array('þ', 'ث', 'ذ', 'ظ'),
'ts' => array('ц'),
'ya' => array('я'),
'yu' => array('ю'),
'zh' => array('ж'),
'(c)' => array('©'),
'A' => array('Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ',
'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Ä', 'Å', 'Ā',
'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ',
'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ',
'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А'),
'B' => array('Б', 'Β'),
'C' => array('Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'),
'D' => array('Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'),
'E' => array('É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ',
'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ',
'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э',
'Є', 'Ə'),
'F' => array('Ф', 'Φ'),
'G' => array('Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'),
'H' => array('Η', 'Ή'),
'I' => array('Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į',
'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ',
'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї'),
'K' => array('К', 'Κ'),
'L' => array('Ĺ', 'Ł', 'Л', 'Λ', 'Ļ'),
'M' => array('М', 'Μ'),
'N' => array('Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'),
'O' => array('Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ',
'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ö', 'Ø', 'Ō',
'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ',
'Ὸ', 'Ό', 'О', 'Θ', 'Ө'),
'P' => array('П', 'Π'),
'R' => array('Ř', 'Ŕ', 'Р', 'Ρ'),
'S' => array('Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'),
'T' => array('Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'),
'U' => array('Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ',
'Ự', 'Û', 'Ü', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У'),
'V' => array('В'),
'W' => array('Ω', 'Ώ'),
'X' => array('Χ'),
'Y' => array('Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ',
'Ы', 'Й', 'Υ', 'Ϋ'),
'Z' => array('Ź', 'Ž', 'Ż', 'З', 'Ζ'),
'AE' => array('Æ'),
'CH' => array('Ч'),
'DJ' => array('Ђ'),
'DZ' => array('Џ'),
'KH' => array('Х'),
'LJ' => array('Љ'),
'NJ' => array('Њ'),
'PS' => array('Ψ'),
'SH' => array('Ш'),
'SHCH' => array('Щ'),
'SS' => array('ẞ'),
'TH' => array('Þ'),
'TS' => array('Ц'),
'YA' => array('Я'),
'YU' => array('Ю'),
'ZH' => array('Ж'),
' ' => array("\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81",
"\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84",
"\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87",
"\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A",
"\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"),
);
}
}

5
libs/Exception.php Normal file
View File

@ -0,0 +1,5 @@
<?php namespace Todaymade\Daux;
class Exception extends \Exception
{
}

View File

@ -0,0 +1,38 @@
<?php namespace Todaymade\Daux\Format\Base\CommonMark;
use League\CommonMark\DocParser;
use League\CommonMark\Environment;
use League\CommonMark\HtmlRenderer;
class CommonMarkConverter extends \League\CommonMark\CommonMarkConverter
{
/**
* Create a new commonmark converter instance.
*
* @param array $config
*/
public function __construct(array $config = array())
{
$environment = Environment::createCommonMarkEnvironment();
$environment->mergeConfig($config);
$this->extendEnvironment($environment);
if (array_key_exists('processor_instance', $config['daux'])) {
$config['daux']['processor_instance']->extendCommonMarkEnvironment($environment);
}
$this->docParser = new DocParser($environment);
$this->htmlRenderer = new HtmlRenderer($environment);
}
protected function getLinkRenderer(Environment $environment)
{
return new LinkRenderer($environment->getConfig('daux'));
}
protected function extendEnvironment(Environment $environment)
{
$environment->addInlineRenderer('Link', $this->getLinkRenderer($environment));
}
}

View File

@ -0,0 +1,74 @@
<?php namespace Todaymade\Daux\Format\Base\CommonMark;
use League\CommonMark\HtmlElement;
use League\CommonMark\HtmlRendererInterface;
use League\CommonMark\Inline\Element\AbstractInline;
use League\CommonMark\Inline\Element\Link;
use Todaymade\Daux\Config;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Exception;
use Todaymade\Daux\Tree\Entry;
class LinkRenderer extends \League\CommonMark\Inline\Renderer\LinkRenderer
{
/**
* @var Config
*/
protected $daux;
public function __construct($daux)
{
$this->daux = $daux;
}
/**
* @param string $url
* @return Entry
* @throws Exception
*/
protected function resolveInternalFile($url)
{
$file = DauxHelper::getFile($this->daux['tree'], $url);
if ($file) {
return $file;
}
$file = DauxHelper::getFile($this->daux['tree'], $url . '.html');
if ($file) {
return $file;
}
throw new Exception("Could not locate file '$url'");
}
/**
* @param Link $inline
* @param HtmlRendererInterface $htmlRenderer
*
* @return HtmlElement
*/
public function render(AbstractInline $inline, HtmlRendererInterface $htmlRenderer)
{
// This can't be in the method type as
// the method is an abstract and should
// have the same interface
if (!$inline instanceof Link) {
throw new \RuntimeException(
"Wrong type passed to " . __CLASS__ . "::" . __METHOD__ .
" the expected type was 'League\\CommonMark\\Inline\\Element\\Link' but '" .
get_class($inline) . "' was provided"
);
}
$element = parent::render($inline, $htmlRenderer);
$url = $inline->getUrl();
if (!empty($url) && $url[0] == '!') {
$file = $this->resolveInternalFile(ltrim($url, "!"));
$element->setAttribute('href', $this->daux['base_url'] . $file->getUrl());
}
return $element;
}
}

View File

@ -0,0 +1,21 @@
<?php namespace Todaymade\Daux\Format\Base;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Daux;
interface Generator
{
/**
* @param Daux $daux
*/
public function __construct(Daux $daux);
/**
* @param InputInterface $input
* @param OutputInterface $output
* @param integer $width
* @return mixed
*/
public function generateAll(InputInterface $input, OutputInterface $output, $width);
}

View File

@ -0,0 +1,14 @@
<?php namespace Todaymade\Daux\Format\Base;
use Todaymade\Daux\Config;
use Todaymade\Daux\Tree\Entry;
interface LiveGenerator
{
/**
* @param Entry $node
* @param Config $params
* @return \Todaymade\Daux\Format\Base\Page
*/
public function generateOne(Entry $node, Config $params);
}

View File

@ -0,0 +1,68 @@
<?php namespace Todaymade\Daux\Format\Base;
use League\CommonMark\CommonMarkConverter;
use Todaymade\Daux\Config;
use Todaymade\Daux\Tree\Content;
abstract class MarkdownPage extends SimplePage
{
/**
* @var Content
*/
protected $file;
/**
* @var Config
*/
protected $params;
/**
* @var CommonMarkConverter
*/
protected $converter;
public function __construct($title, $content)
{
$this->initializePage($title, $content);
}
public function setFile(Content $file)
{
$this->file = $file;
}
public function getFile()
{
return $this->file;
}
public function setParams(Config $params)
{
$this->params = $params;
}
protected function getMarkdownConverter()
{
return $this->converter;
}
protected function convertPage($content)
{
return $this->getMarkdownConverter()->convertToHtml($content);
}
protected function generatePage()
{
return $this->convertPage($this->content);
}
public static function fromFile(Content $file, $params, CommonMarkConverter $converter)
{
$page = new static($file->getTitle(), $file->getContent());
$page->setFile($file);
$page->setParams($params);
$page->converter = $converter;
return $page;
}
}

View File

@ -0,0 +1,6 @@
<?php namespace Todaymade\Daux\Format\Base;
interface Page
{
public function getContent();
}

View File

@ -0,0 +1,23 @@
<?php namespace Todaymade\Daux\Format\Base;
use Todaymade\Daux\Exception;
abstract class RawPage implements Page
{
protected $file;
public function __construct($filename)
{
$this->file = $filename;
}
public function getFile()
{
return $this->file;
}
public function getContent()
{
throw new Exception("you should not use this method to show a raw content");
}
}

View File

@ -0,0 +1,22 @@
<?php namespace Todaymade\Daux\Format\Base;
use Symfony\Component\Console\Output\OutputInterface;
trait RunAction
{
protected function runAction($title, OutputInterface $output, $width, \Closure $closure)
{
$output->write($title);
// 8 is the length of the label + 2 let it breathe
$padding = $width - strlen($title) - 10;
try {
$response = $closure();
} catch (\Exception $e) {
$output->writeln(str_pad(" ", $padding) . "[ <fg=red>FAIL</fg=red> ]");
throw $e;
}
$output->writeln(str_pad(" ", $padding) . "[ <fg=green>OK</fg=green> ]");
return $response;
}
}

View File

@ -0,0 +1,33 @@
<?php namespace Todaymade\Daux\Format\Base;
abstract class SimplePage implements Page
{
protected $title;
protected $content;
protected $generated = null;
public function __construct($title, $content)
{
$this->initializePage($title, $content);
}
public function getContent()
{
if (is_null($this->generated)) {
$this->generated = $this->generatePage();
}
return $this->generated;
}
protected function initializePage($title, $content)
{
$this->title = $title;
$this->content = $content;
}
protected function generatePage()
{
return $this->content;
}
}

View File

@ -0,0 +1,219 @@
<?php namespace Todaymade\Daux\Format\Confluence;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\ParseException;
class Api
{
protected $base_url;
protected $user;
protected $pass;
protected $space;
public function __construct($base_url, $user, $pass)
{
$this->base_url = $base_url;
$this->user = $user;
$this->pass = $pass;
}
public function setSpace($space_id)
{
$this->space = $space_id;
}
protected function getClient()
{
$options = [
'base_url' => $this->base_url . 'rest/api/',
'defaults' => [
'auth' => [$this->user, $this->pass]
]
];
return new Client($options);
}
/**
* The standard error message from guzzle is quite poor in informations,
* this will give little bit more sense to it and return it
*
* @param BadResponseException $e
* @return BadResponseException
*/
protected function handleError(BadResponseException $e)
{
$request = $e->getRequest();
$response = $e->getResponse();
$level = floor($response->getStatusCode() / 100);
if ($level == '4') {
$label = 'Client error response';
} elseif ($level == '5') {
$label = 'Server error response';
} else {
$label = 'Unsuccessful response';
}
$message = $label .
' [url] ' . $request->getUrl() .
' [status code] ' . $response->getStatusCode() .
' [message] ';
try {
$message .= $response->json()['message'];
} catch (ParseException $e) {
$message .= (string) $response->getBody();
}
return new BadResponseException($message, $request, $response, $e->getPrevious());
}
/**
* Get a list of pages
*
* @param integer $rootPage
* @param bool $recursive
* @return array
*/
public function getList($rootPage, $recursive = false)
{
$increment = 15;
// We set a limit of 15 as it appears that
// Confluence fails silently when retrieving
// more than 20 entries with "body.storage"
$base_url = $url = "content/$rootPage/child/page?expand=version,body.storage&limit=$increment";
$start = 0;
$pages = [];
do {
try {
$hierarchy = $this->getClient()->get($url)->json();
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
foreach ($hierarchy['results'] as $result) {
$pages[$result['title']] = [
"id" => $result['id'],
"title" => $result['title'],
"version" => $result['version']['number'],
"content" => $result['body']['storage']['value'],
];
if ($recursive) {
$pages[$result['title']]['children'] = $this->getList($result['id'], true);
}
}
// We don't use _links->next as after ~30 elements
// it doesn't show any new elements. This seems
// to be a bug in Confluence
$start += $increment;
$url = "$base_url&start=$start";
} while (!empty($hierarchy['results']));
return $pages;
}
/**
* @param integer $parent_id
* @param string $title
* @param string $content
* @return integer
*/
public function createPage($parent_id, $title, $content)
{
$body = [
'type' => 'page',
'space' => ['key' => $this->space],
'ancestors' => [['type' => 'page', 'id' => $parent_id]],
'title' => $title,
'body' => ['storage' => ['value' => $content, 'representation' => 'storage']]
];
try {
$response = $this->getClient()->post('content', ['json' => $body])->json();
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
return $response['id'];
}
/**
* @param integer $parent_id
* @param integer $page_id
* @param integer $newVersion
* @param string $title
* @param string $content
*/
public function updatePage($parent_id, $page_id, $newVersion, $title, $content)
{
$body = [
'type' => 'page',
'space' => ['key' => $this->space],
'ancestors' => [['type' => 'page', 'id' => $parent_id]],
'version' => ['number' => $newVersion, "minorEdit" => false],
'title' => $title,
'body' => ['storage' => ['value' => $content, 'representation' => 'storage']]
];
try {
$this->getClient()->put("content/$page_id", ['json' => $body])->json();
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
}
/**
* Delete a page
*
* @param integer $page_id
* @return mixed
*/
public function deletePage($page_id)
{
try {
return $this->getClient()->delete('content/' . $page_id)->json();
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
}
/**
* @param integer $id
* @param array $attachment
*/
public function uploadAttachment($id, $attachment)
{
//get if attachment is uploaded
try {
$result = $this->getClient()->get("content/$id/child/attachment?filename=$attachment[filename]")->json();
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
$url = "content/$id/child/attachment" . count($result['results']) ? "/{$result['results'][0]['id']}/data" : "";
try {
$this->getClient()->post(
$url,
[
'body' => ['file' => fopen($attachment['file']->getPath(), 'r')],
'headers' => ['X-Atlassian-Token' => 'nocheck'],
]
);
} catch (BadResponseException $e) {
throw $this->handleError($e);
}
//FIXME :: When doing an update, Confluence does a null pointer exception
}
}

View File

@ -0,0 +1,20 @@
<?php namespace Todaymade\Daux\Format\Confluence\CommonMark;
use League\CommonMark\Environment;
class CommonMarkConverter extends \Todaymade\Daux\Format\Base\CommonMark\CommonMarkConverter
{
protected function getLinkRenderer(Environment $environment)
{
return new LinkRenderer($environment->getConfig('daux'));
}
protected function extendEnvironment(Environment $environment)
{
parent::extendEnvironment($environment);
//Add code renderer
$environment->addBlockRenderer('FencedCode', new FencedCodeRenderer());
$environment->addBlockRenderer('IndentedCode', new IndentedCodeRenderer());
}
}

View File

@ -0,0 +1,85 @@
<?php namespace Todaymade\Daux\Format\Confluence\CommonMark;
use League\CommonMark\Block\Element\AbstractBlock;
use League\CommonMark\Block\Element\FencedCode;
use League\CommonMark\Block\Renderer\BlockRendererInterface;
use League\CommonMark\HtmlElement;
use League\CommonMark\HtmlRendererInterface;
class FencedCodeRenderer implements BlockRendererInterface
{
protected $supported_languages = [
'actionscript3',
'bash',
'csharp',
'coldfusion',
'cpp',
'css',
'delphi',
'diff',
'erlang',
'groovy',
'html/xml',
'java',
'javafx',
'javascript',
'none',
'perl',
'php',
'powershell',
'python',
'ruby',
'scala',
'sql',
'vb'
];
protected $known_conversions = ['html' => 'html/xml', 'xml' => 'html/xml', 'js' => 'javascript'];
/**
* @param AbstractBlock $block
* @param HtmlRendererInterface $htmlRenderer
* @param bool $inTightList
*
* @return HtmlElement|string
*/
public function render(AbstractBlock $block, HtmlRendererInterface $htmlRenderer, $inTightList = false)
{
if (!($block instanceof FencedCode)) {
throw new \InvalidArgumentException('Incompatible block type: ' . get_class($block));
}
$content = [];
if ($language = $this->getLanguage($block->getInfoWords(), $htmlRenderer)) {
$content[] = new HtmlElement('ac:parameter', ['ac:name' => 'language'], $language);
}
$content[] = new HtmlElement('ac:plain-text-body', [], '<![CDATA[' . $block->getStringContent() . ']]>');
return new HtmlElement(
'ac:structured-macro',
['ac:name' => 'code'],
$content
);
}
public function getLanguage($infoWords, HtmlRendererInterface $htmlRenderer)
{
if (count($infoWords) === 0 || strlen($infoWords[0]) === 0) {
return false;
}
$language = $htmlRenderer->escape($infoWords[0], true);
if (array_key_exists($language, $this->known_conversions)) {
$language = $this->known_conversions[$language];
}
if (in_array($language, $this->supported_languages)) {
return $language;
}
return false;
}
}

View File

@ -0,0 +1,30 @@
<?php namespace Todaymade\Daux\Format\Confluence\CommonMark;
use League\CommonMark\Block\Element\AbstractBlock;
use League\CommonMark\Block\Element\IndentedCode;
use League\CommonMark\Block\Renderer\BlockRendererInterface;
use League\CommonMark\HtmlElement;
use League\CommonMark\HtmlRendererInterface;
class IndentedCodeRenderer implements BlockRendererInterface
{
/**
* @param AbstractBlock $block
* @param HtmlRendererInterface $htmlRenderer
* @param bool $inTightList
*
* @return HtmlElement
*/
public function render(AbstractBlock $block, HtmlRendererInterface $htmlRenderer, $inTightList = false)
{
if (!($block instanceof IndentedCode)) {
throw new \InvalidArgumentException('Incompatible block type: ' . get_class($block));
}
return new HtmlElement(
'ac:structured-macro',
['ac:name' => 'code'],
new HtmlElement('ac:plain-text-body', [], '<![CDATA[' . $block->getStringContent() . ']]>')
);
}
}

View File

@ -0,0 +1,54 @@
<?php namespace Todaymade\Daux\Format\Confluence\CommonMark;
use League\CommonMark\HtmlElement;
use League\CommonMark\HtmlRendererInterface;
use League\CommonMark\Inline\Element\AbstractInline;
use League\CommonMark\Inline\Element\Link;
class LinkRenderer extends \Todaymade\Daux\Format\Base\CommonMark\LinkRenderer
{
/**
* @param Link $inline
* @param HtmlRendererInterface $htmlRenderer
*
* @return HtmlElement
*/
public function render(AbstractInline $inline, HtmlRendererInterface $htmlRenderer)
{
// This can't be in the method type as
// the method is an abstract and should
// have the same interface
if (!$inline instanceof Link) {
throw new \RuntimeException(
"Wrong type passed to " . __CLASS__ . "::" . __METHOD__ .
" the expected type was 'League\\CommonMark\\Inline\\Element\\Link' but '" .
get_class($inline) . "' was provided"
);
}
// Default handling
$element = parent::render($inline, $htmlRenderer);
$url = $inline->getUrl();
if (empty($url) || $url[0] != '!') {
return $element;
}
//Internal links
$file = $this->resolveInternalFile(ltrim($url, "!"));
$link_props = [
'ri:content-title' => trim($this->daux['confluence']['prefix']) . " " . $file->getTitle(),
'ri:space-key' => $this->daux['confluence']['space_id']
];
$page = strval(new HtmlElement('ri:page', $link_props, '', true));
$children = $htmlRenderer->renderInlines($inline->getChildren());
if (strpos($children, "<") !== false) {
$children = '<ac:link-body>' . $children . '</ac:link-body>';
} else {
$children = '<ac:plain-text-link-body><![CDATA[' . $children . ']]></ac:plain-text-link-body>';
}
return new HtmlElement('ac:link', [], $page . $children);
}
}

View File

@ -0,0 +1,105 @@
<?php namespace Todaymade\Daux\Format\Confluence;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Config;
use Todaymade\Daux\Daux;
use Todaymade\Daux\Format\Confluence\CommonMark\CommonMarkConverter;
use Todaymade\Daux\Format\Base\RunAction;
use Todaymade\Daux\Tree\Content;
use Todaymade\Daux\Tree\Directory;
class Generator implements \Todaymade\Daux\Format\Base\Generator
{
use RunAction;
/** @var string */
protected $prefix;
/** @var CommonMarkConverter */
protected $converter;
/** @var Daux */
protected $daux;
/**
* @param Daux $daux
*/
public function __construct(Daux $daux)
{
$this->daux = $daux;
$this->converter = new CommonMarkConverter(['daux' => $this->daux->getParams()]);
}
/**
* {@inheritdoc}
*/
public function generateAll(InputInterface $input, OutputInterface $output, $width)
{
$params = $this->daux->getParams();
$confluence = $params['confluence'];
$this->prefix = trim($confluence['prefix']) . " ";
$tree = $this->runAction(
"Generating Tree ...",
$output,
$width,
function() use ($params) {
$tree = $this->generateRecursive($this->daux->tree, $params);
$tree['title'] = $this->prefix . $params['title'];
return $tree;
}
);
$output->writeln("Start Publishing...");
$publisher = new Publisher($confluence);
$publisher->output = $output;
$publisher->width = $width;
$publisher->publish($tree);
}
private function generateRecursive(Directory $tree, Config $params, $base_url = '')
{
$final = ['title' => $this->prefix . $tree->getTitle()];
$params['base_url'] = $params['base_page'] = $base_url;
$params['image'] = str_replace('<base_url>', $base_url, $params['image']);
if ($base_url !== '') {
$params['entry_page'] = $tree->getFirstPage();
}
foreach ($tree->getEntries() as $key => $node) {
if ($node instanceof Directory) {
$final['children'][$this->prefix . $node->getTitle()] = $this->generateRecursive(
$node,
$params,
'../' . $base_url
);
} elseif ($node instanceof Content) {
$params['request'] = $node->getUrl();
$data = [
'title' => $this->prefix . $node->getTitle(),
'file' => $node,
'page' => MarkdownPage::fromFile($node, $params, $this->converter),
];
// As the page is lazily generated
// We do it now to fail fast in case of problem
$data['page']->getContent();
if ($key == 'index.html') {
$final['title'] = $this->prefix . $tree->getTitle();
$final['file'] = $node;
$final['page'] = $data['page'];
} else {
$final['children'][$data['title']] = $data;
}
}
}
return $final;
}
}

View File

@ -0,0 +1,88 @@
<?php namespace Todaymade\Daux\Format\Confluence;
use DOMDocument;
use Todaymade\Daux\DauxHelper;
class MarkdownPage extends \Todaymade\Daux\Format\Base\MarkdownPage
{
public $attachments = [];
protected function generatePage()
{
$page = parent::generatePage();
//Embed images
// We do it after generation so we can catch the images that were in html already
$page = preg_replace_callback(
"/<img\\s+[^>]*src=['\"]([^\"]*)['\"][^>]*>/",
function($matches) {
if ($result = $this->findImage($matches[1], $matches[0])) {
return $result;
}
return $matches[0];
},
$page
);
return $page;
}
private function findImage($src, $tag)
{
//for protocol relative or http requests : keep the original one
if (substr($src, 0, strlen("http")) === "http" || substr($src, 0, strlen("//")) === "//") {
return $src;
}
//Get the path to the file, relative to the root of the documentation
$url = DauxHelper::getCleanPath(dirname($this->file->getUrl()) . '/' . $src);
//Get any file corresponding to the right one
$file = DauxHelper::getFile($this->params['tree'], $url);
if ($file === false) {
return false;
}
$filename = basename($file->getPath());
//Add the attachment for later upload
$this->attachments[] = ['filename' => $filename, 'file' => $file];
return $this->createImageTag($filename, $this->getAttributes($tag));
}
private function getAttributes($tag)
{
$dom = new DOMDocument();
$dom->loadHTML($tag);
$img = $dom->getElementsByTagName('img')[0];
$attributes = ['align', 'class', 'title', 'style', 'alt', 'height', 'width'];
$used = [];
foreach ($attributes as $attr) {
if ($img->attributes->getNamedItem($attr)) {
$used[$attr] = $img->attributes->getNamedItem($attr)->value;
}
}
return $used;
}
private function createImageTag($filename, $attributes)
{
$img = "<ac:image";
foreach ($attributes as $name => $value) {
$img .= ' ac:' . $name . '="' . htmlentities($value, ENT_QUOTES, 'UTF-8', false) . '"';
}
$img .= "><ri:attachment ri:filename=\"$filename\" /></ac:image>";
return $img;
}
}

View File

@ -0,0 +1,245 @@
<?php namespace Todaymade\Daux\Format\Confluence;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\ParseException;
use Todaymade\Daux\Format\Base\RunAction;
class Publisher
{
use RunAction;
/**
* @var Api
*/
protected $client;
/**
* @var array
*/
protected $confluence;
/**
* @var string
*/
protected $previous_title;
/**
* @var integer terminal width
*/
public $width;
/**
* @var
*/
public $output;
/**
* @param $confluence
*/
public function __construct($confluence)
{
$this->confluence = $confluence;
$this->client = new Api($confluence['base_url'], $confluence['user'], $confluence['pass']);
$this->client->setSpace($confluence['space_id']);
}
public function run($title, $closure)
{
try {
return $this->runAction($title, $this->output, $this->width, $closure);
} catch (BadResponseException $e) {
$this->output->writeLn(" <error>" . $e->getMessage() . "</error>");
}
}
public function publish(array $tree)
{
echo "Finding Root Page...\n";
$pages = $this->client->getList($this->confluence['ancestor_id']);
$published = null;
foreach ($pages as $page) {
if ($page['title'] == $tree['title']) {
$published = $page;
break;
}
}
$this->run(
"Getting already published pages...",
function() use (&$published) {
if ($published != null) {
$published['children'] = $this->client->getList($published['id'], true);
}
}
);
$published = $this->run(
"Create placeholder pages...",
function() use ($tree, $published) {
return $this->createRecursive($this->confluence['ancestor_id'], $tree, $published);
}
);
$this->output->writeLn("Publishing updates...");
$this->updateRecursive($this->confluence['ancestor_id'], $tree, $published);
}
protected function niceTitle($title)
{
if ($title == "index.html") {
return "Homepage";
}
return rtrim(strtr($title, ['index.html' => '', '.html' => '']), "/");
}
protected function createPage($parent_id, $entry, $published)
{
echo "- " . $this->niceTitle($entry['file']->getUrl()) . "\n";
$published['version'] = 1;
$published['id'] = $this->client->createPage($parent_id, $entry['title'], "The content will come very soon !");
return $published;
}
protected function createPlaceholderPage($parent_id, $entry, $published)
{
echo "- " . $entry['title'] . "\n";
$published['version'] = 1;
$published['id'] = $this->client->createPage($parent_id, $entry['title'], "");
return $published;
}
protected function recursiveWithCallback($parent_id, $entry, $published, $callback)
{
$published = $callback($parent_id, $entry, $published);
if (array_key_exists('children', $entry)) {
foreach ($entry['children'] as $child) {
$pub = [];
if (isset($published['children']) && array_key_exists($child['title'], $published['children'])) {
$pub = $published['children'][$child['title']];
}
$published['children'][$child['title']] = $this->recursiveWithCallback(
$published['id'],
$child,
$pub,
$callback
);
}
}
return $published;
}
protected function createRecursive($parent_id, $entry, $published)
{
$callback = function($parent_id, $entry, $published) {
//TODO :: remove deleted pages
// nothing to do if the ID already exists
if (array_key_exists('id', $published)) {
return $published;
}
if (array_key_exists('page', $entry)) {
return $this->createPage($parent_id, $entry, $published);
}
// If we have no $entry['page'] it means the page
// doesn't exist, but to respect the hierarchy,
// we need a blank page there
return $this->createPlaceholderPage($parent_id, $entry, $published);
};
return $this->recursiveWithCallback($parent_id, $entry, $published, $callback);
}
protected function updateRecursive($parent_id, $entry, $published)
{
$callback = function($parent_id, $entry, $published) {
if (array_key_exists('id', $published) && array_key_exists('page', $entry)) {
$this->updatePage($parent_id, $entry, $published);
}
return $published;
};
return $this->recursiveWithCallback($parent_id, $entry, $published, $callback);
}
protected function shouldUpdate($local, $published)
{
if (!array_key_exists('content', $published)) {
return true;
}
$trimmed_local = trim($local->getContent());
$trimmed_distant = trim($published['content']);
if ($trimmed_local == $trimmed_distant) {
return false;
}
similar_text($trimmed_local, $trimmed_distant, $percent);
// I consider that if the files are 98% identical you
// don't need to update. This will work for false positives.
// But sadly will miss if it's just a typo update
if ($percent >= 98) {
return false;
}
//DEBUG
if (getenv("DEBUG") && strtolower(getenv("DEBUG")) != "false") {
$prefix = 'static/export/';
if (!is_dir($prefix)) {
mkdir($prefix, 0777, true);
}
$url = $local->getFile()->getUrl();
file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_local.html']), $trimmed_local);
file_put_contents($prefix . strtr($url, ['/' => '_', '.html' => '_distant.html']), $trimmed_distant);
}
return true;
}
protected function updatePage($parent_id, $entry, $published)
{
if ($this->previous_title != "Updating") {
$this->previous_title = "Updating";
echo "Updating Pages...\n";
}
$this->run(
"- " . $this->niceTitle($entry['file']->getUrl()),
function() use ($entry, $published, $parent_id) {
if ($this->shouldUpdate($entry['page'], $published)) {
$this->client->updatePage(
$parent_id,
$published['id'],
$published['version'] + 1,
$entry['title'],
$entry['page']->getContent()
);
}
}
);
if (count($entry['page']->attachments)) {
foreach ($entry['page']->attachments as $attachment) {
$this->run(
" With attachment: $attachment[filename]",
function() use ($published, $attachment) {
$this->client->uploadAttachment($published['id'], $attachment);
}
);
}
}
}
}

View File

@ -0,0 +1,118 @@
<?php namespace Todaymade\Daux\Format\HTML;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Config;
use Todaymade\Daux\Daux;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Format\Base\CommonMark\CommonMarkConverter;
use Todaymade\Daux\Format\Base\LiveGenerator;
use Todaymade\Daux\Format\Base\RunAction;
use Todaymade\Daux\Generator\Helper;
use Todaymade\Daux\Tree\Content;
use Todaymade\Daux\Tree\Directory;
use Todaymade\Daux\Tree\Entry;
use Todaymade\Daux\Tree\Raw;
class Generator implements \Todaymade\Daux\Format\Base\Generator, LiveGenerator
{
use RunAction;
/** @var CommonMarkConverter */
protected $converter;
/** @var Daux */
protected $daux;
/**
* @param Daux $daux
*/
public function __construct(Daux $daux)
{
$this->daux = $daux;
$this->converter = new CommonMarkConverter(['daux' => $this->daux->getParams()]);
}
public function generateAll(InputInterface $input, OutputInterface $output, $width)
{
$destination = $input->getOption('destination');
$params = $this->daux->getParams();
if (is_null($destination)) {
$destination = $this->daux->local_base . DIRECTORY_SEPARATOR . 'static';
}
$this->runAction(
"Copying Static assets ...",
$output,
$width,
function() use ($destination) {
Helper::copyAssets($destination, $this->daux->local_base);
}
);
$output->writeLn("Generating ...");
$this->generateRecursive($this->daux->tree, $destination, $params, $output, $width);
}
/**
* Recursively generate the documentation
*
* @param Directory $tree
* @param string $output_dir
* @param \Todaymade\Daux\Config $params
* @param OutputInterface $output
* @param integer $width
* @param string $base_url
* @throws \Exception
*/
private function generateRecursive(Directory $tree, $output_dir, $params, $output, $width, $base_url = '')
{
DauxHelper::rebaseConfiguration($params, $base_url);
if ($base_url !== '' && empty($params['entry_page'])) {
$params['entry_page'] = $tree->getFirstPage();
}
foreach ($tree->getEntries() as $key => $node) {
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);
// Rebase configuration again as $params is a shared object
DauxHelper::rebaseConfiguration($params, $base_url);
} else {
$this->runAction(
"- " . $node->getUrl(),
$output,
$width,
function() use ($node, $output_dir, $key, $params) {
if (!$node instanceof Content) {
copy($node->getPath(), $output_dir . DIRECTORY_SEPARATOR . $key);
return;
}
$generated = $this->generateOne($node, $params);
file_put_contents($output_dir . DIRECTORY_SEPARATOR . $key, $generated->getContent());
}
);
}
}
}
/**
* @param Entry $node
* @param Config $params
* @return \Todaymade\Daux\Format\Base\Page
*/
public function generateOne(Entry $node, Config $params)
{
if ($node instanceof Raw) {
return new RawPage($node->getPath());
}
$params['request'] = $node->getUrl();
return MarkdownPage::fromFile($node, $params, $this->converter);
}
}

View File

@ -0,0 +1,88 @@
<?php namespace Todaymade\Daux\Format\HTML;
use Todaymade\Daux\Tree\Root;
class MarkdownPage extends \Todaymade\Daux\Format\Base\MarkdownPage
{
private $language;
private $homepage;
private function initialize()
{
$this->homepage = false;
if ($this->file->getParent()->getIndexPage() == $this->file) {
if ($this->params['multilanguage']) {
if ($this->file->getParent()->getParent() instanceof Root) {
$this->homepage = true;
}
} elseif ($this->file->getParent() instanceof Root) {
$this->homepage = true;
}
}
$this->language = '';
if ($this->params['multilanguage'] && count($this->file->getParents())) {
$language_dir = $this->file->getParents()[0];
$this->language = $language_dir->getName();
}
}
/**
* @param \Todaymade\Daux\Tree\Directory[] $parents
* @param bool $multilanguage
* @return array
*/
private function getBreadcrumbTrail($parents, $multilanguage)
{
if ($multilanguage && !empty($parents)) {
$parents = array_splice($parents, 1);
}
$breadcrumb_trail = array();
if (!empty($parents)) {
foreach ($parents as $node) {
$page = $node->getIndexPage() ?: $node->getFirstPage();
$breadcrumb_trail[$node->getTitle()] = $page? $page->getUrl() : '';
}
}
return $breadcrumb_trail;
}
protected function generatePage()
{
$this->initialize();
$params = $this->params;
$entry_page = [];
if ($this->homepage) {
if ($params['multilanguage']) {
foreach ($params['languages'] as $key => $name) {
$entry_page[$name] = $params['base_page'] . $params['entry_page'][$key]->getUrl();
}
} else {
$entry_page['View Documentation'] = $params['base_page'] . $params['entry_page']->getUrl();
}
}
$page = [
'entry_page' => $entry_page,
'homepage' => $this->homepage,
'title' => $this->file->getTitle(),
'filename' => $this->file->getName(),
'language' => $this->language,
'path' => $this->file->getPath(),
'modified_time' => filemtime($this->file->getPath()),
'markdown' => $this->content,
'request' => $params['request'],
'content' => $this->convertPage($this->content),
'breadcrumbs' => $params['html']['breadcrumbs']
];
if ($page['breadcrumbs']) {
$page['breadcrumb_trail'] = $this->getBreadcrumbTrail($this->file->getParents(), $params['multilanguage']);
$page['breadcrumb_separator'] = $params['html']['breadcrumb_separator'];
}
$template = new Template($params['templates'], $params['theme']['templates']);
return $template->render($this->homepage ? 'home' : 'content', ['page' => $page, 'params' => $params]);
}
}

View File

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

View File

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

View File

@ -0,0 +1,149 @@
<?php namespace Todaymade\Daux\Format\HTML;
use League\Plates\Engine;
use Todaymade\Daux\Daux;
use Todaymade\Daux\Tree\Content;
use Todaymade\Daux\Tree\Directory;
class Template
{
protected $engine;
/**
* @param string $base
* @param string $theme
*/
public function __construct($base, $theme)
{
// Create new Plates instance
$this->engine = new Engine($base);
if (!is_dir($theme)) {
$theme = $base;
}
$this->engine->addFolder('theme', $theme, true);
$this->registerFunctions();
}
/**
* @param string $name
* @param array $data
* @return string
*/
public function render($name, array $data = array())
{
$this->engine->addData([
'base_url' => $data['params']['base_url'],
'base_page' => $data['params']['base_page'],
'page' => $data['page'],
'params' => $data['params'],
'tree' => $data['params']['tree'],
]);
return $this->engine->render($name, $data);
}
protected function registerFunctions()
{
$this->engine->registerFunction('get_navigation', function($tree, $path, $current_url, $base_page, $mode) {
$nav = $this->buildNavigation($tree, $path, $current_url, $base_page, $mode);
return $this->renderNavigation($nav);
});
$this->engine->registerFunction('get_breadcrumb_title', function($page, $base_page) {
$title = '';
$breadcrumb_trail = $page['breadcrumb_trail'];
$separator = $this->getSeparator($page['breadcrumb_separator']);
foreach ($breadcrumb_trail as $key => $value) {
$title .= '<a href="' . $base_page . $value . '">' . $key . '</a>' . $separator;
}
if ($page['filename'] === 'index' || $page['filename'] === '_index') {
if ($page['title'] != '') {
$title = substr($title, 0, -1 * strlen($separator));
}
} else {
$title .= '<a href="' . $base_page . $page['request'] . '">' . $page['title'] . '</a>';
}
return $title;
});
}
private function renderNavigation($entries)
{
$nav = "";
foreach ($entries as $entry) {
if (array_key_exists('children', $entry)) {
if (array_key_exists('href', $entry)) {
$link = '<a href="' . $entry['href'] . '" class="folder">' . $entry['title'] . '</a>';
} else {
$link = '<a href="#" class="aj-nav folder">' . $entry['title'] . '</a>';
}
$link .= $this->renderNavigation($entry['children']);
} else {
$link = '<a href="' . $entry['href'] . '">' . $entry['title'] . '</a>';
}
$nav .= "<li class='$entry[class]'>$link</li>";
}
return "<ul class='nav nav-list'>$nav</ul>";
}
private function buildNavigation(Directory $tree, $path, $current_url, $base_page, $mode)
{
$nav = [];
foreach ($tree->getEntries() as $node) {
$url = $node->getUri();
if ($node instanceof Content) {
if (in_array($node->getName(), ['index', '_index'])) {
continue;
}
$link = ($path === '') ? $url : $path . '/' . $url;
$nav[] = [
'title' => $node->getTitle(),
'href' => $base_page . $link,
'class' => ($current_url === $link) ? 'active' : ''
];
} elseif ($node instanceof Directory) {
$link = ($path === '') ? $url : $path . '/' . $url;
$folder = [
'title' => $node->getTitle(),
'class' => (strpos($current_url, $link) === 0) ? 'open' : '',
];
if ($mode === Daux::STATIC_MODE) {
$link .= "/index.html";
}
if ($node->getIndexPage()) {
$folder['href'] = $base_page . $link;
}
//Child pages
$new_path = ($path === '') ? $url : $path . '/' . $url;
$folder['children'] = $this->buildNavigation($node, $new_path, $current_url, $base_page, $mode);
$nav[] = $folder;
}
}
return $nav;
}
/**
* @param string $separator
* @return string
*/
private function getSeparator($separator)
{
switch ($separator) {
case 'Chevrons':
return ' <i class="glyphicon glyphicon-chevron-right"></i> ';
default:
return $separator;
}
}
}

View File

@ -0,0 +1,49 @@
<?php namespace Todaymade\Daux\Generator;
use Symfony\Component\Console\Application as SymfonyApplication;
use Symfony\Component\Console\Input\InputInterface;
class Application extends SymfonyApplication
{
/**
* Gets the name of the command based on input.
*
* @param InputInterface $input The input interface
*
* @return string The command name
*/
protected function getCommandName(InputInterface $input)
{
// This should return the name of your command.
return 'generate';
}
/**
* Gets the default commands that should always be available.
*
* @return array An array of default Command instances
*/
protected function getDefaultCommands()
{
// Keep the core default commands to have the HelpCommand
// which is used when using the --help option
$defaultCommands = parent::getDefaultCommands();
$defaultCommands[] = new Command();
return $defaultCommands;
}
/**
* Overridden so that the application doesn't expect the command
* name to be the first argument.
*/
public function getDefinition()
{
$inputDefinition = parent::getDefinition();
// clear out the normal first argument, which is the command name
$inputDefinition->setArguments();
return $inputDefinition;
}
}

View File

@ -0,0 +1,58 @@
<?php namespace Todaymade\Daux\Generator;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Daux;
class Command extends SymfonyCommand
{
protected function configure()
{
$description = 'Destination folder, relative to the working directory';
$this
->setName('generate')
->setDescription('Generate documentation')
->addOption('configuration', 'c', InputArgument::OPTIONAL, 'Configuration file')
->addOption('format', 'f', InputArgument::OPTIONAL, 'Output format, html or confluence', 'html')
->addOption('processor', 'p', InputArgument::OPTIONAL, 'Manipulations on the tree')
->addOption('destination', 'd', InputArgument::OPTIONAL, $description, 'static');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$daux = new Daux(Daux::STATIC_MODE);
$daux->initialize($input->getOption('configuration'));
$width = $this->getApplication()->getTerminalDimensions()[0];
// Instiantiate the processor if one is defined
$this->prepareProcessor($daux, $input, $output, $width);
// Generate the tree
$daux->generateTree();
$daux->getProcessor()->manipulateTree($daux->tree);
// Set the format if requested
if ($input->getOption('format')) {
$daux->getParams()['format'] = $input->getOption('format');
}
// Generate the documentation
$daux->getGenerator()->generateAll($input, $output, $width);
}
protected function prepareProcessor(Daux $daux, InputInterface $input, OutputInterface $output, $width)
{
if ($input->getOption('processor')) {
$daux->getParams()['processor'] = $input->getOption('processor');
}
$class = $daux->getProcessorClass();
if (!empty($class)) {
$daux->setProcessor(new $class($daux, $output, $width));
}
}
}

71
libs/Generator/Helper.php Normal file
View File

@ -0,0 +1,71 @@
<?php namespace Todaymade\Daux\Generator;
class Helper
{
/**
* Copy all files from $path to $local_base
*
* @param string $path
* @param string $local_base
*/
public static function copyAssets($path, $local_base)
{
if (is_dir($path)) {
static::rmdir($path);
} else {
mkdir($path);
}
mkdir($path . DIRECTORY_SEPARATOR . 'resources');
static::copyRecursive(
$local_base . DIRECTORY_SEPARATOR . 'resources',
$path . DIRECTORY_SEPARATOR . 'resources'
);
}
/**
* Remove a directory recursively
*
* @param string $dir
*/
protected static function rmdir($dir)
{
$it = new \RecursiveDirectoryIterator($dir);
$files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
foreach ($files as $file) {
if ($file->getFilename() === '.' || $file->getFilename() === '..') {
continue;
}
if ($file->isDir()) {
rmdir($file->getRealPath());
} else {
unlink($file->getRealPath());
}
}
}
/**
* Copy files recursively
*
* @param string $source
* @param string $destination
*/
protected static function copyRecursive($source, $destination)
{
if (!is_dir($destination)) {
mkdir($destination);
}
$dir = opendir($source);
while (false !== ($file = readdir($dir))) {
if ($file != '.' && $file != '..') {
if (is_dir($source . '/' . $file)) {
static::copyRecursive($source . '/' . $file, $destination . '/' . $file);
} else {
copy($source . '/' . $file, $destination . '/' . $file);
}
}
}
closedir($dir);
}
}

71
libs/Processor.php Normal file
View File

@ -0,0 +1,71 @@
<?php namespace Todaymade\Daux;
use League\CommonMark\Environment;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Tree\Root;
class Processor
{
/**
* @var Daux
*/
protected $daux;
/**
* @var OutputInterface
*/
protected $output;
/**
* @var integer
*/
protected $width;
/**
* @param Daux $daux
* @param OutputInterface $output
* @param integer $width
*/
public function __construct(Daux $daux, OutputInterface $output, $width)
{
$this->daux = $daux;
$this->output = $output;
$this->width = $width;
}
/**
* With this connection point, you can transform
* the tree as you want, move pages, modify
* pages and even add new ones.
*
* @param Root $root
*/
public function manipulateTree(Root $root)
{
}
/**
* This connection point provides
* a way to extend the Markdown
* parser and renderer.
*
* @param Environment $environment
*/
public function extendCommonMarkEnvironment(Environment $environment)
{
}
/**
* Provide new generators with this extension point. You
* can simply return an array, the key is the format's
* name, the value is a class name implementing the
* `Todaymade\Daux\Format\Base\Generator` contract.
* You can also replace base generators.
*
* @return array
*/
public function addGenerators()
{
return [];
}
}

43
libs/Server/ErrorPage.php Normal file
View File

@ -0,0 +1,43 @@
<?php namespace Todaymade\Daux\Server;
use Todaymade\Daux\Format\HTML\SimplePage;
use Todaymade\Daux\Format\HTML\Template;
class ErrorPage extends SimplePage
{
const NORMAL_ERROR_TYPE = 'NORMAL_ERROR';
const MISSING_PAGE_ERROR_TYPE = 'MISSING_PAGE_ERROR';
const FATAL_ERROR_TYPE = 'FATAL_ERROR';
/**
* @var \Todaymade\Daux\Config
*/
private $params;
/**
* @param string $title
* @param string $content
* @param \Todaymade\Daux\Config $params
*/
public function __construct($title, $content, $params)
{
parent::__construct($title, $content);
$this->params = $params;
}
/**
* @return string
*/
protected function generatePage()
{
$params = $this->params;
$page = [
'title' => $this->title,
'content' => $this->content,
'language' => '',
];
$template = new Template($params['templates'], $params['theme']['templates']);
return $template->render('error', ['page' => $page, 'params' => $params]);
}
}

81
libs/Server/MimeType.php Normal file
View File

@ -0,0 +1,81 @@
<?php namespace Todaymade\Daux\Server;
/**
* Class MimeType
* @package Defr
* @author Dennis Fridrich <fridrich.dennis@gmail.com>
* @see http://www.php.net/mime_content_type
*/
class MimeType
{
/**
* @var array
*/
protected static $mimeTypes = array(
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// Images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// Archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// Audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// Adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// MS Office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// Open Office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
/**
* @param $filename
* @return string
*/
public static function get($filename)
{
$pathInfo = pathinfo($filename);
$extension = strtolower($pathInfo['extension']);
if (array_key_exists($extension, self::$mimeTypes)) {
return self::$mimeTypes[$extension];
} elseif (function_exists('finfo_open') && is_file($filename)) {
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
} else {
return 'application/octet-stream';
}
}
}

View File

@ -0,0 +1,7 @@
<?php namespace Todaymade\Daux\Server;
use Todaymade\Daux\Exception;
class NotFoundException extends Exception
{
}

178
libs/Server/Server.php Normal file
View File

@ -0,0 +1,178 @@
<?php namespace Todaymade\Daux\Server;
use Symfony\Component\Console\Output\NullOutput;
use Todaymade\Daux\Daux;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Exception;
use Todaymade\Daux\Format\Base\LiveGenerator;
use Todaymade\Daux\Format\HTML\RawPage;
class Server
{
private $daux;
private $params;
private $host;
private $base_url;
/**
* Serve the documentation
*
* @throws Exception
*/
public static function serve()
{
$daux = new Daux(Daux::LIVE_MODE);
$daux->initialize();
$class = $daux->getProcessorClass();
if (!empty($class)) {
$daux->setProcessor(new $class($daux, new NullOutput(), 0));
}
// Set this critical configuration
// for the tree generation
$daux->getParams()['index_key'] = 'index';
// Improve the tree with a processor
$daux->generateTree();
$daux->getProcessor()->manipulateTree($daux->tree);
$server = new static($daux);
try {
$page = $server->handle($_REQUEST);
} catch (NotFoundException $e) {
http_response_code(404);
$page = new ErrorPage("An error occured", $e->getMessage(), $daux->getParams());
}
if ($page instanceof RawPage) {
header('Content-type: ' . MimeType::get($page->getFile()));
// Transfer file in 1024 byte chunks to save memory usage.
if ($fd = fopen($page->getFile(), 'rb')) {
while (!feof($fd)) {
print fread($fd, 1024);
}
fclose($fd);
}
return;
}
header('Content-type: text/html; charset=utf-8');
echo $page->getContent();
}
public function __construct(Daux $daux)
{
$this->daux = $daux;
$this->host = $_SERVER['HTTP_HOST'];
$this->base_url = $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
$t = strrpos($this->base_url, '/index.php');
if ($t != false) {
$this->base_url = substr($this->base_url, 0, $t);
}
if (substr($this->base_url, -1) !== '/') {
$this->base_url .= '/';
}
}
/**
* @return \Todaymade\Daux\Config
*/
public function getParams()
{
$params = $this->daux->getParams();
$params['host'] = $this->host;
DauxHelper::rebaseConfiguration($params, '//' . $this->base_url);
$params['base_page'] = '//' . $this->base_url;
if (!$this->daux->options['live']['clean_urls']) {
$params['base_page'] .= 'index.php/';
}
return $params;
}
/**
* Handle an incoming request
*
* @param array $query
* @return \Todaymade\Daux\Format\Base\Page
* @throws Exception
* @throws NotFoundException
*/
public function handle($query = [])
{
$this->params = $this->getParams();
$request = $this->getRequest();
$request = urldecode($request);
if ($request == 'index_page') {
$request = $this->daux->tree->getIndexPage()->getUri();
}
return $this->getPage($request);
}
/**
* @param string $request
* @return \Todaymade\Daux\Format\Base\Page
* @throws NotFoundException
*/
private function getPage($request)
{
$file = DauxHelper::getFile($this->daux->tree, $request);
if ($file === false) {
throw new NotFoundException('The Page you requested is yet to be made. Try again later.');
}
$generator = $this->daux->getGenerator();
if (!$generator instanceof LiveGenerator) {
throw new \RuntimeException(
"The generator '" . get_class($generator) . "' does not implement the interface " .
"'Todaymade\\Daux\\Format\\Base\\LiveGenerator' and thus doesn't support live rendering."
);
}
return $this->daux->getGenerator()->generateOne($file, $this->params);
}
public function getRequest()
{
if (isset($_SERVER['PATH_INFO'])) {
$uri = $_SERVER['PATH_INFO'];
} elseif (isset($_SERVER['REQUEST_URI'])) {
$uri = $_SERVER['REQUEST_URI'];
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) {
$uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
} elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) {
$uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
if (strncmp($uri, '?/', 2) === 0) {
$uri = substr($uri, 2);
}
$parts = preg_split('#\?#i', $uri, 2);
$uri = $parts[0];
if (isset($parts[1])) {
$_SERVER['QUERY_STRING'] = $parts[1];
parse_str($_SERVER['QUERY_STRING'], $_GET);
} else {
$_SERVER['QUERY_STRING'] = '';
$_GET = array();
}
$uri = parse_url($uri, PHP_URL_PATH);
} else {
return false;
}
$uri = str_replace(array('//', '../'), '/', trim($uri, '/'));
if ($uri == "") {
$uri = "index_page";
}
return $uri;
}
}

170
libs/Tree/Builder.php Normal file
View File

@ -0,0 +1,170 @@
<?php namespace Todaymade\Daux\Tree;
use Todaymade\Daux\Daux;
use Todaymade\Daux\DauxHelper;
class Builder
{
/**
* Build the initial tree
*
* @param Directory $node
* @param array $ignore
*/
public static function build($node, $ignore)
{
if (!$dh = opendir($node->getPath())) {
return;
}
if ($node instanceof Root) {
// Ignore config.json in the root directory
$ignore['files'][] = 'config.json';
}
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
$path = $node->getPath() . DIRECTORY_SEPARATOR . $file;
if (is_dir($path) && in_array($file, $ignore['folders'])) {
continue;
}
if (!is_dir($path) && in_array($file, $ignore['files'])) {
continue;
}
if (is_dir($path)) {
$new = new Directory($node, static::removeSortingInformations(static::getFilename($path)), $path);
$new->setName(DauxHelper::pathinfo($path)['filename']);
$new->setTitle(static::removeSortingInformations($new->getName(), ' '));
static::build($new, $ignore);
} else {
static::createContent($node, $path);
}
}
$node->sort();
}
/**
* @param Directory $parent
* @param string $path
* @return Content|Raw
*/
public static function createContent(Directory $parent, $path)
{
$name = DauxHelper::pathinfo($path)['filename'];
$config = $parent->getConfig();
if (!in_array(pathinfo($path, PATHINFO_EXTENSION), $config['valid_content_extensions'])) {
$entry = new Raw($parent, static::removeSortingInformations(static::getFilename($path)), $path, filemtime($path));
$entry->setTitle(static::removeSortingInformations($name, ' '));
$entry->setName($name);
return $entry;
}
$uri = static::removeSortingInformations($name);
if ($config['mode'] === Daux::STATIC_MODE) {
$uri .= '.html';
}
$entry = new Content($parent, $uri, $path, filemtime($path));
if ($entry->getUri() == $config['index_key']) {
if ($parent instanceof Root) {
$entry->setTitle($config['title']);
} else {
$entry->setTitle($parent->getTitle());
}
} else {
$entry->setTitle(static::removeSortingInformations($name, ' '));
}
$entry->setName($name);
return $entry;
}
/**
* @param string $file
* @return string
*/
protected static function getFilename($file)
{
$parts = explode('/', $file);
return end($parts);
}
/**
* @param string $filename
* @return string
*/
protected static function removeSortingInformations($filename, $separator = '_')
{
$filename = explode('_', $filename);
if ($filename[0] == '' || is_numeric($filename[0])) {
unset($filename[0]);
} else {
$t = $filename[0];
if ($t[0] == '-') {
$filename[0] = substr($t, 1);
}
}
$filename = implode($separator, $filename);
return $filename;
}
/**
* @param Directory $parent
* @param String $title
* @return Directory
*/
public static function getOrCreateDir(Directory $parent, $title)
{
$slug = DauxHelper::slug($title);
if (array_key_exists($slug, $parent->getEntries())) {
return $parent->getEntries()[$slug];
}
$dir = new Directory($parent, $slug);
$dir->setTitle($title);
return $dir;
}
/**
* @param Directory $parent
* @param string $title
* @return Content
*/
public static function getOrCreatePage(Directory $parent, $title)
{
$uri = $slug = DauxHelper::slug($title);
if ($parent->getConfig()['mode'] === Daux::STATIC_MODE) {
$uri = $slug . ".html";
}
if (array_key_exists($uri, $parent->getEntries())) {
return $parent->getEntries()[$uri];
}
$page = new Content($parent, $uri);
$page->setContent("-"); //set an almost empty content to avoid problems
if ($title == 'index') {
$page->setName('_index');
$page->setTitle($parent->getTitle());
} else {
$page->setName($slug);
$page->setTitle($title);
}
return $page;
}
}

40
libs/Tree/Content.php Normal file
View File

@ -0,0 +1,40 @@
<?php namespace Todaymade\Daux\Tree;
use Todaymade\Daux\DauxHelper;
class Content extends Entry
{
/**
* @var string
*/
protected $content;
/**
* @return string
*/
public function getContent()
{
if (!$this->content) {
$this->content = file_get_contents($this->getPath());
}
return $this->content;
}
/**
* @param string $content
*/
public function setContent($content)
{
$this->content = $content;
}
/**
* @param string $file
* @return string
*/
protected function getFilename($file)
{
return DauxHelper::pathinfo($file)['filename'];
}
}

159
libs/Tree/Directory.php Normal file
View File

@ -0,0 +1,159 @@
<?php namespace Todaymade\Daux\Tree;
class Directory extends Entry
{
/** @var Entry[] */
protected $children = [];
/** @var Content */
protected $first_page;
public function sort()
{
uasort($this->children, array($this, 'compareEntries'));
}
/**
* @return Entry[]
*/
public function getEntries()
{
return $this->children;
}
public function addChild(Entry $entry)
{
$this->children[$entry->getUri()] = $entry;
}
public function removeChild(Entry $entry)
{
unset($this->children[$entry->getUri()]);
}
/**
* @return \Todaymade\Daux\Config
*/
public function getConfig()
{
if (!$this->parent) {
throw new \RuntimeException("Could not retrieve configuration. Are you sure that your tree has a Root ?");
}
return $this->parent->getConfig();
}
/**
* @return Content|null
*/
public function getIndexPage()
{
$index_key = $this->getConfig()['index_key'];
if (isset($this->children[$index_key])) {
return $this->children[$index_key];
}
return null;
}
/**
* @return Content|null
*/
public function getFirstPage()
{
if ($this->first_page) {
return $this->first_page;
}
// First we try to find a real page
foreach ($this->getEntries() as $node) {
if ($node instanceof Content) {
if ($this instanceof Root && $this->getIndexPage() == $node) {
// The homepage should not count as first page
continue;
}
$this->setFirstPage($node);
return $node;
}
}
// If we can't find one we check in the sub-directories
foreach ($this->getEntries() as $node) {
if ($node instanceof Directory && $page = $node->getFirstPage()) {
$this->setFirstPage($page);
return $page;
}
}
return null;
}
/**
* @param Content $first_page
*/
public function setFirstPage($first_page)
{
$this->first_page = $first_page;
}
private function compareEntries($a, $b)
{
$name_a = explode('_', $a->name);
$name_b = explode('_', $b->name);
if (is_numeric($name_a[0])) {
$a = intval($name_a[0]);
if (is_numeric($name_b[0])) {
$b = intval($name_b[0]);
if (($a >= 0) == ($b >= 0)) {
$a = abs($a);
$b = abs($b);
if ($a == $b) {
return (strcasecmp($name_a[1], $name_b[1]));
}
return ($a > $b) ? 1 : -1;
}
return ($a >= 0) ? -1 : 1;
}
$t = $name_b[0];
if ($t && $t[0] === '-') {
return -1;
}
return ($a < 0) ? 1 : -1;
} else {
if (is_numeric($name_b[0])) {
$b = intval($name_b[0]);
if ($b >= 0) {
return 1;
}
$t = $name_a[0];
if ($t && $t[0] === '-') {
return 1;
}
return ($b >= 0) ? 1 : -1;
}
$p = $name_a[0];
$q = $name_b[0];
if (($p && $p[0] === '-') == ($q && $q[0] === '-')) {
return strcasecmp($p, $q);
} else {
return ($p[0] === '-') ? 1 : -1;
}
}
}
public function dump()
{
$dump = parent::dump();
$dump['index'] = $this->getIndexPage() ? $this->getIndexPage()->getUrl() : '';
$dump['first'] = $this->getFirstPage() ? $this->getFirstPage()->getUrl() : '';
foreach ($this->getEntries() as $entry) {
$dump['children'][] = $entry->dump();
}
return $dump;
}
}

170
libs/Tree/Entry.php Normal file
View File

@ -0,0 +1,170 @@
<?php namespace Todaymade\Daux\Tree;
abstract class Entry
{
/** @var string */
protected $title;
/** @var string */
protected $name;
/** @var string */
protected $uri;
/** @var Directory */
protected $parent;
/** @var string */
protected $path;
/** @var integer */
protected $last_modified;
/**
* @param Directory $parent
* @param string $uri
* @param string $path
* @param integer $last_modified
*/
public function __construct(Directory $parent, $uri, $path = null, $last_modified = null)
{
$this->setUri($uri);
$this->setParent($parent);
if ($path !== null) {
$this->path = $path;
}
if ($last_modified !== null) {
$this->last_modified = $last_modified;
}
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getUri()
{
return $this->uri;
}
/**
* @param string $uri
*/
public function setUri($uri)
{
if ($this->parent) {
$this->parent->removeChild($this);
}
$this->uri = $uri;
if ($this->parent) {
$this->parent->addChild($this);
}
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* @return Directory
*/
public function getParent()
{
return $this->parent;
}
/**
* Return all parents starting with the root
*
* @return Directory[]
*/
public function getParents()
{
$parents = [];
if ($this->parent && !$this->parent instanceof Root) {
$parents = $this->parent->getParents();
$parents[] = $this->parent;
}
return $parents;
}
/**
* @param Directory $parent
*/
protected function setParent(Directory $parent)
{
if ($this->parent) {
$this->parent->removeChild($this);
}
$parent->addChild($this);
$this->parent = $parent;
}
/**
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* @return string
*/
public function getUrl()
{
$url = '';
if ($this->getParent() && !$this->getParent() instanceof Root) {
$url = $this->getParent()->getUrl() . '/' . $url;
}
$url .= $this->getUri();
return $url;
}
public function dump()
{
return [
'title' => $this->getTitle(),
'type' => get_class($this),
'name' => $this->getName(),
'uri' => $this->getUri(),
'url' => $this->getUrl(),
'path' => $this->path
];
}
}

5
libs/Tree/Raw.php Normal file
View File

@ -0,0 +1,5 @@
<?php namespace Todaymade\Daux\Tree;
class Raw extends Entry
{
}

38
libs/Tree/Root.php Normal file
View File

@ -0,0 +1,38 @@
<?php namespace Todaymade\Daux\Tree;
use Todaymade\Daux\Config;
class Root extends Directory
{
/** @var Config */
protected $config;
/**
* The root doesn't have a parent
*
* @param string $uri
*/
public function __construct(Config $config, $uri)
{
$this->setConfig($config);
$this->setUri($uri);
$this->path = $uri;
}
/**
* @return Config
*/
public function getConfig()
{
return $this->config;
}
/**
* @param Config $config
*/
public function setConfig($config)
{
$this->config = $config;
}
}

View File

@ -1,341 +0,0 @@
<?php
namespace Todaymade\Daux;
require_once(dirname(__FILE__) . '/../vendor/autoload.php');
require_once('daux_directory.php');
require_once('daux_helper.php');
require_once('daux_page.php');
class Daux
{
const STATIC_MODE = 'DAUX_STATIC';
const LIVE_MODE = 'DAUX_LIVE';
public static $VALID_MARKDOWN_EXTENSIONS;
private $local_base;
private $base_url;
private $host;
private $docs_path;
private $tree;
private $options;
private $error_page;
private $error = false;
private $params;
private $mode;
function __construct($global_config_file = NULL) {
$this->initial_setup($global_config_file);
}
public function initialize($config_file = 'config.json') {
if ($this->error) return;
$this->load_docs_config($config_file);
$this->generate_directory_tree();
if (!$this->error) $this->params = $this->get_page_params();
}
public function generate_static($output_dir = NULL) {
if (is_null($output_dir)) $output_dir = $this->local_base . DIRECTORY_SEPARATOR . 'static';
DauxHelper::clean_copy_assets($output_dir, $this->local_base);
$this->recursive_generate_static($this->tree, $output_dir, $this->params);
}
public function handle_request($url, $query = array()) {
if ($this->error) return $this->error_page;
if (!$this->params['clean_urls']) $this->params['base_page'] .= 'index.php/';
$request = DauxHelper::get_request();
$request = urldecode($request);
$request_type = isset($query['method']) ? $query['method'] : '';
if($request == 'first_page') {
$request = $this->tree->first_page->uri;
}
switch ($request_type) {
case 'DauxEdit':
if ($this->options['file_editor']) {
$content = isset($query['markdown']) ? $query['markdown'] : '';
return $this->save_file($request, $content);
}
return $this->generate_error_page('Editing Disabled', 'Editing is currently disabled in config',
ErrorPage::FATAL_ERROR_TYPE);
default:
return $this->get_page($request);
}
}
private function initial_setup($global_config_file) {
$this->setup_environment_variables();
$this->load_global_config($global_config_file);
}
private function setup_environment_variables() {
global $argc;
$this->local_base = dirname(dirname(__FILE__));
$this->base_url = '';
if (isset($argc)) {
$this->mode = Daux::STATIC_MODE;
return;
}
$this->mode = Daux::LIVE_MODE;
$this->host = $_SERVER['HTTP_HOST'];
$this->base_url = $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
$t = strrpos($this->base_url, '/index.php');
if ($t != FALSE) $this->base_url = substr($this->base_url, 0, $t);
if (substr($this->base_url, -1) !== '/') $this->base_url .= '/';
}
private function load_global_config($global_config_file) {
if (is_null($global_config_file)) $global_config_file = $this->local_base . DIRECTORY_SEPARATOR . 'global.json';
if (!file_exists($global_config_file)) {
$this->generate_error_page('Global Config File Missing',
'The Global Config file is missing. Requested File : ' . $global_config_file, ErrorPage::FATAL_ERROR_TYPE);
return;
}
$global_config = json_decode(file_get_contents($global_config_file), true);
if (!isset($global_config)) {
$this->generate_error_page('Corrupt Global Config File',
'The Global Config file is corrupt. Check that the JSON encoding is correct', ErrorPage::FATAL_ERROR_TYPE);
return;
}
if (!isset($global_config['docs_directory'])) {
$this->generate_error_page('Docs Directory not set', 'The Global Config file does not have the docs directory set.',
ErrorPage::FATAL_ERROR_TYPE);
return;
}
$this->docs_path = $global_config['docs_directory'];
if (!is_dir($this->docs_path) && !is_dir($this->docs_path = $this->local_base . DIRECTORY_SEPARATOR . $this->docs_path)) {
$this->generate_error_page('Docs Directory not found',
'The Docs directory does not exist. Check the path again : ' . $this->docs_path, ErrorPage::FATAL_ERROR_TYPE);
return;
}
if (!isset($global_config['valid_markdown_extensions'])) static::$VALID_MARKDOWN_EXTENSIONS = array('md', 'markdown');
else static::$VALID_MARKDOWN_EXTENSIONS = $global_config['valid_markdown_extensions'];
}
private function load_docs_config($config_file) {
$config_file = $this->docs_path . DIRECTORY_SEPARATOR . $config_file;
if (!file_exists($config_file)) {
$this->generate_error_page('Config File Missing',
'The local config file is missing. Check path : ' . $config_file, ErrorPage::FATAL_ERROR_TYPE);
return;
}
$this->options = json_decode(file_get_contents($this->local_base . DIRECTORY_SEPARATOR . 'default.json'), true);
if (is_file($config_file)) {
$config = json_decode(file_get_contents($config_file), true);
if (!isset($config)) {
$this->generate_error_page('Invalid Config File',
'There was an error parsing the Config file. Please review', ErrorPage::FATAL_ERROR_TYPE);
return;
}
$this->options = array_merge($this->options, $config);
}
if (isset($this->options['timezone'])) date_default_timezone_set($this->options['timezone']);
else if (!ini_get('date.timezone')) date_default_timezone_set('GMT');
}
private function generate_directory_tree() {
$this->tree = DauxHelper::build_directory_tree($this->docs_path, $this->options['ignore'], $this->mode);
if (!empty($this->options['languages'])) {
foreach ($this->options['languages'] as $key => $node) {
$this->tree->value[$key]->title = $node;
}
}
}
private function recursive_generate_static($tree, $output_dir, $params, $base_url = '') {
$params['base_url'] = $params['base_page'] = $base_url;
$new_params = $params;
//changed this as well in order for the templates to be put in the right place
$params['theme'] = DauxHelper::rebase_theme($params['theme'], $base_url, $params['base_url'] . "templates/default/themes/" . $params['theme']['name'] . '/');
//
$params['image'] = str_replace('<base_url>', $base_url, $params['image']);
if ($base_url !== '') $params['entry_page'] = $tree->first_page;
foreach ($tree->value as $key => $node) {
if ($node->type === Directory_Entry::DIRECTORY_TYPE) {
$new_output_dir = $output_dir . DIRECTORY_SEPARATOR . $key;
@mkdir($new_output_dir);
$this->recursive_generate_static($node, $new_output_dir, $new_params, '../' . $base_url);
} else {
$params['request'] = $node->get_url();
$params['file_uri'] = $node->name;
$page = MarkdownPage::fromFile($node, $params);
file_put_contents($output_dir . DIRECTORY_SEPARATOR . $key, $page->get_page_content());
}
}
}
private function save_file($request, $content) {
$file = $this->get_file_from_request($request);
if ($file === false) return $this->generate_error_page('Page Not Found',
'The Page you requested is yet to be made. Try again later.', ErrorPage::MISSING_PAGE_ERROR_TYPE);
if ($file->write($content)) return new SimplePage('Success', 'Successfully Edited');
else return $this->generate_error_page('File Not Writable', 'The file you wish to write to is not writable.',
ErrorPage::FATAL_ERROR_TYPE);
}
private function generate_error_page($title, $content, $type) {
$this->error_page = new ErrorPage($title, $content, $this->get_page_params($type));
$this->error = true;
return $this->error_page;
}
private function get_page($request) {
$params = $this->params;
$file = $this->get_file_from_request($request);
if ($file === false) return $this->generate_error_page('Page Not Found',
'The Page you requested is yet to be made. Try again later.', ErrorPage::MISSING_PAGE_ERROR_TYPE);
$params['request'] = $request;
$params['file_uri'] = $file->value;
if ($request !== 'index') $params['entry_page'] = $file->first_page;
return MarkdownPage::fromFile($file, $params);
}
private function get_page_params($mode = '') {
$params = array();
$params['local_base'] = $this->local_base;
if ($mode === '') $mode = $this->mode;
$params['mode'] = $mode;
switch ($mode) {
case ErrorPage::FATAL_ERROR_TYPE:
$params['error_type'] = ErrorPage::FATAL_ERROR_TYPE;
break;
case ErrorPage::NORMAL_ERROR_TYPE:
case ErrorPage::MISSING_PAGE_ERROR_TYPE:
$params['error_type'] = $mode;
$params['index_key'] = 'index';
$params['docs_path'] = $this->docs_path;
$protocol = '//';
$params['base_url'] = $protocol . $this->base_url;
$params['base_page'] = $params['base_url'];
$params['host'] = $this->host;
$params['tree'] = $this->tree;
$params['index'] = ($this->tree->index_page !== false) ? $this->tree->index_page : $this->tree->first_page;
$params['clean_urls'] = $this->options['clean_urls'];
$params['tagline'] = $this->options['tagline'];
$params['title'] = $this->options['title'];
$params['author'] = $this->options['author'];
$params['image'] = $this->options['image'];
if ($params['image'] !== '') $params['image'] = str_replace('<base_url>', $params['base_url'], $params['image']);
$params['repo'] = $this->options['repo'];
$params['links'] = $this->options['links'];
$params['twitter'] = $this->options['twitter'];
$params['google_analytics'] = ($g = $this->options['google_analytics']) ?
DauxHelper::google_analytics($g, $this->host) : '';
$params['piwik_analytics'] = ($p = $this->options['piwik_analytics']) ?
DauxHelper::piwik_analytics($p, $this->options['piwik_analytics_id']) : '';
$params['template'] = $this->options['template'];
$params['theme'] = DauxHelper::configure_theme($this->local_base . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR .
$this->options['template'] . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $this->options['theme'] . '.thm', $params['base_url'],
$this->local_base, $params['base_url'] . "templates/" . $params['template'] . "/themes/" . $this->options['theme'] . '/');
break;
case Daux::LIVE_MODE:
$params['docs_path'] = $this->docs_path;
$params['index_key'] = 'index';
$protocol = '//';
$params['base_url'] = $protocol . $this->base_url;
$params['base_page'] = $params['base_url'];
$params['host'] = $this->host;
$params['tree'] = $this->tree;
$params['index'] = ($this->tree->index_page !== false) ? $this->tree->index_page : $this->tree->first_page;
$params['clean_urls'] = $this->options['clean_urls'];
$params['tagline'] = $this->options['tagline'];
$params['title'] = $this->options['title'];
$params['author'] = $this->options['author'];
$params['image'] = $this->options['image'];
if ($params['image'] !== '') $params['image'] = str_replace('<base_url>', $params['base_url'], $params['image']);
$params['repo'] = $this->options['repo'];
$params['links'] = $this->options['links'];
$params['twitter'] = $this->options['twitter'];
$params['google_analytics'] = ($g = $this->options['google_analytics']) ?
DauxHelper::google_analytics($g, $this->host) : '';
$params['piwik_analytics'] = ($p = $this->options['piwik_analytics']) ?
DauxHelper::piwik_analytics($p, $this->options['piwik_analytics_id']) : '';
$params['template'] = $this->options['template'];
$params['theme'] = DauxHelper::configure_theme($this->local_base . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR .
$this->options['template'] . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $this->options['theme'] . '.thm', $params['base_url'],
$this->local_base, $params['base_url'] . "templates/" . $params['template'] . "/themes/" . $this->options['theme'] . '/', $mode);
if ($params['breadcrumbs'] = $this->options['breadcrumbs'])
$params['breadcrumb_separator'] = $this->options['breadcrumb_separator'];
$params['multilanguage'] = !empty($this->options['languages']);
$params['languages'] = $this->options['languages'];
if (empty($this->options['languages'])) {
$params['entry_page'] = $this->tree->first_page;
} else {
foreach ($this->options['languages'] as $key => $name) {
$params['entry_page'][$key] = $this->tree->value[$key]->first_page;
}
}
$params['toggle_code'] = $this->options['toggle_code'];
$params['float'] = $this->options['float'];
$params['date_modified'] = $this->options['date_modified'];
$params['file_editor'] = $this->options['file_editor'];
break;
case Daux::STATIC_MODE:
$params['docs_path'] = $this->docs_path;
$params['index_key'] = 'index.html';
$params['base_url'] = '';
$params['base_page'] = $params['base_url'];
$params['tree'] = $this->tree;
$params['index'] = ($this->tree->index_page !== false) ? $this->tree->index_page : $this->tree->first_page;
$params['tagline'] = $this->options['tagline'];
$params['title'] = $this->options['title'];
$params['author'] = $this->options['author'];
$params['image'] = $this->options['image'];
$params['repo'] = $this->options['repo'];
$params['links'] = $this->options['links'];
$params['twitter'] = $this->options['twitter'];
$params['google_analytics'] = ($g = $this->options['google_analytics']) ?
DauxHelper::google_analytics($g, $this->host) : '';
$params['piwik_analytics'] = ($p = $this->options['piwik_analytics']) ?
DauxHelper::piwik_analytics($p, $this->options['piwik_analytics_id']) : '';
$params['template'] = $this->options['template'];
$params['theme'] = DauxHelper::configure_theme($this->local_base . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR .
$this->options['template'] . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $this->options['theme'] . '.thm', $params['base_url'],
$this->local_base, $params['base_url'] . "templates/" . $params['template'] . "/themes/" . $this->options['theme'] . '/', $mode);
if ($params['breadcrumbs'] = $this->options['breadcrumbs'])
$params['breadcrumb_separator'] = $this->options['breadcrumb_separator'];
$params['multilanguage'] = !empty($this->options['languages']);
$params['languages'] = $this->options['languages'];
if (empty($this->options['languages'])) {
$params['entry_page'] = $this->tree->first_page;
} else {
foreach ($this->options['languages'] as $key => $name) {
$params['entry_page'][$key] = $this->tree->value[$key]->first_page;
}
}
$params['toggle_code'] = $this->options['toggle_code'];
$params['float'] = $this->options['float'];
$params['date_modified'] = $this->options['date_modified'];
$params['file_editor'] = false;
break;
}
return $params;
}
private function get_file_from_request($request) {
$file = $this->tree->retrieve_file($request);
return $file;
}
}
?>

View File

@ -1,128 +0,0 @@
<?php
namespace Todaymade\Daux;
class Directory_Entry
{
const FILE_TYPE = 'FILE_TYPE';
const DIRECTORY_TYPE = 'DIRECTORY_TYPE';
public $name;
public $title;
public $type;
public $index_page;
public $first_page;
public $value;
public $uri;
public $local_path;
public $last_modified;
public $parents;
function __construct($path = '', $parents = array()) {
if (!isset($path) || $path == '' || !file_exists($path)) return;
$this->local_path = $path;
$this->parents = $parents;
$this->last_modified = filemtime($path);
$this->name = DauxHelper::pathinfo($path);
$this->name = $this->name['filename'];
$this->title = DauxHelper::get_title_from_file($this->name);
$this->uri = DauxHelper::get_url_from_filename($this->name);
$this->index_page = false;
if (is_dir($path)) {
$this->type = Directory_Entry::DIRECTORY_TYPE;
$this->value = array();
} else {
$this->type = Directory_Entry::FILE_TYPE;
$this->value = $this->uri;
}
}
public function sort() {
if ($this->type == static::DIRECTORY_TYPE) uasort($this->value, array($this, 'compare_directory_entries'));
}
public function retrieve_file($request, $get_first_file = false) {
$tree = $this;
$request = explode('/', $request);
foreach ($request as $node) {
if ($tree->type === static::DIRECTORY_TYPE) {
if (isset($tree->value[$node])) $tree = $tree->value[$node];
else {
if ($node === 'index' || $node === 'index.html') {
if ($get_first_file) {
return ($tree->index_page) ? $tree->index_page : $tree->first_page;
} else {
return $tree->index_page;
}
} else return false;
}
} else return false;
}
if ($tree->type === static::DIRECTORY_TYPE) {
if ($tree->index_page) return $tree->index_page;
else return ($get_first_file) ? $tree->first_page : false;
} else {
return $tree;
}
}
public function get_url() {
$url = '';
foreach ($this->parents as $node) {
$url .= $node->uri . '/';
}
$url .= $this->uri;
return $url;
}
public function get_first_page() {
foreach ($this->value as $node) {
if ($node->type === static::FILE_TYPE && $node->title != 'index')
return $node;
}
foreach ($this->value as $node) {
if ($node->type === static::DIRECTORY_TYPE) {
$page = $node->get_first_page();
if ($page) return $page;
}
}
return false;
}
public function write($content) {
if (is_writable($this->local_path)) file_put_contents($this->local_path, $content);
else return false;
return true;
}
private function compare_directory_entries($a, $b) {
$name_a = explode('_', $a->name);
$name_b = explode('_', $b->name);
if (is_numeric($name_a[0])) {
$a = intval($name_a[0]);
if (is_numeric($name_b[0])) {
$b = intval($name_b[0]);
if (($a >= 0) == ($b >= 0)) {
$a = abs($a);
$b = abs($b);
if ($a == $b) return (strcasecmp($name_a[1], $name_b[1]));
return ($a > $b) ? 1 : -1;
}
return ($a >= 0) ? -1 : 1;
}
$t = $name_b[0];
if ($t && $t[0] === '-') return -1;
return ($a < 0) ? 1 : -1;
} else {
if (is_numeric($name_b[0])) {
$b = intval($name_b[0]);
if ($b >= 0) return 1;
$t = $name_a[0];
if ($t && $t[0] === '-') return 1;
return ($b >= 0) ? 1 : -1;
}
$p = $name_a[0];
$q = $name_b[0];
if (($p && $p[0] === '-') == ($q && $q[0] === '-')) return strcasecmp($p, $q);
else return ($p[0] === '-') ? 1 : -1;
}
}
}
?>

View File

@ -1,363 +0,0 @@
<?php
namespace Todaymade\Daux;
class DauxHelper {
public static function get_breadcrumb_title_from_request($request, $separator = 'Chevrons', $multilanguage = false) {
if ($multilanguage) $request = substr($request, strpos($request, '/') + 1);
$request = str_replace('_', ' ', $request);
switch ($separator) {
case 'Chevrons':
$request = str_replace('/', ' <i class="glyphicon glyphicon-chevron-right"></i> ', $request);
return $request;
case 'Colons':
$request = str_replace('/', ': ', $request);
return $request;
case 'Spaces':
$request = str_replace('/', ' ', $request);
return $request;
default:
$request = str_replace('/', $separator, $request);
return $request;
}
return $request;
}
public static function get_title_from_file($file) {
$file = static::pathinfo($file);
return static::get_title_from_filename($file['filename']);
}
public static function get_title_from_filename($filename) {
$filename = explode('_', $filename);
if ($filename[0] == '' || is_numeric($filename[0])) unset($filename[0]);
else {
$t = $filename[0];
if ($t[0] == '-') $filename[0] = substr($t, 1);
}
$filename = implode(' ', $filename);
return $filename;
}
public static function get_url_from_file($file) {
$file = static::pathinfo($file);
return static::get_url_from_filename($file['filename']);
}
public static function get_url_from_filename($filename) {
$filename = explode('_', $filename);
if ($filename[0] == '' || is_numeric($filename[0])) unset($filename[0]);
else {
$t = $filename[0];
if ($t[0] == '-') $filename[0] = substr($t, 1);
}
$filename = implode('_', $filename);
return $filename;
}
public static function build_directory_tree($dir, $ignore, $mode) {
return static::directory_tree_builder($dir, $ignore, $mode);
}
//Depreciated
public static function get_request_from_url($url, $base_url) {
$url = substr($url, strlen($base_url));
if (strpos($url, 'index.php') === 0) {
$request = (($i = strpos($url, 'request=')) !== false) ? $request = substr($url, $i + 8) : '';
if ($end = strpos($request, '&')) $request = substr($request, 0, $end);
$request = ($request === '') ? 'index' : $request;
} else {
$request = ($url == '') ? 'index' : $url;
$request = ($end = strpos($request, '?')) ? substr($request, 0, $end) : $request;
}
return $request;
}
public static function get_request($prefix_slash = false)
{
if (isset($_SERVER['PATH_INFO'])) $uri = $_SERVER['PATH_INFO'];
else if (isset($_SERVER['REQUEST_URI'])) {
$uri = $_SERVER['REQUEST_URI'];
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
else if (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
if (strncmp($uri, '?/', 2) === 0) $uri = substr($uri, 2);
$parts = preg_split('#\?#i', $uri, 2);
$uri = $parts[0];
if (isset($parts[1])) {
$_SERVER['QUERY_STRING'] = $parts[1];
parse_str($_SERVER['QUERY_STRING'], $_GET);
} else {
$_SERVER['QUERY_STRING'] = '';
$_GET = array();
}
$uri = parse_url($uri, PHP_URL_PATH);
}
else return false;
$uri = str_replace(array('//', '../'), '/', trim($uri, '/'));
if ($uri == "") $uri = "first_page";
return $uri;
}
public static function configure_theme($theme, $base_url, $local_base, $theme_url, $mode = Daux::LIVE_MODE) {
$name = static::pathinfo($theme);
if (is_file($theme)) {
$theme = file_get_contents($theme);
$theme = json_decode($theme, true);
if (!$theme) $theme = array();
} else $theme = array();
$theme['name'] = $name['filename'];
if ($mode === Daux::LIVE_MODE) {
if (!isset($theme['favicon'])) $theme['favicon'] = utf8_encode($base_url . 'img/favicon.png');
else {
$theme['favicon'] = utf8_encode(str_replace('<base_url>', $base_url, $theme['favicon']));
$theme['favicon'] = str_replace('<theme_url>', $theme_url, $theme['favicon']);
}
if (!isset($theme['css'])) $theme['css'] = array();
else {
foreach ($theme['css'] as $key => $css) {
$theme['css'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $css));
$theme['css'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $css));
}
}
if (!isset($theme['fonts'])) $theme['fonts'] = array();
else {
foreach ($theme['fonts'] as $key => $font) {
$theme['fonts'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $font));
$theme['fonts'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $font));
}
}
if (!isset($theme['js'])) $theme['js'] = array();
else {
foreach ($theme['js'] as $key => $js) {
$theme['js'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $js));
$theme['js'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $js));
}
}
} else {
if (!isset($theme['favicon'])) $theme['favicon'] = '<base_url>img/favicon.png';
if (!isset($theme['css'])) $theme['css'] = array();
if (!isset($theme['fonts'])) $theme['fonts'] = array();
if (!isset($theme['js'])) $theme['js'] = array();
}
if (!isset($theme['template'])) $theme['template'] = $local_base . DIRECTORY_SEPARATOR . 'templates' .
DIRECTORY_SEPARATOR . 'default/default.tpl';
else $theme['template'] = str_replace('<local_base>', $local_base, $theme['template']);
if (!isset($theme['error-template'])) $theme['error-template'] = $local_base . DIRECTORY_SEPARATOR . 'templates' .
DIRECTORY_SEPARATOR . 'default/error.tpl';
else $theme['error-template'] = str_replace('<local_base>', $local_base, $theme['error-template']);
if (!isset($theme['require-jquery'])) $theme['require-jquery'] = false;
if (!isset($theme['bootstrap-js'])) $theme['bootstrap-js'] = false;
return $theme;
}
public static function rebase_theme($theme, $base_url, $theme_url) {
$theme['favicon'] = utf8_encode(str_replace('<base_url>', $base_url, $theme['favicon']));
$theme['favicon'] = str_replace('<theme_url>', $theme_url, $theme['favicon']);
foreach ($theme['css'] as $key => $css) {
$theme['css'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $css));
$theme['css'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $css));
}
foreach ($theme['fonts'] as $key => $font) {
$theme['fonts'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $font));
$theme['fonts'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $font));
}
foreach ($theme['js'] as $key => $js) {
$theme['js'][$key] = utf8_encode(str_replace('<base_url>', $base_url, $js));
$theme['js'][$key] = utf8_encode(str_replace('<theme_url>', $theme_url, $js));
}
return $theme;
}
public static function google_analytics($analytics, $host) {
$ga = <<<EOT
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
EOT;
$ga .= "ga('create', '" . $analytics . "', '" . $host . "');";
$ga .= "ga('send', 'pageview');";
$ga .= '</script>';
return $ga;
}
public static function piwik_analytics($analytics_url, $analytics_id) {
$pa = <<<EOT
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["trackPageView"]);
_paq.push(["enableLinkTracking"]);
(function() {
EOT;
$pa .= 'var u=(("https:" == document.location.protocol) ? "https" : "http") + "://' . $analytics_url . '/";';
$pa .= '_paq.push(["setTrackerUrl", u+"piwik.php"]);';
$pa .= '_paq.push(["setSiteId", ' . $analytics_id . ']);';
$pa .= <<<EOT
var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
})();
</script>
EOT;
return $pa;
}
private static function directory_tree_builder($dir, $ignore, $mode = Daux::LIVE_MODE, $parents = null) {
if ($dh = opendir($dir)) {
$node = new Directory_Entry($dir, $parents);
$new_parents = $parents;
if (is_null($new_parents)) $new_parents = array();
else $new_parents[] = $node;
while (($entry = readdir($dh)) !== false) {
if ($entry == '.' || $entry == '..') continue;
$path = $dir . DIRECTORY_SEPARATOR . $entry;
if (is_dir($path) && in_array($entry, $ignore['folders'])) continue;
if (!is_dir($path) && in_array($entry, $ignore['files'])) continue;
$file_details = static::pathinfo($path);
if (is_dir($path)) $entry = static::directory_tree_builder($path, $ignore, $mode, $new_parents);
else if (in_array($file_details['extension'], Daux::$VALID_MARKDOWN_EXTENSIONS))
{
$entry = new Directory_Entry($path, $new_parents);
if ($mode === Daux::STATIC_MODE) $entry->uri .= '.html';
}
if ($entry instanceof Directory_Entry) $node->value[$entry->uri] = $entry;
}
$node->sort();
$node->first_page = $node->get_first_page();
$index_key = ($mode === Daux::LIVE_MODE) ? 'index' : 'index.html';
if (isset($node->value[$index_key])) {
$node->value[$index_key]->first_page = $node->first_page;
$node->index_page = $node->value[$index_key];
} else $node->index_page = false;
return $node;
}
}
public static function pathinfo($path) {
preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $m);
if (isset($m[1])) $ret['dir']=$m[1];
if (isset($m[2])) $ret['basename']=$m[2];
if (isset($m[5])) $ret['extension']=$m[5];
if (isset($m[3])) $ret['filename']=$m[3];
return $ret;
}
public static function clean_copy_assets($path, $local_base){
@mkdir($path);
static::clean_directory($path);
@mkdir($path . DIRECTORY_SEPARATOR . 'img');
static::copy_recursive($local_base . DIRECTORY_SEPARATOR . 'img', $path . DIRECTORY_SEPARATOR . 'img');
@mkdir($path . DIRECTORY_SEPARATOR . 'js');
static::copy_recursive($local_base . DIRECTORY_SEPARATOR . 'js', $path . DIRECTORY_SEPARATOR . 'js');
//added and changed these in order to fetch the theme files and put them in the right place
@mkdir($path . DIRECTORY_SEPARATOR . 'templates');
@mkdir($path . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'default');
@mkdir($path . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR . 'themes');
static::copy_recursive($local_base . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR .
'default' . DIRECTORY_SEPARATOR . 'themes', $path . DIRECTORY_SEPARATOR . 'templates' .
DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR . 'themes');
//
}
// Rmdir
private static function clean_directory($dir) {
$it = new \RecursiveDirectoryIterator($dir);
$files = new \RecursiveIteratorIterator($it,
\RecursiveIteratorIterator::CHILD_FIRST);
foreach($files as $file) {
if ($file->getFilename() === '.' || $file->getFilename() === '..') continue;
if ($file->isDir()) rmdir($file->getRealPath());
else unlink($file->getRealPath());
}
}
private static function copy_recursive($src,$dst) {
$dir = opendir($src);
@mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
static::copy_recursive($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
}
if (!function_exists('http_response_code')) {
function http_response_code($code = NULL) {
if ($code !== NULL) {
switch ($code) {
case 100: $text = 'Continue'; break;
case 101: $text = 'Switching Protocols'; break;
case 200: $text = 'OK'; break;
case 201: $text = 'Created'; break;
case 202: $text = 'Accepted'; break;
case 203: $text = 'Non-Authoritative Information'; break;
case 204: $text = 'No Content'; break;
case 205: $text = 'Reset Content'; break;
case 206: $text = 'Partial Content'; break;
case 300: $text = 'Multiple Choices'; break;
case 301: $text = 'Moved Permanently'; break;
case 302: $text = 'Moved Temporarily'; break;
case 303: $text = 'See Other'; break;
case 304: $text = 'Not Modified'; break;
case 305: $text = 'Use Proxy'; break;
case 400: $text = 'Bad Request'; break;
case 401: $text = 'Unauthorized'; break;
case 402: $text = 'Payment Required'; break;
case 403: $text = 'Forbidden'; break;
case 404: $text = 'Not Found'; break;
case 405: $text = 'Method Not Allowed'; break;
case 406: $text = 'Not Acceptable'; break;
case 407: $text = 'Proxy Authentication Required'; break;
case 408: $text = 'Request Time-out'; break;
case 409: $text = 'Conflict'; break;
case 410: $text = 'Gone'; break;
case 411: $text = 'Length Required'; break;
case 412: $text = 'Precondition Failed'; break;
case 413: $text = 'Request Entity Too Large'; break;
case 414: $text = 'Request-URI Too Large'; break;
case 415: $text = 'Unsupported Media Type'; break;
case 500: $text = 'Internal Server Error'; break;
case 501: $text = 'Not Implemented'; break;
case 502: $text = 'Bad Gateway'; break;
case 503: $text = 'Service Unavailable'; break;
case 504: $text = 'Gateway Time-out'; break;
case 505: $text = 'HTTP Version not supported'; break;
default:
exit('Unknown http status code "' . htmlentities($code) . '"');
break;
}
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' ' . $code . ' ' . $text);
$GLOBALS['http_response_code'] = $code;
} else {
$code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
}
return $code;
}
}
?>

View File

@ -1,200 +0,0 @@
<?php
namespace Todaymade\Daux;
interface Page
{
function get_page_content();
function display();
}
class SimplePage implements Page
{
protected $title;
protected $content;
protected $html = null;
public function __construct($title, $content) {
$this->initialize_page($title, $content);
}
public function initialize_page($title, $content) {
$this->title = $title;
$this->content = $content;
}
public function display() {
header('Content-type: text/html; charset=utf-8');
echo $this->get_page_content();
}
public function get_page_content() {
if (is_null($this->html)) {
$this->html = $this->generate_page();
}
return $this->html;
}
private function generate_page() {
return $this->content;
}
}
class ErrorPage extends SimplePage
{
const NORMAL_ERROR_TYPE = 'NORMAL_ERROR';
const MISSING_PAGE_ERROR_TYPE = 'MISSING_PAGE_ERROR';
const FATAL_ERROR_TYPE = 'FATAL_ERROR';
private $params;
private $type;
private static $template;
public function __construct($title, $content, $params) {
parent::__construct($title, $content);
$this->params = $params;
$this->type = $params['error_type'];
}
public function display() {
http_response_code($this->type === static::MISSING_PAGE_ERROR_TYPE ? 404 : 500);
parent::display();
}
public function get_page_content() {
if ($this->type !== static::FATAL_ERROR_TYPE && is_null(static::$template)) {
include_once($this->params['theme']['error-template']);
static::$template = new Template();
}
if (is_null($this->html)) {
$this->html = $this->generate_page();
}
return $this->html;
}
public function generate_page() {
if ($this->type === static::FATAL_ERROR_TYPE) return $this->content;
$params = $this->params;
$page['title'] = $this->title;
$page['theme'] = $params['theme'];
$page['content'] = $this->content;
$page['google_analytics'] = $params['google_analytics'];
$page['piwik_analytics'] = $params['piwik_analytics'];
return static::$template->get_content($page, $params);
}
}
class MarkdownPage extends SimplePage
{
private $filename;
private $params;
private $language;
private $mtime;
private $homepage;
private $breadcrumb_trail;
private static $template;
public function __construct() {
}
// For Future Expansion
public static function fromFile($file, $params) {
$instance = new self();
$instance->initialize_from_file($file, $params);
return $instance;
}
private function initialize_from_file($file, $params) {
$this->title = $file->title;
$this->filename = $file->name;
$this->path = $file->local_path;
$this->mtime = $file->last_modified;
$this->params = $params;
if ($this->title === 'index') {
$this->homepage = ($this->filename === '_index');
$minimum_parent_dir_size = ($params['multilanguage']) ? 2 : 1;
if (count($file->parents) >= $minimum_parent_dir_size) {
$parent = end($file->parents);
$this->title = $parent->title;
} else $this->title = $params['title'];
} else {
$this->homepage = false;
}
if ($params['breadcrumbs'])
$this->breadcrumb_trail = $this->build_breadcrumb_trail($file->parents, $params['multilanguage']);
$this->language = '';
if ($params['multilanguage'] && !empty($file->parents)) {
reset($file->parents);
$language_dir = current($file->parents);
$this->language = $language_dir->name;
}
if (is_null(static::$template)) {
include_once($params['theme']['template']);
static::$template = new Template();
}
}
private function build_breadcrumb_trail($parents, $multilanguage) {
if ($multilanguage && !empty($parents)) $parents = array_splice($parents, 1);
$breadcrumb_trail = array();
if (!empty($parents)) {
foreach ($parents as $node) {
$breadcrumb_trail[$node->title] = $node->get_url();
}
}
return $breadcrumb_trail;
}
public function get_page_content() {
if (is_null($this->html)) {
$this->content = file_get_contents($this->path);
$this->html = $this->generate_page();
}
return $this->html;
}
private function generate_page() {
$params = $this->params;
$Parsedown = new \Parsedown();
if ($params['request'] === $params['index_key']) {
if ($params['multilanguage']) {
foreach ($params['languages'] as $key => $name) {
$entry_page[utf8_encode($name)] = utf8_encode($params['base_page'] . $params['entry_page'][$key]->get_url());
}
} else $entry_page['View Documentation'] = utf8_encode($params['base_page'] . $params['entry_page']->uri);
} else if ($params['file_uri'] === 'index')
$entry_page[utf8_encode($params['entry_page']->title)] = utf8_encode($params['base_page'].
$params['entry_page']->get_url());
$page['entry_page'] = (isset($entry_page)) ? $entry_page : null;
$page['homepage'] = $this->homepage;
$page['title'] = $this->title;
$page['tagline'] = $params['tagline'];
$page['author'] = $params['author'];
$page['filename'] = $this->filename;
if ($page['breadcrumbs'] = $params['breadcrumbs']) {
$page['breadcrumb_trail'] = $this->breadcrumb_trail;
$page['breadcrumb_separator'] = $params['breadcrumb_separator'];
}
$page['language'] = $this->language;
$page['path'] = $this->path;
$page['request'] = utf8_encode($params['request']);
$page['theme'] = $params['theme'];
$page['modified_time'] = filemtime($this->path);
$page['markdown'] = $this->content;
$page['content'] = $Parsedown->text($this->content);
$page['file_editor'] = $params['file_editor'];
$page['google_analytics'] = $params['google_analytics'];
$page['piwik_analytics'] = $params['piwik_analytics'];
return static::$template->get_content($page, $params);
}
}
?>

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Some files were not shown because too many files have changed in this diff Show More