silverstripe-docsviewer/code/DocumentationViewer.php

220 lines
5.5 KiB
PHP
Raw Normal View History

<?php
/**
* Documentation Handler.
*
* Reads the bundled markdown files from doc/ folders and displays output in
* a formatted page
*
* @todo
* - We should move away from relying on DebugViewer. We could even use the actual
* standard template system for the layout
*
* - Abstract html / css out from DebugViewer
*
* @package sapphiredocs
*/
class DocumentationViewer extends Controller {
static $url_handlers = array(
'' => 'index',
'$Module/$Class' => 'parsePage'
);
/**
* An array of files to ignore from the listing
*
* @var array
*/
static $ignored_files = array('.', '..', '.DS_Store', '.svn', '.git');
/**
* Documentation Home
*
* Displays a welcome message as well as links to the sapphire sections and the
* installed modules
*/
function index() {
$renderer = new DebugView();
$renderer->writeHeader();
$renderer->writeInfo("SilverStripe Documentation", '');
$base = Director::baseURL();
// write the main content (sapphire) on the left
echo "<div id='LeftColumn'><div class='box'>";
echo "<h2>Sapphire</h2>";
$this->generateNestedTree('sapphire');
echo "</div></div>";
echo "<div id='RightColumn'>";
$modules = scandir(BASE_PATH);
// generate a list of module documentation (not core)
if($modules) {
foreach($modules as $module) {
// skip sapphire since this is on the left
$ignored_modules = array('sapphire', 'assets', 'themes');
if(!in_array($module, $ignored_modules) && !in_array($module, self::$ignored_files) && is_dir(BASE_PATH .'/'. $module)) {
echo "<div class='box'><h2>". $module ."</h2>";
// see if docs folder is present
$subfolders = scandir(BASE_PATH .'/'. $module);
if($subfolders && in_array('docs', $subfolders)) {
$this->generateNestedTree($module);
}
else {
echo "<p class='noDocs'>No Documentation For Module</p>";
}
echo "</div>";
}
}
}
// for each of the modules. Display them here
echo "</div>";
$renderer->writeFooter();
}
/**
* Parse a given individual markdown page
*
* @param HTTPRequest
*/
function parsePage($request) {
require_once('../sapphiredocs/thirdparty/markdown.php');
$class = $request->param('Class');
$module = $request->param('Module');
if(!stripos($class, '.md')) $class .= '.md';
$renderer = new DebugView();
$renderer->writeHeader();
$renderer->writeInfo("SilverStripe Documentation", '');
$base = Director::baseURL();
// find page
$path = BASE_PATH . '/'. $module .'/docs/';
echo "<div id='LeftColumn'><div class='box'>";
if($page = $this->findPage($path, $class)) {
echo Markdown(file_get_contents($page));
}
else {
echo "<p>Documentation Page Not Found</p>";
}
echo "</div></div> <div id='RightColumn'></div>";
echo '<script type="text/javascript" src="'. Director::absoluteBaseURL(). 'sapphire/thirdparty/jquery/jquery.min.js"></script>
<script type="text/javascript" src="'. Director::absoluteBaseURL() .'sapphiredocs/javascript/DocumentationViewer.js"></script>
';
$renderer->writeFooter();
}
/**
* Find a documentation page within a given module.
*
* @todo Currently this only works on pages - eg if you go /dev/docs/Forms/ it won't show the
* overall forms page
*
* @param String - Name of Module
* @param String - Name of doc page
*
* @return String|false - File path
*/
private function findPage($path, $name) {
// open docs folder
$handle = opendir($path);
if($handle) {
while (false !== ($file = readdir($handle))) {
if(!in_array($file, self::$ignored_files)) {
if(is_dir($path.$file)) {
// keep looking down the tree
return $this->findPage($path.$file, $name);
}
elseif(strtolower($file) == strtolower($name)) {
return $path .'/'. $file;
}
}
}
}
return false;
}
/**
* Generate a nested tree for a given folder via recursion
*
* @param String - module to generate
*/
private function generateNestedTree($module) {
$path = BASE_PATH . '/'. $module .'/docs/';
return (is_dir($path)) ? $this->recursivelyGenerateTree($path, $module) : false;
}
/**
* Recursive method to generate the tree
*
* @param String - folder to work through
* @param String - module we're working through
*/
private function recursivelyGenerateTree($path, $module) {
echo "<ul class='tree'>";
$handle = opendir($path);
if($handle) {
while (false !== ($file = readdir($handle))) {
if(!in_array($file, self::$ignored_files)) {
$newPath = $path.$file;
// if the file is a dir nest the pages
if(is_dir($newPath)) {
// if this has a number
echo "<li class='level'>". $this->formatStringForTitle($file) ."</li>";
$this->recursivelyGenerateTree($newPath, $module);
}
else {
$file = str_ireplace('.md', '', $file);
echo "<li class='page'><a href='". Director::absoluteBaseURL() . 'dev/docs/' . $module .'/'. $file . "'>". $this->formatStringForTitle($file) ."</a></li>";
}
}
}
}
closedir($handle);
echo "</ul>";
}
/**
* Take a file name and generate a 'nice' title for it
*
* @todo find a nicer way of removing the numbers.
*
* @param String
* @return String
*/
private function formatStringForTitle($title) {
// remove numbers if used.
if(substr($title, 2, 1) == '-') $title = substr($title, 3);
// change - to spaces
$title = str_ireplace('-', ' ', $title);
return $title;
}
}