Commit 33b53fa5 by Carsten Brandt

added apidoc template based on twitter bootstrap

issue #1797
parent bf59a521
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"yiisoft/yii2": "*", "yiisoft/yii2": "*",
"yiisoft/yii2-bootstrap": "*",
"phpdocumentor/reflection": "dev-master | >1.0.2" "phpdocumentor/reflection": "dev-master | >1.0.2"
}, },
"autoload": { "autoload": {
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\bootstrap;
use yii\apidoc\models\Context;
use yii\console\Controller;
use Yii;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Renderer extends \yii\apidoc\templates\html\Renderer
{
public $layout = '@yii/apidoc/templates/bootstrap/views/bootstrap.php';
public $indexView = '@yii/apidoc/templates/bootstrap/views/index.php';
public $pageTitle = 'Yii Framework 2.0 API Documentation';
}
\ No newline at end of file
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\bootstrap;
use Yii;
use yii\base\InvalidConfigException;
use yii\bootstrap\BootstrapAsset;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* Nav renders a nav HTML component.
*
* For example:
*
* ```php
* echo Nav::widget([
* 'items' => [
* [
* 'label' => 'Home',
* 'url' => ['site/index'],
* 'linkOptions' => [...],
* ],
* [
* 'label' => 'Dropdown',
* 'items' => [
* ['label' => 'Level 1 - Dropdown A', 'url' => '#'],
* '<li class="divider"></li>',
* '<li class="dropdown-header">Dropdown Header</li>',
* ['label' => 'Level 1 - Dropdown B', 'url' => '#'],
* ],
* ],
* ],
* ]);
* ```
*
* Note: Multilevel dropdowns beyond Level 1 are not supported in Bootstrap 3.
*
* @see http://getbootstrap.com/components.html#dropdowns
* @see http://getbootstrap.com/components/#nav
*
* @author Antonio Ramirez <amigo.cobos@gmail.com>
* @since 2.0
*/
class SideNavWidget extends \yii\bootstrap\Widget
{
/**
* @var array list of items in the nav widget. Each array element represents a single
* menu item which can be either a string or an array with the following structure:
*
* - label: string, required, the nav item label.
* - url: optional, the item's URL. Defaults to "#".
* - visible: boolean, optional, whether this menu item is visible. Defaults to true.
* - linkOptions: array, optional, the HTML attributes of the item's link.
* - options: array, optional, the HTML attributes of the item container (LI).
* - active: boolean, optional, whether the item should be on active state or not.
* - items: array|string, optional, the configuration array for creating a [[Dropdown]] widget,
* or a string representing the dropdown menu. Note that Bootstrap does not support sub-dropdown menus.
*
* If a menu item is a string, it will be rendered directly without HTML encoding.
*/
public $items = [];
/**
* @var boolean whether the nav items labels should be HTML-encoded.
*/
public $encodeLabels = true;
/**
* @var string the route used to determine if a menu item is active or not.
* If not set, it will use the route of the current request.
* @see params
* @see isItemActive
*/
public $activeUrl;
/**
* Initializes the widget.
*/
public function init()
{
parent::init();
if (!isset($this->options['class'])) {
Html::addCssClass($this->options, 'list-group');
}
}
/**
* Renders the widget.
*/
public function run()
{
echo $this->renderItems();
BootstrapAsset::register($this->getView());
}
/**
* Renders widget items.
*/
public function renderItems()
{
$items = [];
foreach ($this->items as $i => $item) {
if (isset($item['visible']) && !$item['visible']) {
unset($items[$i]);
continue;
}
$items[] = $this->renderItem($item);
}
return Html::tag('div', implode("\n", $items), $this->options);
}
/**
* Renders a widget's item.
* @param string|array $item the item to render.
* @return string the rendering result.
* @throws InvalidConfigException
*/
public function renderItem($item)
{
if (is_string($item)) {
return $item;
}
if (!isset($item['label'])) {
throw new InvalidConfigException("The 'label' option is required.");
}
$label = $this->encodeLabels ? Html::encode($item['label']) : $item['label'];
// $options = ArrayHelper::getValue($item, 'options', []);
$items = ArrayHelper::getValue($item, 'items');
$url = Html::url(ArrayHelper::getValue($item, 'url', '#'));
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
Html::addCssClass($linkOptions, 'list-group-item');
if (isset($item['active'])) {
$active = ArrayHelper::remove($item, 'active', false);
} else {
$active = ($url == $this->activeUrl);
}
if ($items !== null) {
$linkOptions['data-toggle'] = 'collapse';
$linkOptions['data-parent'] = '#' . $this->id;
$id = $this->id . '-' . static::$counter++;
$url = '#' . $id;
$label .= ' ' . Html::tag('b', '', ['class' => 'caret']);
if (is_array($items)) {
if ($active === false) {
foreach($items as $subItem) {
if (isset($subItem['active']) && $subItem['active']) {
$active = true;
}
}
}
$items = static::widget([
'id' => $id,
'items' => $items,
'encodeLabels' => $this->encodeLabels,
'view' => $this->getView(),
'options' => [
'class' => "submenu panel-collapse collapse" . ($active ? ' in' : '')
]
]);
}
}
if ($active) {
Html::addCssClass($linkOptions, 'active');
}
return Html::a($label, $url, $linkOptions) . $items;
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\bootstrap\assets;
use yii\web\JqueryAsset;
use yii\web\View;
/**
* The asset bundle for the offline template.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class AssetBundle extends \yii\web\AssetBundle
{
public $sourcePath = '@yii/apidoc/templates/bootstrap/assets/css';
public $css = [
// 'api.css',
'style.css',
];
public $depends = [
'yii\web\JqueryAsset',
'yii\bootstrap\BootstrapAsset',
'yii\bootstrap\BootstrapPluginAsset',
];
public $jsOptions = [
'position' => View::POS_HEAD,
];
}
pre {
color: #000000;
background-color: #FFF5E6;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
/* Put a nice border around it. */
padding: 1px;
width: 90%;
/* Don't wrap its contents, and show scrollbars. */
/* white-space: nowrap;*/
overflow: auto;
/* Stop after about 24 lines, and just show a scrollbar. */
/* max-height: 24em; */
margin: 5px;
padding-left: 20px;
border: 1px solid #FFE6BF;
border-left: 6px solid #FFE6BF;
}
code {
color: #000000;
background-color: #FFF5E6;
padding: 1px;
}
div.code {
display: none;
color: #000000;
background-color: #FFF5E6;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
/* Put a nice border around it. */
padding: 1px;
width: 90%;
/* Don't wrap its contents, and show scrollbars. */
/* white-space: nowrap;*/
overflow: auto;
/* Stop after about 24 lines, and just show a scrollbar. */
/* max-height: 24em; */
margin: 5px;
padding-left: 20px;
border-left: 6px solid #FFE6BF;
}
table.summaryTable {
background: #E6ECFF;
border-collapse: collapse;
width: 100%;
}
table.summaryTable th, table.summaryTable td {
border: 1px #BFCFFF solid;
padding: 0.2em;
}
table.summaryTable th {
background: #CCD9FF;
text-align: left;
}
#nav {
padding: 3px;
margin: 0 0 10px 0;
border-top: 1px #BFCFFF solid;
}
#classDescription {
padding: 5px;
margin: 10px 0 20px 0;
border-bottom: 1px solid #BFCFFF;
}
.detailHeader {
font-weight: bold;
font-size: 12pt;
margin: 30px 0 5px 0;
border-bottom: 1px solid #BFCFFF;
}
.detailHeaderTag {
font-weight: normal;
font-size: 10pt;
}
.paramNameCol {
width: 12%;
font-weight: bold;
}
.paramTypeCol {
width: 12%;
}
.sourceCode {
margin: 5px 0;
padding:5px;
background:#FFF5E6;
}
\ No newline at end of file
html,
body {
height: 100%;
}
.wrap {
min-height: 100%;
height: auto;
width: auto;
margin: 60px 30px 0 30px;
padding: 0;
}
.footer {
height: 60px;
background-color: #f5f5f5;
border-top: 1px solid #ddd;
padding: 20px 30px;
}
#navigation {
margin-top: 20px;
}
.submenu a {
background: #f5f5f5;
border-radius: 0;
}
.submenu a:hover, .submenu a:active,
.submenu a.active, .submenu a.active:hover, .submenu a.active:active {
background: #44b5f6;
border-color: #44b5f6;
border-radius: 0;
color: #fff;
}
.signature, .signature2 {
padding: 3px;
color: #000000;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
white-space: pre-line;
word-wrap: break-word;
word-break: break-all;
}
.signature {
margin: 10px 0 10px 0;
background: #E6ECFF;
border: 1px #BFCFFF solid;
}
<?php
use yii\apidoc\templates\bootstrap\SideNavWidget;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\helpers\Html;
use yii\helpers\StringHelper;
use yii\widgets\Menu;
/**
* @var yii\web\View $this
*/
\yii\apidoc\templates\bootstrap\assets\AssetBundle::register($this);
$this->beginPage();
?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
<meta charset="<?= Yii::$app->charset ?>"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="language" content="en" />
<?php $this->head() ?>
<title><?= Html::encode($this->context->pageTitle) ?></title>
</head>
<body>
<?php $this->beginBody() ?>
<div class="wrap">
<?php
NavBar::begin([
'brandLabel' => $this->context->pageTitle,
'brandUrl' => './index.html',
'options' => [
'class' => 'navbar-inverse navbar-fixed-top',
],
'padded' => false,
'view' => $this,
]);
echo Nav::widget([
'options' => ['class' => 'navbar-nav'],
'items' => [
['label' => 'Class reference', 'url' => './index.html'],
// ['label' => 'Application API', 'url' => '/site/about'],
// ['label' => 'Guide', 'url' => './guide_index.html'],
],
'view' => $this,
]);
NavBar::end();
?>
<!-- <div class="container">-->
<div class="row">
<div class="col-md-2">
<?php
ksort($types);
$nav = [];
foreach($types as $i=>$class) {
$namespace = $class->namespace;
if (empty($namespace)) {
$namespace = 'Not namespaced classes';
}
if (!isset($nav[$namespace])) {
$nav[$namespace] = [
'label' => $namespace,
'url' => '#',
'items' => [],
];
}
$nav[$namespace]['items'][] = [
'label' => StringHelper::basename($class->name),
'url' => './' . $this->context->generateUrl($class->name),
'active' => isset($type) && ($class->name == $type->name),
];
} ?>
<?= SideNavWidget::widget([
'id' => 'navigation',
'items' => $nav,
// 'route' => 'wtf',
'view' => $this,
])?>
</div>
<div class="col-md-9" role="main">
<?= $content ?>
</div>
</div>
<!-- </div>-->
</div>
<footer class="footer">
<?php /* <p class="pull-left">&copy; My Company <?= date('Y') ?></p> */ ?>
<p class="pull-right"><?= Yii::powered() ?></p>
</footer>
<script type="text/javascript">
/*<![CDATA[*/
$("a.toggle").on('click', function() {
var $this = $(this);
if ($this.hasClass('properties-hidden')) {
$this.text($this.text().replace(/Show/,'Hide'));
$this.parents(".summary").find(".inherited").show();
$this.removeClass('properties-hidden');
} else {
$this.text($this.text().replace(/Hide/,'Show'));
$this.parents(".summary").find(".inherited").hide();
$this.addClass('properties-hidden');
}
return false;
});
/*
$(".sourceCode a.show").toggle(function(){
$(this).text($(this).text().replace(/show/,'hide'));
$(this).parents(".sourceCode").find("div.code").show();
},function(){
$(this).text($(this).text().replace(/hide/,'show'));
$(this).parents(".sourceCode").find("div.code").hide();
});
$("a.sourceLink").click(function(){
$(this).attr('target','_blank');
});
*/
/*]]>*/
</script>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
\ No newline at end of file
<?php
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc;
/**
* @var ClassDoc[]|InterfaceDoc[]|TraitDoc[] $types
* @var yii\web\View $this
*/
?><h1>Class Reference</h1>
<table class="summaryTable docIndex table table-bordered table-striped table-hover">
<colgroup>
<col class="col-package" />
<col class="col-class" />
<col class="col-description" />
</colgroup>
<tr>
<th>Class</th>
<th>Description</th>
</tr>
<?php
ksort($types);
foreach($types as $i=>$class):
?>
<tr>
<td><?= $this->context->typeLink($class, $class->name) ?></td>
<td><?= \yii\apidoc\helpers\Markdown::process($class->shortDescription, $class) ?></td>
</tr>
<?php endforeach; ?>
</table>
...@@ -107,6 +107,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -107,6 +107,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$fileContent = $this->renderWithLayout($this->typeView, [ $fileContent = $this->renderWithLayout($this->typeView, [
'type' => $type, 'type' => $type,
'docContext' => $context, 'docContext' => $context,
'types' => $types,
]); ]);
file_put_contents($dir . '/' . $this->generateFileName($type->name), $fileContent); file_put_contents($dir . '/' . $this->generateFileName($type->name), $fileContent);
Console::updateProgress(++$done, $typeCount); Console::updateProgress(++$done, $typeCount);
...@@ -166,7 +167,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -166,7 +167,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$links[] = Html::a( $links[] = Html::a(
$type->name, $type->name,
null, null,
['href' => $this->generateLink($type->name)] ['href' => $this->generateUrl($type->name)]
) . $postfix; ) . $postfix;
} }
} }
...@@ -191,7 +192,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -191,7 +192,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
if (($type = $this->context->getType($subject->definedBy)) === null) { if (($type = $this->context->getType($subject->definedBy)) === null) {
return $subject->name; return $subject->name;
} else { } else {
$link = $this->generateLink($type->name); $link = $this->generateUrl($type->name);
if ($subject instanceof MethodDoc) { if ($subject instanceof MethodDoc) {
$link .= '#' . $subject->name . '()'; $link .= '#' . $subject->name . '()';
} else { } else {
...@@ -336,7 +337,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -336,7 +337,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
. ' )'; . ' )';
} }
protected function generateLink($typeName) public function generateUrl($typeName)
{ {
return $this->generateFileName($typeName); return $this->generateFileName($typeName);
} }
......
...@@ -15,7 +15,7 @@ if (empty($type->constants)) { ...@@ -15,7 +15,7 @@ if (empty($type->constants)) {
<p><a href="#" class="toggle">Hide inherited constants</a></p> <p><a href="#" class="toggle">Hide inherited constants</a></p>
<table class="summaryTable"> <table class="summaryTable table table-striped table-bordered table-hover">
<colgroup> <colgroup>
<col class="col-const" /> <col class="col-const" />
<col class="col-description" /> <col class="col-description" />
......
...@@ -13,9 +13,9 @@ if (empty($events)) { ...@@ -13,9 +13,9 @@ if (empty($events)) {
} ?> } ?>
<h2>Event Details</h2> <h2>Event Details</h2>
<?php foreach($events as $event): ?> <?php foreach($events as $event): ?>
<div class="detailHeader" id="<?= $event->name.'-detail' ?>"> <div class="detailHeader h3" id="<?= $event->name.'-detail' ?>">
<?php echo $event->name; ?> <?php echo $event->name; ?>
<span class="detailHeaderTag"> <span class="detailHeaderTag small">
event event
<?php if(!empty($event->since)): ?> <?php if(!empty($event->since)): ?>
(available since version <?= $event->since ?>) (available since version <?= $event->since ?>)
......
...@@ -15,7 +15,7 @@ if (empty($type->events)) { ...@@ -15,7 +15,7 @@ if (empty($type->events)) {
<p><a href="#" class="toggle">Hide inherited events</a></p> <p><a href="#" class="toggle">Hide inherited events</a></p>
<table class="summaryTable"> <table class="summaryTable table table-striped table-bordered table-hover">
<colgroup> <colgroup>
<col class="col-event" /> <col class="col-event" />
<col class="col-description" /> <col class="col-description" />
......
...@@ -16,9 +16,9 @@ if (empty($methods)) { ...@@ -16,9 +16,9 @@ if (empty($methods)) {
<?php foreach($methods as $method): ?> <?php foreach($methods as $method): ?>
<div class="detailHeader" id="<?= $method->name . '()-detail' ?>"> <div class="detailHeader h3" id="<?= $method->name . '()-detail' ?>">
<?= $method->name ?>() <?= $method->name ?>()
<span class="detailHeaderTag"> <span class="detailHeaderTag small">
method method
<?php if (!empty($method->since)): ?> <?php if (!empty($method->since)): ?>
(available since version <?php echo $method->since; ?>) (available since version <?php echo $method->since; ?>)
...@@ -26,11 +26,9 @@ if (empty($methods)) { ...@@ -26,11 +26,9 @@ if (empty($methods)) {
</span> </span>
</div> </div>
<table class="summaryTable"> <table class="summaryTable table table-striped table-bordered table-hover">
<tr><td colspan="3"> <tr><td colspan="3">
<div class="signature2"> <div class="signature2"><?= $this->context->renderMethodSignature($method) ?></div>
<?= $this->context->renderMethodSignature($method) ?>
</div>
</td></tr> </td></tr>
<?php if(!empty($method->params) || !empty($method->return) || !empty($method->exceptions)): ?> <?php if(!empty($method->params) || !empty($method->return) || !empty($method->exceptions)): ?>
<?php foreach($method->params as $param): ?> <?php foreach($method->params as $param): ?>
......
...@@ -19,7 +19,7 @@ if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && cou ...@@ -19,7 +19,7 @@ if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && cou
<p><a href="#" class="toggle">Hide inherited methods</a></p> <p><a href="#" class="toggle">Hide inherited methods</a></p>
<table class="summaryTable"> <table class="summaryTable table table-striped table-bordered table-hover">
<colgroup> <colgroup>
<col class="col-method" /> <col class="col-method" />
<col class="col-description" /> <col class="col-description" />
......
...@@ -16,9 +16,9 @@ if (empty($properties)) { ...@@ -16,9 +16,9 @@ if (empty($properties)) {
<?php foreach($properties as $property): ?> <?php foreach($properties as $property): ?>
<div class="detailHeader" id="<?= $property->name.'-detail' ?>"> <div class="detailHeader h3" id="<?= $property->name.'-detail' ?>">
<?php echo $property->name; ?> <?php echo $property->name; ?>
<span class="detailHeaderTag"> <span class="detailHeaderTag small">
property property
<?php if($property->getIsReadOnly()) echo ' <em>read-only</em> '; ?> <?php if($property->getIsReadOnly()) echo ' <em>read-only</em> '; ?>
<?php if($property->getIsWriteOnly()) echo ' <em>write-only</em> '; ?> <?php if($property->getIsWriteOnly()) echo ' <em>write-only</em> '; ?>
...@@ -28,9 +28,7 @@ if (empty($properties)) { ...@@ -28,9 +28,7 @@ if (empty($properties)) {
</span> </span>
</div> </div>
<div class="signature"> <div class="signature"><?php echo $this->context->renderPropertySignature($property); ?></div>
<?php echo $this->context->renderPropertySignature($property); ?>
</div>
<p><?= Markdown::process($property->description, $type) ?></p> <p><?= Markdown::process($property->description, $type) ?></p>
......
...@@ -18,7 +18,7 @@ if ($protected && count($type->getProtectedProperties()) == 0 || !$protected && ...@@ -18,7 +18,7 @@ if ($protected && count($type->getProtectedProperties()) == 0 || !$protected &&
<p><a href="#" class="toggle">Hide inherited properties</a></p> <p><a href="#" class="toggle">Hide inherited properties</a></p>
<table class="summaryTable"> <table class="summaryTable table table-striped table-bordered table-hover">
<colgroup> <colgroup>
<col class="col-property" /> <col class="col-property" />
<col class="col-type" /> <col class="col-type" />
......
...@@ -44,7 +44,7 @@ $renderer = $this->context; ...@@ -44,7 +44,7 @@ $renderer = $this->context;
<?php endif; ?> <?php endif; ?>
</div> </div>
<table class="summaryTable docClass"> <table class="summaryTable docClass table table-bordered">
<colgroup> <colgroup>
<col class="col-name" /> <col class="col-name" />
<col class="col-value" /> <col class="col-value" />
......
...@@ -21,8 +21,8 @@ use yii\helpers\StringHelper; ...@@ -21,8 +21,8 @@ use yii\helpers\StringHelper;
*/ */
class Renderer extends \yii\apidoc\templates\html\Renderer class Renderer extends \yii\apidoc\templates\html\Renderer
{ {
public $layout = false;//'@yii/apidoc/templates/offline/views/offline.php'; public $layout = false;
public $indexView = '@yii/apidoc/templates/offline/views/index.php'; public $indexView = '@yii/apidoc/templates/online/views/index.php';
public $pageTitle = 'Yii Framework 2.0 API Documentation'; public $pageTitle = 'Yii Framework 2.0 API Documentation';
...@@ -56,13 +56,13 @@ class Renderer extends \yii\apidoc\templates\html\Renderer ...@@ -56,13 +56,13 @@ class Renderer extends \yii\apidoc\templates\html\Renderer
$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN); $controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
} }
protected function generateLink($typeName) protected function generateUrl($typeName)
{ {
return strtolower(str_replace('\\', '-', $typeName)); return strtolower(str_replace('\\', '-', $typeName));
} }
protected function generateFileName($typeName) protected function generateFileName($typeName)
{ {
return $this->generateLink($typeName) . '.html'; return $this->generateUrl($typeName) . '.html';
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment