From 33b53fa55d9035c8d604759ee2d663c27baa3f5a Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Thu, 23 Jan 2014 15:27:35 +0100
Subject: [PATCH] added apidoc template based on twitter bootstrap
issue #1797
---
extensions/apidoc/composer.json | 1 +
.../apidoc/templates/bootstrap/Renderer.php | 26 +++
.../templates/bootstrap/SideNavWidget.php | 178 ++++++++++++++++++
.../bootstrap/assets/AssetBundle.php | 33 ++++
.../templates/bootstrap/assets/css/api.css | 99 ++++++++++
.../templates/bootstrap/assets/css/style.css | 52 +++++
.../templates/bootstrap/views/bootstrap.php | 128 +++++++++++++
.../templates/bootstrap/views/index.php | 32 ++++
extensions/apidoc/templates/html/Renderer.php | 7 +-
.../templates/html/views/constSummary.php | 2 +-
.../templates/html/views/eventDetails.php | 4 +-
.../templates/html/views/eventSummary.php | 2 +-
.../templates/html/views/methodDetails.php | 10 +-
.../templates/html/views/methodSummary.php | 2 +-
.../templates/html/views/propertyDetails.php | 8 +-
.../templates/html/views/propertySummary.php | 2 +-
.../apidoc/templates/html/views/type.php | 2 +-
.../apidoc/templates/online/Renderer.php | 8 +-
18 files changed, 571 insertions(+), 25 deletions(-)
create mode 100644 extensions/apidoc/templates/bootstrap/Renderer.php
create mode 100644 extensions/apidoc/templates/bootstrap/SideNavWidget.php
create mode 100644 extensions/apidoc/templates/bootstrap/assets/AssetBundle.php
create mode 100644 extensions/apidoc/templates/bootstrap/assets/css/api.css
create mode 100644 extensions/apidoc/templates/bootstrap/assets/css/style.css
create mode 100644 extensions/apidoc/templates/bootstrap/views/bootstrap.php
create mode 100644 extensions/apidoc/templates/bootstrap/views/index.php
diff --git a/extensions/apidoc/composer.json b/extensions/apidoc/composer.json
index e488f84483..b5a1c9edc7 100644
--- a/extensions/apidoc/composer.json
+++ b/extensions/apidoc/composer.json
@@ -20,6 +20,7 @@
"minimum-stability": "dev",
"require": {
"yiisoft/yii2": "*",
+ "yiisoft/yii2-bootstrap": "*",
"phpdocumentor/reflection": "dev-master | >1.0.2"
},
"autoload": {
diff --git a/extensions/apidoc/templates/bootstrap/Renderer.php b/extensions/apidoc/templates/bootstrap/Renderer.php
new file mode 100644
index 0000000000..1bb1bf5729
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/Renderer.php
@@ -0,0 +1,26 @@
+
+ * @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
diff --git a/extensions/apidoc/templates/bootstrap/SideNavWidget.php b/extensions/apidoc/templates/bootstrap/SideNavWidget.php
new file mode 100644
index 0000000000..2e346a2729
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/SideNavWidget.php
@@ -0,0 +1,178 @@
+ [
+ * [
+ * 'label' => 'Home',
+ * 'url' => ['site/index'],
+ * 'linkOptions' => [...],
+ * ],
+ * [
+ * 'label' => 'Dropdown',
+ * 'items' => [
+ * ['label' => 'Level 1 - Dropdown A', 'url' => '#'],
+ * '',
+ * '',
+ * ['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
+ * @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;
+ }
+}
diff --git a/extensions/apidoc/templates/bootstrap/assets/AssetBundle.php b/extensions/apidoc/templates/bootstrap/assets/AssetBundle.php
new file mode 100644
index 0000000000..0aef5eb654
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/assets/AssetBundle.php
@@ -0,0 +1,33 @@
+
+ * @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,
+ ];
+}
diff --git a/extensions/apidoc/templates/bootstrap/assets/css/api.css b/extensions/apidoc/templates/bootstrap/assets/css/api.css
new file mode 100644
index 0000000000..a3f53eca4c
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/assets/css/api.css
@@ -0,0 +1,99 @@
+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
diff --git a/extensions/apidoc/templates/bootstrap/assets/css/style.css b/extensions/apidoc/templates/bootstrap/assets/css/style.css
new file mode 100644
index 0000000000..57e3de9a23
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/assets/css/style.css
@@ -0,0 +1,52 @@
+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;
+}
diff --git a/extensions/apidoc/templates/bootstrap/views/bootstrap.php b/extensions/apidoc/templates/bootstrap/views/bootstrap.php
new file mode 100644
index 0000000000..8e2c0d67c5
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/views/bootstrap.php
@@ -0,0 +1,128 @@
+beginPage();
+?>
+
+
+
+
+
+
+ head() ?>
+ = Html::encode($this->context->pageTitle) ?>
+
+
+
+beginBody() ?>
+
+ $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();
+ ?>
+
+
+
+ $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,
+ ])?>
+
+
+ = $content ?>
+
+
+
+
+
+
+
*/ ?>
+ = Yii::powered() ?>
+
+
+
+
+endBody() ?>
+
+
+endPage() ?>
\ No newline at end of file
diff --git a/extensions/apidoc/templates/bootstrap/views/index.php b/extensions/apidoc/templates/bootstrap/views/index.php
new file mode 100644
index 0000000000..a8b29fc526
--- /dev/null
+++ b/extensions/apidoc/templates/bootstrap/views/index.php
@@ -0,0 +1,32 @@
+Class Reference
+
+
+
+
+
+
+
+
+ | Class |
+ Description |
+
+$class):
+?>
+
+ | = $this->context->typeLink($class, $class->name) ?> |
+ = \yii\apidoc\helpers\Markdown::process($class->shortDescription, $class) ?> |
+
+
+
diff --git a/extensions/apidoc/templates/html/Renderer.php b/extensions/apidoc/templates/html/Renderer.php
index df7d18eda0..4cca12285d 100644
--- a/extensions/apidoc/templates/html/Renderer.php
+++ b/extensions/apidoc/templates/html/Renderer.php
@@ -107,6 +107,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$fileContent = $this->renderWithLayout($this->typeView, [
'type' => $type,
'docContext' => $context,
+ 'types' => $types,
]);
file_put_contents($dir . '/' . $this->generateFileName($type->name), $fileContent);
Console::updateProgress(++$done, $typeCount);
@@ -166,7 +167,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$links[] = Html::a(
$type->name,
null,
- ['href' => $this->generateLink($type->name)]
+ ['href' => $this->generateUrl($type->name)]
) . $postfix;
}
}
@@ -191,7 +192,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
if (($type = $this->context->getType($subject->definedBy)) === null) {
return $subject->name;
} else {
- $link = $this->generateLink($type->name);
+ $link = $this->generateUrl($type->name);
if ($subject instanceof MethodDoc) {
$link .= '#' . $subject->name . '()';
} else {
@@ -336,7 +337,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
. ' )';
}
- protected function generateLink($typeName)
+ public function generateUrl($typeName)
{
return $this->generateFileName($typeName);
}
diff --git a/extensions/apidoc/templates/html/views/constSummary.php b/extensions/apidoc/templates/html/views/constSummary.php
index b7d55160f3..56200a6743 100644
--- a/extensions/apidoc/templates/html/views/constSummary.php
+++ b/extensions/apidoc/templates/html/views/constSummary.php
@@ -15,7 +15,7 @@ if (empty($type->constants)) {
Hide inherited constants
-
+
diff --git a/extensions/apidoc/templates/html/views/eventDetails.php b/extensions/apidoc/templates/html/views/eventDetails.php
index a5b3091d8b..b869122b22 100644
--- a/extensions/apidoc/templates/html/views/eventDetails.php
+++ b/extensions/apidoc/templates/html/views/eventDetails.php
@@ -13,9 +13,9 @@ if (empty($events)) {
} ?>
Event Details
-