mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 11:05:56 +02:00
FEATURE: added support to register versions and modules manually and disable the automatic includsion. FEATURE: added support for multiple versions and languages in the documentation. ENHANCEMENT: added toolbox to view module docs on pages and lots of other new templates
This commit is contained in:
parent
e11837763b
commit
a07855109f
182
code/DocumentationEntity.php
Normal file
182
code/DocumentationEntity.php
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for a documentation entity which is created when registering the
|
||||||
|
* path with {@link DocumentationService::register()}. This refers to a whole package
|
||||||
|
* rather than a specific page but if we need page options we may need to introduce
|
||||||
|
* a class for that.
|
||||||
|
*
|
||||||
|
* @package sapphiredocs
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DocumentationEntity extends ViewableData {
|
||||||
|
|
||||||
|
static $casting = array(
|
||||||
|
'Name' => 'Text'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String $module folder name
|
||||||
|
*/
|
||||||
|
private $moduleFolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String $title nice title
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Array $version version numbers and the paths to each
|
||||||
|
*/
|
||||||
|
private $versions = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Array $langs a list of available langauges
|
||||||
|
*/
|
||||||
|
private $langs = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. You do not need to pass the langs to this as
|
||||||
|
* it will work out the languages from the filesystem
|
||||||
|
*
|
||||||
|
* @param String $module name of module
|
||||||
|
* @param String $version version of this module
|
||||||
|
* @param String $path path to this module
|
||||||
|
*/
|
||||||
|
function __construct($module, $version = '', $path, $title = false) {
|
||||||
|
$this->addVersion($version, $path);
|
||||||
|
$this->title = (!$title) ? $this->module : $title;
|
||||||
|
$this->moduleFolder = $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the languages which are available
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public function getLanguages() {
|
||||||
|
return $this->langs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this entity has a given language
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasLanguage($lang) {
|
||||||
|
return (in_array($lang, $this->langs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a langauge or languages to the entity
|
||||||
|
*
|
||||||
|
* @param Array|String languages
|
||||||
|
*/
|
||||||
|
public function addLanguage($language) {
|
||||||
|
if(is_array($language)) {
|
||||||
|
$this->langs = array_unique(array_merge($this->langs, $language));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->langs[] = $language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the folder name of this module
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function getModuleFolder() {
|
||||||
|
return $this->moduleFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the title of this module
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function getTitle() {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the versions which are available
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public function getVersions() {
|
||||||
|
return array_keys($this->versions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether we have a given version of this entity
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasVersion($version) {
|
||||||
|
return (isset($this->versions[$version]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether we have any versions at all0
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasVersions() {
|
||||||
|
return (sizeof($this->versions) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add another version to this entity
|
||||||
|
*
|
||||||
|
* @param Float $version Version number
|
||||||
|
* @param String $path path to folder
|
||||||
|
*/
|
||||||
|
public function addVersion($version = '', $path) {
|
||||||
|
// determine the langs in this path
|
||||||
|
|
||||||
|
$langs = scandir($path);
|
||||||
|
|
||||||
|
$available = array();
|
||||||
|
|
||||||
|
if($langs) {
|
||||||
|
foreach($langs as $key => $lang) {
|
||||||
|
if(!is_dir($path . $lang) || strlen($lang) > 2 || in_array($lang, DocumentationService::get_ignored_files(), true))
|
||||||
|
$lang = 'en';
|
||||||
|
|
||||||
|
if(!in_array($lang, $available))
|
||||||
|
$available[] = $lang;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addLanguage($available);
|
||||||
|
$this->versions[$version] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a version from this entity
|
||||||
|
*
|
||||||
|
* @param Float $version
|
||||||
|
*/
|
||||||
|
public function removeVersion($version = '') {
|
||||||
|
if(isset($this->versions[$version])) {
|
||||||
|
unset($this->versions[$version]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the path to this documentation entity
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function getPath($version = false, $lang = false) {
|
||||||
|
|
||||||
|
if(!$version) $version = '';
|
||||||
|
if(!$lang) $lang = 'en';
|
||||||
|
|
||||||
|
if(!$this->hasVersion($version)) $path = array_pop($this->versions);
|
||||||
|
else $path = $this->versions[$version];
|
||||||
|
|
||||||
|
return $path . $lang .'/';
|
||||||
|
}
|
||||||
|
}
|
153
code/DocumentationParser.php
Normal file
153
code/DocumentationParser.php
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for MarkdownUltra parsing in the template and related functionality for
|
||||||
|
* parsing paths and documents
|
||||||
|
*
|
||||||
|
* @package sapphiredocs
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DocumentationParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a given path to the documentation for a file. Performs a case insensitive
|
||||||
|
* lookup on the file system. Automatically appends the file extension to one of the markdown
|
||||||
|
* extensions as well so /install/ in a web browser will match /install.md or /INSTALL.md
|
||||||
|
*
|
||||||
|
* @param String $module path to a module
|
||||||
|
* @param Array path of urls. Should be folders, last one is a page
|
||||||
|
*
|
||||||
|
* @return HTMLText
|
||||||
|
*/
|
||||||
|
public static function parse($module, $path) {
|
||||||
|
require_once('../sapphiredocs/thirdparty/markdown.php');
|
||||||
|
|
||||||
|
if($content = self::find_page($module, $path)) {
|
||||||
|
$content = Markdown(file_get_contents($content));
|
||||||
|
|
||||||
|
return DBField::create('HTMLText', $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a documentation page given a path and a file name. It ignores the extensions
|
||||||
|
* and simply compares the title.
|
||||||
|
*
|
||||||
|
* Name may also be a path /install/foo/bar.
|
||||||
|
*
|
||||||
|
* @param String $entity path to the entity
|
||||||
|
* @param Array $path path to the file in the entity
|
||||||
|
*
|
||||||
|
* @return String|false - File path
|
||||||
|
*/
|
||||||
|
private static function find_page($entity, $path) {
|
||||||
|
return self::find_page_recursive($entity, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function for finding the goal
|
||||||
|
*/
|
||||||
|
private static function find_page_recursive($base, $goal) {
|
||||||
|
$handle = opendir($base);
|
||||||
|
|
||||||
|
$name = strtolower(array_shift($goal));
|
||||||
|
|
||||||
|
if(!$name) $name = 'index';
|
||||||
|
|
||||||
|
if($handle) {
|
||||||
|
$extensions = DocumentationService::get_valid_extensions();
|
||||||
|
|
||||||
|
while (false !== ($file = readdir($handle))) {
|
||||||
|
if(in_array($file, DocumentationService::get_valid_extensions())) continue;
|
||||||
|
|
||||||
|
$formatted = strtolower($file);
|
||||||
|
|
||||||
|
// if the name has a . then take the substr
|
||||||
|
$formatted = ($pos = strrpos($formatted, '.')) ? substr($formatted, 0, $pos) : $formatted;
|
||||||
|
$name = ($dot = strrpos($formatted, '.')) ? substr($name, 0, $dot) : $name;
|
||||||
|
|
||||||
|
// the folder is the one that we are looking for.
|
||||||
|
if($name == $formatted) {
|
||||||
|
|
||||||
|
if(is_dir($base . $file)) {
|
||||||
|
// if this is a directory check that there is any more states to get
|
||||||
|
// to in the goal. If none then what we want is the 'index.md' file
|
||||||
|
if(count($goal) > 0) {
|
||||||
|
return self::find_page_recursive($base . $file, $goal);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// recurse but check for an index.md file next time around
|
||||||
|
return self::find_page_recursive($base . $file, array('index'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// goal state. End of recursion
|
||||||
|
$result = $base .'/'. $file;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String helper for cleaning a file name to a readable version.
|
||||||
|
*
|
||||||
|
* @param String $name to convert
|
||||||
|
*
|
||||||
|
* @return String $name output
|
||||||
|
*/
|
||||||
|
public static function clean_page_name($name) {
|
||||||
|
// remove dashs and _
|
||||||
|
$name = str_ireplace(array('-', '_'), ' ', $name);
|
||||||
|
|
||||||
|
// remove extension
|
||||||
|
$hasExtension = strpos($name, '.');
|
||||||
|
|
||||||
|
if($hasExtension !== false && $hasExtension > 0) {
|
||||||
|
$name = substr($name, 0, $hasExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert first letter
|
||||||
|
return ucfirst($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the children from a given module. Used for building the tree of the page
|
||||||
|
*
|
||||||
|
* @param String module name
|
||||||
|
*
|
||||||
|
* @return DataObjectSet
|
||||||
|
*/
|
||||||
|
public static function get_pages_from_folder($folder) {
|
||||||
|
$handle = opendir($folder);
|
||||||
|
$output = new DataObjectSet();
|
||||||
|
|
||||||
|
if($handle) {
|
||||||
|
$extensions = DocumentationService::get_valid_extensions();
|
||||||
|
$ignore = DocumentationService::get_ignored_files();
|
||||||
|
|
||||||
|
while (false !== ($file = readdir($handle))) {
|
||||||
|
if(!in_array($file, $ignore)) {
|
||||||
|
$file = strtolower($file);
|
||||||
|
|
||||||
|
$clean = ($pos = strrpos($file, '.')) ? substr($file, 0, $pos) : $file;
|
||||||
|
|
||||||
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => self::clean_page_name($file),
|
||||||
|
'Filename' => $clean,
|
||||||
|
'Path' => $folder . $file .'/'
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
}
|
342
code/DocumentationService.php
Normal file
342
code/DocumentationService.php
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DocumentationService
|
||||||
|
*
|
||||||
|
* Handles the management of the documentation services delivered by the module.
|
||||||
|
* Includes registering which components to document and handles the entities being
|
||||||
|
* documented
|
||||||
|
*
|
||||||
|
* @todo - unregistering a lang / version from site does not update the registered_* arrays
|
||||||
|
* - handle modules (rather than core) differently
|
||||||
|
* @package sapphiredocs
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DocumentationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping of know / popular languages to nice titles.
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
private static $language_mapping = array(
|
||||||
|
'en' => 'English',
|
||||||
|
'fr' => 'French',
|
||||||
|
'de' => 'German'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Files to ignore from any documentation listing.
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
private static $ignored_files = array('.', '..', '.DS_Store', '.svn', '.git', 'assets', 'themes');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the ignored files list
|
||||||
|
*
|
||||||
|
* @param Array
|
||||||
|
*/
|
||||||
|
public function set_ignored_files($files) {
|
||||||
|
self::$ignored_files = $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of files which are ignored
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public function get_ignored_files() {
|
||||||
|
return self::$ignored_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Case insenstive values to use as extensions on markdown pages.
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
public static $valid_markdown_extensions = array('.md', '.txt', '.markdown');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the allowed extensions
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function get_valid_extensions() {
|
||||||
|
return self::$valid_markdown_extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered modules to include in the documentation. Either pre-filled by the
|
||||||
|
* automatic filesystem parser or via {@link DocumentationService::register()}. Stores
|
||||||
|
* {@link DocumentEntity} objects which contain the languages and versions of each module.
|
||||||
|
*
|
||||||
|
* You can remove registered modules using {@link DocumentationService::unregister()}
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
private static $registered_modules = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Major Versions store. We don't want to register all versions of every module in
|
||||||
|
* the documentation but for sapphire/cms and overall we need to register major
|
||||||
|
* versions via {@link DocumentationService::register}
|
||||||
|
*
|
||||||
|
* @var Array
|
||||||
|
*/
|
||||||
|
private static $major_versions = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the major versions
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function get_major_versions() {
|
||||||
|
return self::$major_versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a given language is registered in the system
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function is_registered_language($lang) {
|
||||||
|
$langs = self::get_registered_languages();
|
||||||
|
|
||||||
|
return (isset($langs[$lang]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the registered languages. Optionally limited to a module. Includes
|
||||||
|
* the nice titles
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function get_registered_languages($module = false) {
|
||||||
|
$langs = array();
|
||||||
|
|
||||||
|
if($module) {
|
||||||
|
if(isset(self::$registered_modules[$module])) {
|
||||||
|
$langs = self::$registered_modules[$module]->getLanguages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if($modules = self::get_registered_modules()) {
|
||||||
|
|
||||||
|
foreach($modules as $module) {
|
||||||
|
$langs = array_unique(array_merge($langs, $module->getLanguages()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = array();
|
||||||
|
foreach($langs as $lang) {
|
||||||
|
$output[$lang] = self::get_language_title($lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the registered versions in the system. Optionally only
|
||||||
|
* include versions from a module.
|
||||||
|
*
|
||||||
|
* @param String $module module to check for versions
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_registered_versions($module = false) {
|
||||||
|
if($module) {
|
||||||
|
if(isset($registered_modules[$module])) {
|
||||||
|
return $registered_modules[$module]->getVersions();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$major_versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should generation of documentation categories be automatic. If this
|
||||||
|
* is set to true then it will generate documentation sections (modules) from
|
||||||
|
* the filesystem. This can be slow and also some projects may want to restrict
|
||||||
|
* to specific project folders (rather than everything).
|
||||||
|
*
|
||||||
|
* You can also disable or remove a given folder from registration using
|
||||||
|
* {@link DocumentationService::unregister()}
|
||||||
|
*
|
||||||
|
* @see DocumentationService::$registered_modules
|
||||||
|
* @see DocumentationService::set_automatic_registration();
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private static $automatic_registration = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set automatic registration of modules and documentation folders
|
||||||
|
*
|
||||||
|
* @see DocumentationService::$automatic_registration
|
||||||
|
* @param bool
|
||||||
|
*/
|
||||||
|
public static function set_automatic_registration($bool = true) {
|
||||||
|
self::$automatic_registration = $bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is automatic registration of modules enabled.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function automatic_registration_enabled() {
|
||||||
|
return self::$automatic_registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the modules which are listed for documentation. Optionally only get
|
||||||
|
* modules which have a version or language given
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function get_registered_modules($version = false, $lang = false) {
|
||||||
|
$output = array();
|
||||||
|
|
||||||
|
if($modules = self::$registered_modules) {
|
||||||
|
if($version || $lang) {
|
||||||
|
foreach($modules as $module) {
|
||||||
|
if(self::is_registered_module($module->getModuleFolder(), $version, $lang)) {
|
||||||
|
$output[] = $module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$output = $modules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a module is registered with the documenter
|
||||||
|
*
|
||||||
|
* @param String $module module name
|
||||||
|
* @param String $version version
|
||||||
|
* @param String $lang language
|
||||||
|
*
|
||||||
|
* @return DocumentationEntity $module the registered module
|
||||||
|
*/
|
||||||
|
public static function is_registered_module($module, $version = false, $lang = false) {
|
||||||
|
|
||||||
|
if(isset(self::$registered_modules[$module])) {
|
||||||
|
$module = self::$registered_modules[$module];
|
||||||
|
|
||||||
|
if($lang && !$module->hasLanguage($lang)) return false;
|
||||||
|
|
||||||
|
if($version && !$module->hasVersion($version)) return false;
|
||||||
|
|
||||||
|
return $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a module to be included in the documentation. To unregister a module
|
||||||
|
* use {@link DocumentationService::unregister()}. Must include the trailing slash
|
||||||
|
*
|
||||||
|
* @param String $module Name of module to register
|
||||||
|
* @param String $path Path to documentation root.
|
||||||
|
* @param Float $version Version of module.
|
||||||
|
* @param String $title Nice title to use
|
||||||
|
* @param bool $major is this a major release
|
||||||
|
*/
|
||||||
|
public static function register($module, $path, $version = '', $title = false, $major = false) {
|
||||||
|
|
||||||
|
// add the module to the registered array
|
||||||
|
if(!isset(self::$registered_modules[$module])) {
|
||||||
|
// module is completely new
|
||||||
|
$entity = new DocumentationEntity($module, $version, $path, $title);
|
||||||
|
|
||||||
|
self::$registered_modules[$module] = $entity;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// module exists so add the version to it
|
||||||
|
$entity = self::$registered_modules[$module];
|
||||||
|
|
||||||
|
$entity->addVersion($version, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($major) {
|
||||||
|
if(!$version) $version = '';
|
||||||
|
|
||||||
|
if(!in_array($version, self::$major_versions)) {
|
||||||
|
self::$major_versions[] = $version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a module from being included in the documentation. Useful
|
||||||
|
* for keeping {@link DocumentationService::$automatic_registration} enabled
|
||||||
|
* but disabling modules which you do not want to show. Combined with a
|
||||||
|
* {@link Director::isLive()} you can hide modules you don't want a client to see.
|
||||||
|
*
|
||||||
|
* If no version or lang specified then the whole module is removed. Otherwise only
|
||||||
|
* the specified version of the documentation.
|
||||||
|
*
|
||||||
|
* @param String $module
|
||||||
|
* @param String $version
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function unregister($module, $version = '') {
|
||||||
|
if(isset(self::$registered_modules[$module])) {
|
||||||
|
$module = self::$registered_modules[$module];
|
||||||
|
|
||||||
|
if($version) {
|
||||||
|
$module->removeVersion($version);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// only given a module so unset the whole module
|
||||||
|
unset(self::$registered_modules[$module]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the docs from off a file system if automatic registration is turned on.
|
||||||
|
*/
|
||||||
|
public static function load_automatic_registration() {
|
||||||
|
if(self::automatic_registration_enabled()) {
|
||||||
|
$modules = scandir(BASE_PATH);
|
||||||
|
|
||||||
|
if($modules) {
|
||||||
|
foreach($modules as $key => $module) {
|
||||||
|
if(is_dir(BASE_PATH .'/'. $module) && !in_array($module, self::$ignored_files, true)) {
|
||||||
|
// check to see if it has docs
|
||||||
|
$docs = BASE_PATH .'/'. $module .'/docs/';
|
||||||
|
|
||||||
|
if(is_dir($docs)) {
|
||||||
|
self::register($module, $docs, '', $module, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a language code to a 'nice' text string. Uses the
|
||||||
|
* {@link self::$language_mapping} array combined with translatable.
|
||||||
|
*
|
||||||
|
* @param String $code code
|
||||||
|
*/
|
||||||
|
public static function get_language_title($lang) {
|
||||||
|
return (isset(self::$language_mapping[$lang])) ? _t("DOCUMENTATIONSERVICE.LANG-$lang", self::$language_mapping[$lang]) : $lang;
|
||||||
|
}
|
||||||
|
}
|
@ -3,277 +3,420 @@
|
|||||||
/**
|
/**
|
||||||
* Documentation Viewer.
|
* Documentation Viewer.
|
||||||
*
|
*
|
||||||
* Reads the bundled markdown files from docs/ folders and displays output in a formatted page at /dev/docs/.
|
* Reads the bundled markdown files from documentation folders and displays the output (either
|
||||||
* For more documentation on how to use this class see the documentation online in /dev/docs/ or in the
|
* via markdown or plain text)
|
||||||
* /sapphiredocs/docs folder
|
*
|
||||||
|
* For more documentation on how to use this class see the documentation in /sapphiredocs/docs folder
|
||||||
|
*
|
||||||
|
* To view the documentation in the browser use:
|
||||||
|
*
|
||||||
|
* http://yoursite.com/dev/docs/ Which is locked to ADMIN only
|
||||||
|
*
|
||||||
|
* @todo - Add ability to have docs on the front end as the main site.
|
||||||
|
* - Fix Language Selector (enabling it troubles the handleRequest when submitting)
|
||||||
|
* - SS_HTTPRequest when we ask for 10 params it gives us 10. Could be 10 blank ones.
|
||||||
|
* It would mean I could save alot of code if it only gave back an array of size X
|
||||||
|
* up to a maximum of 10...
|
||||||
*
|
*
|
||||||
* @author Will Rossiter <will@silverstripe.com>
|
|
||||||
* @package sapphiredocs
|
* @package sapphiredocs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class DocumentationViewer extends Controller {
|
class DocumentationViewer extends Controller {
|
||||||
|
|
||||||
static $url_handlers = array(
|
static $allowed_actions = array(
|
||||||
'' => 'index',
|
'LanguageForm',
|
||||||
'$Module/$Page/$OtherPage' => 'parse'
|
'doLanguageForm',
|
||||||
|
'handleRequest',
|
||||||
|
'fr', // better way of handling this?
|
||||||
|
'en'
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
static $casting = array(
|
||||||
* An array of files to ignore from the listing
|
'Version' => 'Text',
|
||||||
*
|
'Lang' => 'Text',
|
||||||
* @var array
|
'Module' => 'Text',
|
||||||
*/
|
'LanguageTitle' => 'Text'
|
||||||
static $ignored_files = array('.', '..', '.DS_Store', '.svn', '.git', 'assets', 'themes');
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of case insenstive values to use as readmes
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
static $readme_files = array('readme', 'readme.md', 'readme.txt', 'readme.markdown');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
function init() {
|
||||||
* Main documentation page
|
parent::init();
|
||||||
*/
|
|
||||||
function index() {
|
$canAccess = (Director::isDev() || Director::is_cli() || Permission::check("ADMIN"));
|
||||||
return $this->customise(array(
|
|
||||||
'DocumentedModules' => $this->DocumentedModules()
|
if(!$canAccess) return Security::permissionFailure($this);
|
||||||
))->renderWith(array('DocumentationViewer_index', 'DocumentationViewer'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Individual documentation page
|
* Handle the url parsing for the documentation. In order to make this
|
||||||
|
* user friendly this does some tricky things..
|
||||||
*
|
*
|
||||||
* @param HTTPRequest
|
* The urls which should work
|
||||||
|
* / - index page
|
||||||
|
* /en/sapphire - the index page of sapphire (shows versions)
|
||||||
|
* /2.4/en/sapphire - the docs for 2.4 sapphire.
|
||||||
|
* /2.4/en/sapphire/installation/
|
||||||
|
*
|
||||||
|
* @return SS_HTTPResponse
|
||||||
*/
|
*/
|
||||||
function parse($request) {
|
public function handleRequest(SS_HTTPRequest $request) {
|
||||||
require_once('../sapphiredocs/thirdparty/markdown.php');
|
|
||||||
|
|
||||||
$page = $request->param('Page');
|
$this->Version = $request->shift();
|
||||||
$module = $request->param('Module');
|
$this->Lang = $request->shift();
|
||||||
|
|
||||||
$path = BASE_PATH .'/'. $module .'/docs';
|
$this->Remaining = $request->shift(10);
|
||||||
|
|
||||||
if($content = $this->findPage($path, $page)) {
|
DocumentationService::load_automatic_registration();
|
||||||
$title = $page;
|
|
||||||
$content = Markdown(file_get_contents($content));
|
if(isset($this->Version)) {
|
||||||
|
// check to see if its a valid version. If its not a float then its not actually a version
|
||||||
|
// its actually a language and it needs to change. So this means we support 2 structures
|
||||||
|
// /2.4/en/sapphire/page and
|
||||||
|
// /en/sapphire/page which is a link to the latest one
|
||||||
|
|
||||||
|
if(!is_numeric($this->Version)) {
|
||||||
|
// not numeric so /en/sapphire/folder/page
|
||||||
|
if(isset($this->Lang) && $this->Lang)
|
||||||
|
array_unshift($this->Remaining, $this->Lang);
|
||||||
|
|
||||||
|
$this->Lang = $this->Version;
|
||||||
|
$this->Version = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$title = 'Page not Found';
|
// if(!DocumentationService::is_registered_version($this->Version)) {
|
||||||
$content = false;
|
// $this->httpError(404, 'The requested version could not be found.');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isset($this->Lang)) {
|
||||||
|
// check to see if its a valid language
|
||||||
|
// if(!DocumentationService::is_registered_language($this->Lang)) {
|
||||||
|
// $this->httpError(404, 'The requested language could not be found.');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->Lang = 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->customise(array(
|
return parent::handleRequest($request);
|
||||||
'Title' => $title,
|
|
||||||
'Content' => $content
|
|
||||||
))->renderWith('DocumentationViewer');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of the modules installed. Currently to determine if a module is
|
* Custom templates for each of the sections.
|
||||||
* installed look at all the folders and check is a _config file.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function getModules() {
|
function getViewer($action) {
|
||||||
$modules = scandir(BASE_PATH);
|
// count the number of parameters after the language, version are taken
|
||||||
|
// into account. This automatically includes ' ' so all the counts
|
||||||
|
// are 1 more than what you would expect
|
||||||
|
|
||||||
if($modules) {
|
if($this->Remaining) {
|
||||||
foreach($modules as $key => $module) {
|
$params = count(array_unique($this->Remaining));
|
||||||
if(!is_dir(BASE_PATH .'/'. $module) || in_array($module, self::$ignored_files, true) || !file_exists(BASE_PATH . '/'. $module .'/_config.php')) {
|
|
||||||
unset($modules[$key]);
|
switch($params) {
|
||||||
|
case '1':
|
||||||
|
return parent::getViewer('home');
|
||||||
|
case '2':
|
||||||
|
return parent::getViewer('folder');
|
||||||
|
default:
|
||||||
|
if($module = $this->getModule()) {
|
||||||
|
$params = $this->Remaining;
|
||||||
|
array_shift($params);
|
||||||
|
|
||||||
|
$path = implode('/', array_unique($params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(is_dir($module->getPath() . $path)) return parent::getViewer('folder');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $modules;
|
return parent::getViewer($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a set of modules for the home page
|
* Return all the available languages. Optionally the languages which are
|
||||||
|
* available for a given module
|
||||||
*
|
*
|
||||||
|
* @param String - The name of the module
|
||||||
* @return DataObjectSet
|
* @return DataObjectSet
|
||||||
*/
|
*/
|
||||||
function DocumentedModules() {
|
function getLanguages($module = false) {
|
||||||
|
$output = new DataObjectSet();
|
||||||
|
|
||||||
$modules = new DataObjectSet();
|
if($module) {
|
||||||
|
// lookup the module for the available languages
|
||||||
|
|
||||||
// include sapphire first
|
// @todo
|
||||||
$modules->push(new ArrayData(array(
|
}
|
||||||
'Title' => 'sapphire',
|
else {
|
||||||
'Content' => $this->generateNestedTree('sapphire'),
|
$languages = DocumentationService::get_registered_languages();
|
||||||
'Readme' => $this->readmeExists('sapphire')
|
|
||||||
)));
|
|
||||||
|
|
||||||
$extra_ignore = array('sapphire');
|
if($languages) {
|
||||||
|
foreach($languages as $key => $lang) {
|
||||||
|
|
||||||
foreach($this->getModules() as $module) {
|
if(stripos($_SERVER['REQUEST_URI'], '/'. $this->Lang .'/') === false) {
|
||||||
if(!in_array($module, $extra_ignore) && $this->moduleHasDocs($module)) {
|
// no language is in the URL currently. It needs to insert the language
|
||||||
$modules->push(new ArrayData(array(
|
// into the url like /sapphire/install to /en/sapphire/install
|
||||||
'Title' => $module,
|
//
|
||||||
'Content' => $this->generateNestedTree($module),
|
// @todo
|
||||||
'Readme' => $this->readmeExists($module)
|
}
|
||||||
|
|
||||||
|
$link = str_ireplace('/'.$this->Lang .'/', '/'. $lang .'/', $_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => $lang,
|
||||||
|
'Link' => $link
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $modules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a list of modules (folder which has a _config) which have no /docs/ folder
|
|
||||||
*
|
|
||||||
* @return DataObjectSet
|
|
||||||
*/
|
|
||||||
function UndocumentedModules() {
|
|
||||||
$modules = $this->getModules();
|
|
||||||
$undocumented = array();
|
|
||||||
|
|
||||||
if($modules) {
|
|
||||||
foreach($modules as $module) {
|
|
||||||
if(!$this->moduleHasDocs($module)) $undocumented[] = $module;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode(', ', $undocumented);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to determine whether a module has documentation
|
|
||||||
*
|
|
||||||
* @param String - Module folder name
|
|
||||||
* @return bool - Has docs folder
|
|
||||||
*/
|
|
||||||
function moduleHasDocs($module) {
|
|
||||||
return is_dir(BASE_PATH .'/'. $module .'/docs/');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Work out if a module contains a readme
|
|
||||||
*
|
|
||||||
* @param String - Module to check
|
|
||||||
* @return bool|String - of path
|
|
||||||
*/
|
|
||||||
private function readmeExists($module) {
|
|
||||||
$children = scandir(BASE_PATH.'/'.$module);
|
|
||||||
|
|
||||||
$readmeOptions = self::$readme_files;
|
|
||||||
|
|
||||||
if($children) {
|
|
||||||
foreach($children as $i => $file) {
|
|
||||||
if(in_array(strtolower($file), $readmeOptions)) return $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a documentation page within a given module.
|
|
||||||
*
|
|
||||||
* @param String - Path to 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))) {
|
|
||||||
$newpath = $path .'/'. $file;
|
|
||||||
|
|
||||||
if(!in_array($file, self::$ignored_files)) {
|
|
||||||
|
|
||||||
if(is_dir($newpath)) return $this->findPage($newpath, $name);
|
|
||||||
|
|
||||||
elseif(strtolower($this->formatStringForTitle($file)) == strtolower($name)) {
|
|
||||||
return $newpath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, $output = '') {
|
|
||||||
$output .= "<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
|
|
||||||
$output .= "<li class='folder'>". $this->formatStringForTitle($file) ."</li>";
|
|
||||||
|
|
||||||
$output = $this->recursivelyGenerateTree($newPath, $module, $output);
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$offset = (strpos($file,'-') > 0) ? strpos($file,'-') + 1 : 0;
|
|
||||||
|
|
||||||
$file = substr(str_ireplace('.md', '', $file), $offset);
|
|
||||||
|
|
||||||
$output .= "<li class='page'><a href='". Director::absoluteBaseURL() . 'dev/docs/' . $module .'/'. $file . "'>". $this->formatStringForTitle($file) ."</a></li>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir($handle);
|
|
||||||
$output .= "</ul>";
|
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a file name and generate a 'nice' title for it.
|
* Get all the versions loaded into the module. If the project is only displaying from
|
||||||
|
* the filesystem then they are loaded under the 'Current' namespace.
|
||||||
*
|
*
|
||||||
* example. 01-Getting-Started -> Getting Started
|
* @todo Only show 'core' versions (2.3, 2.4) versions of the modules are going
|
||||||
|
* to spam this
|
||||||
*
|
*
|
||||||
* @param String - raw title
|
* @param String $module name of module to limit it to eg sapphire
|
||||||
* @return String - nicely formatted one
|
* @return DataObjectSet
|
||||||
*/
|
*/
|
||||||
private function formatStringForTitle($title) {
|
function getVersions($module = false) {
|
||||||
// remove numbers if used.
|
$versions = DocumentationService::get_registered_versions($module);
|
||||||
if(substr($title, 2, 1) == '-') $title = substr($title, 3);
|
$output = new DataObjectSet();
|
||||||
|
|
||||||
// change - to spaces
|
foreach($versions as $key => $version) {
|
||||||
$title = str_ireplace('-', ' ', $title);
|
// work out the link to this version of the documentation.
|
||||||
|
//
|
||||||
|
// @todo Keep the user on their given page rather than redirecting to module.
|
||||||
|
// @todo Get links working
|
||||||
|
$linkingMode = ($this->Version == $version) ? 'current' : 'link';
|
||||||
|
|
||||||
// remove extension
|
if(!$version) $version = 'Current';
|
||||||
$title = str_ireplace(array('.md', '.markdown'), '', $title);
|
$major = (in_array($version, DocumentationService::get_major_versions())) ? true : false;
|
||||||
|
|
||||||
return $title;
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => $version,
|
||||||
|
'Link' => $_SERVER['REQUEST_URI'],
|
||||||
|
'LinkingMode' => $linkingMode,
|
||||||
|
'MajorRelease' => $major
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the module which are to be documented. It filters
|
||||||
|
* the list based on the current head version. It displays the contents
|
||||||
|
* from the index.md file on the page to use.
|
||||||
|
*
|
||||||
|
* @return DataObject
|
||||||
|
*/
|
||||||
|
function getModules($version = false, $lang = false) {
|
||||||
|
if(!$version) $version = $this->Version;
|
||||||
|
if(!$lang) $lang = $this->Lang;
|
||||||
|
|
||||||
|
$modules = DocumentationService::get_registered_modules($version, $lang);
|
||||||
|
$output = new DataObjectSet();
|
||||||
|
|
||||||
|
if($modules) {
|
||||||
|
foreach($modules as $module) {
|
||||||
|
// build the dataset. Load the $Content from an index.md
|
||||||
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => $module->getTitle(),
|
||||||
|
'Code' => $module,
|
||||||
|
'Content' => DocumentationParser::parse($module->getPath(), array('index'))
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently accessed entity from the site.
|
||||||
|
*
|
||||||
|
* @return false|DocumentationEntity
|
||||||
|
*/
|
||||||
|
function getModule() {
|
||||||
|
if($this->Remaining && is_array($this->Remaining)) {
|
||||||
|
return DocumentationService::is_registered_module($this->Remaining[0], $this->Version, $this->Lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the related pages to this module and the children to those pages
|
||||||
|
*
|
||||||
|
* @todo this only handles 2 levels. Could make it recursive
|
||||||
|
*
|
||||||
|
* @return false|DataObjectSet
|
||||||
|
*/
|
||||||
|
function getModulePages() {
|
||||||
|
if($module = $this->getModule()) {
|
||||||
|
$pages = DocumentationParser::get_pages_from_folder($module->getPath());
|
||||||
|
|
||||||
|
if($pages) {
|
||||||
|
foreach($pages as $page) {
|
||||||
|
$linkParts = array($module->getModuleFolder());
|
||||||
|
|
||||||
|
// don't include the 'index in the url
|
||||||
|
if($page->Title != "Index") $linkParts[] = $page->Filename;
|
||||||
|
|
||||||
|
$page->Link = $this->Link($linkParts);
|
||||||
|
|
||||||
|
$page->LinkingMode = 'link';
|
||||||
|
$page->Children = false;
|
||||||
|
|
||||||
|
if(isset($this->Remaining[1])) {
|
||||||
|
if(strtolower($this->Remaining[1]) == $page->Filename) {
|
||||||
|
$page->LinkingMode = 'current';
|
||||||
|
|
||||||
|
if(is_dir($page->Path)) {
|
||||||
|
$children = DocumentationParser::get_pages_from_folder($page->Path);
|
||||||
|
$segments = array($module->getModuleFolder(), $this->Remaining[1]);
|
||||||
|
|
||||||
|
foreach($children as $child) {
|
||||||
|
$child->Link = $this->Link(array_merge($segments, array($child->Filename)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$page->Children = $children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the content for the page. If its an actual documentation page then
|
||||||
|
* display the content from the page, otherwise display the contents from
|
||||||
|
* the index.md file if its a folder
|
||||||
|
*
|
||||||
|
* @return HTMLText
|
||||||
|
*/
|
||||||
|
function getContent() {
|
||||||
|
if($module = $this->getModule()) {
|
||||||
|
// name of the module. Throw it away since we already have the module path.
|
||||||
|
$filepath = $this->Remaining;
|
||||||
|
array_shift($filepath);
|
||||||
|
|
||||||
|
return DocumentationParser::parse($module->getPath(), $filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a list of breadcrumbs for the user. Based off the remaining params
|
||||||
|
* in the url
|
||||||
|
*
|
||||||
|
* @return DataObjectSet
|
||||||
|
*/
|
||||||
|
function getBreadcrumbs() {
|
||||||
|
$pages = $this->Remaining;
|
||||||
|
|
||||||
|
$output = new DataObjectSet();
|
||||||
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => ($this->Version) ? $this->Version : _t('DocumentationViewer.DOCUMENTATION', 'Documentation'),
|
||||||
|
'Link' => $this->Link()
|
||||||
|
)));
|
||||||
|
|
||||||
|
if($pages) {
|
||||||
|
$path = array();
|
||||||
|
|
||||||
|
foreach($pages as $page => $title) {
|
||||||
|
if($title) {
|
||||||
|
$path[] = $title;
|
||||||
|
|
||||||
|
$output->push(new ArrayData(array(
|
||||||
|
'Title' => DocumentationParser::clean_page_name($title),
|
||||||
|
'Link' => $this->Link($path)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the base link to this documentation location
|
||||||
|
*
|
||||||
|
* @todo Make this work on non /dev/
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function Link($path = false) {
|
||||||
|
$base = Director::absoluteBaseURL();
|
||||||
|
|
||||||
|
// @todo
|
||||||
|
$loc = 'dev/docs/';
|
||||||
|
|
||||||
|
$version = ($this->Version) ? $this->Version . '/' : false;
|
||||||
|
$lang = ($this->Lang) ? $this->Lang .'/' : false;
|
||||||
|
|
||||||
|
$action = '';
|
||||||
|
if(is_string($path)) $action = $path . '/';
|
||||||
|
|
||||||
|
if(is_array($path)) {
|
||||||
|
foreach($path as $key => $value) {
|
||||||
|
if($value) {
|
||||||
|
$action .= $value .'/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $base . $loc . $version . $lang . $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the language dropdown.
|
||||||
|
*
|
||||||
|
* @todo do this on a page by page rather than global
|
||||||
|
*
|
||||||
|
* @return Form
|
||||||
|
*/
|
||||||
|
function LanguageForm() {
|
||||||
|
if($module = $this->getModule()) {
|
||||||
|
$langs = DocumentationService::get_registered_languages($module->getModuleFolder());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$langs = DocumentationService::get_registered_languages();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = new FieldSet(
|
||||||
|
$dropdown = new DropdownField(
|
||||||
|
'LangCode',
|
||||||
|
_t('DocumentationViewer.LANGUAGE', 'Language'),
|
||||||
|
$langs,
|
||||||
|
$this->Lang
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$actions = new FieldSet(
|
||||||
|
new FormAction('doLanguageForm', _t('DocumentationViewer.CHANGE', 'Change'))
|
||||||
|
);
|
||||||
|
|
||||||
|
$dropdown->setDisabled(true);
|
||||||
|
|
||||||
|
return new Form($this, 'LanguageForm', $fields, $actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the language change
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function doLanguageForm($data, $form) {
|
||||||
|
$this->Lang = (isset($data['LangCode'])) ? $data['LangCode'] : 'en';
|
||||||
|
|
||||||
|
return $this->redirect($this->Link());
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,83 +1,84 @@
|
|||||||
/**
|
/**
|
||||||
* Documentation Viewer Styles.
|
* Documentation Viewer Styles.
|
||||||
*
|
*
|
||||||
|
* @author Will Rossiter <will@silverstripe.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{ margin:0;padding: 0;}
|
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{ margin:0;padding: 0;}
|
||||||
|
|
||||||
|
/* Core */
|
||||||
html { background: #f4f4f4;}
|
html { background: #f4f4f4;}
|
||||||
body { font: 14px/1.1 Arial,sans-serif; color: #444; }
|
body { font: 14px/1.1 Arial,sans-serif; color: #444; }
|
||||||
|
|
||||||
a { color: #1389ce; text-decoration: none; }
|
a { color: #1389ce; text-decoration: none; }
|
||||||
a:hover { text-decoration: underline;}
|
a:hover,
|
||||||
p {
|
a:focus { text-decoration: underline;}
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-bottom: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul { margin: 8px 16px 20px 20px; }
|
p { font-size: 14px; line-height: 22px; margin-bottom: 22px; }
|
||||||
li { font-size: 12px; line-height: 18px; margin-bottom: 8px;}
|
|
||||||
|
ul { margin: 11px 0 22px 20px; }
|
||||||
|
li { font-size: 12px; line-height: 13px; margin-bottom: 8px;}
|
||||||
|
|
||||||
|
|
||||||
h1 { font-size: 30px; margin-bottom: 18px; color: #111; }
|
h1 { font-size: 33px; line-height: 33px; margin-bottom: 22px; color: #111; letter-spacing: -1px;}
|
||||||
h2 { font-size: 24px; margin-bottom: 16px; color: #111; }
|
h2 { font-size: 24px; line-height: 33px; margin-bottom: 11px; color: #111; }
|
||||||
h3 { font-size: 18px; margin-bottom: 16px; color: #111; }
|
h3 { font-size: 18px; line-height: 22px; margin-bottom: 11px; color: #111; }
|
||||||
h4 { font-size: 16px; margin-bottom: 6px; line-height: 16px;}
|
h4 { font-size: 16px; margin-bottom: 11px; line-height: 22px;}
|
||||||
h5 { font-size: 14px; line-height: 18px; margin-bottom: 6px;}
|
h5 { font-size: 14px; line-height: 22px; margin-bottom: 11px;}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
margin-bottom: 18px;
|
margin-bottom: 22px;
|
||||||
font-family:'Bitstream Vera Sans Mono',Monaco, 'Courier New', monospace;
|
font-family:'Bitstream Vera Sans Mono',Monaco, 'Courier New', monospace;
|
||||||
border-left: 4px solid #eee;
|
|
||||||
background: #f4f4f4;
|
background: #f4f4f4;
|
||||||
padding: 12px;
|
padding: 11px;
|
||||||
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container { width: 960px; margin: 20px auto; padding: 20px; background: #fff; overflow: hidden; }
|
/* Forms */
|
||||||
|
fieldset { border: none; }
|
||||||
|
|
||||||
#header { border-bottom: 3px solid #535360; padding-top: 10px; margin-bottom: 30px; }
|
/* Container */
|
||||||
#header h1 { margin-bottom: 9px;}
|
#container { width: 960px; margin: 44px auto 22px auto; padding: 22px 30px; background: #fff; overflow: hidden;
|
||||||
#header h1 a { text-decoration: none; font-size: 30px; color: #333; letter-spacing: -1px;}
|
-webkit-box-shadow: 0 0 20px #ccc; -moz-box-shadow: 0 0 20px #ccc;}
|
||||||
|
|
||||||
#header .breadcrumbs { font-size: 12px; }
|
/* Header */
|
||||||
#left-column {
|
#header { padding: 11px 0 0 0; margin-bottom: 22px; }
|
||||||
width: 640px;
|
#header h1 { margin-bottom: 0px; line-height: 33px;}
|
||||||
float: left;
|
#header h1 a { text-decoration: none; font-size: 30px; color: #121929; letter-spacing: -1px;}
|
||||||
}
|
|
||||||
|
#header #breadcrumbs p { font-size: 11px; margin: 0 0 10px 0; color: #798D85;}
|
||||||
|
#header #breadcrumbs p a { color: #798D85;}
|
||||||
|
|
||||||
|
/* Language Bar */
|
||||||
|
#language { position: absolute; top: 12px; left: 50%; margin-left: -480px; width: 960px; }
|
||||||
|
#language label { float: left; width: 830px; line-height: 19px; text-align: right; font-size: 11px; color: #999;}
|
||||||
|
#language select { float: right; width: 120px;}
|
||||||
|
#language input.action { float: right; margin-top: 4px;}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
#footer { width: 960px; margin: 22px auto; }
|
||||||
|
#footer p { font-size: 11px; line-height: 11px; color: #798D85;}
|
||||||
|
#footer p a { color: #798D85;}
|
||||||
|
|
||||||
|
/* Content */
|
||||||
|
#layout { }
|
||||||
|
#content { }
|
||||||
|
|
||||||
|
/* Versions */
|
||||||
|
#versions-nav { background: #121929; margin: 0 0 44px; padding: 10px 0 0 10px; overflow: hidden;}
|
||||||
|
#versions-nav h2 { font-size: 11px; color: #fff; font-weight: normal; float: left; margin-right: 5px;}
|
||||||
|
#versions-nav ul { margin: 0; padding: 0; float: left;}
|
||||||
|
#versions-nav li { list-style: none; }
|
||||||
|
#versions-nav li a { display: block; float: left; margin-left: 4px; padding: 11px; font-size: 14px;}
|
||||||
|
#versions-nav li a.current { background: #fff;}
|
||||||
|
#left-column { width: 640px; float: left; }
|
||||||
|
|
||||||
#right-column {
|
#right-column {
|
||||||
width: 260px;
|
width: 260px;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
#home #left-column { width: 500px; }
|
|
||||||
#home #right-column { width: 340px; }
|
|
||||||
#home .box {
|
|
||||||
margin: 0 12px 12px 0px;
|
|
||||||
border: 1px solid #d8d8d8;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
}
|
|
||||||
#home .box h2 {
|
|
||||||
background: #535360;
|
|
||||||
border: 1px solid #535360;
|
|
||||||
-moz-border-top-radius: 4px;
|
|
||||||
-webkit-border-top-left-radius: 4px;
|
|
||||||
-webkit-border-top-right-radius: 4px;
|
|
||||||
padding: 6px 8px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
#home .box h2 a {
|
|
||||||
background: url(../images/readme.png) no-repeat right center;
|
|
||||||
padding: 2px 20px 0 0;
|
|
||||||
font-size: 11px;
|
|
||||||
color: #fff;
|
|
||||||
display: block;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
#right-column .box {
|
#right-column .box {
|
||||||
margin: 0 12px 12px 0;
|
margin: 0 12px 12px 0;
|
||||||
}
|
}
|
||||||
@ -103,19 +104,27 @@ pre {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module { margin: 10px -; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TOC
|
* TOC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ul#toc {
|
.sidebar-box {
|
||||||
margin: 0;
|
margin: 0 0 11px 0;
|
||||||
padding: 20px;
|
padding: 11px 15px;
|
||||||
background: #f4f4f4;
|
background: #f4f4f4;
|
||||||
width: 220px;
|
width: 220px;
|
||||||
}
|
}
|
||||||
ul#toc h4 { font-size: 12px; margin-bottom: 0px;}
|
.sidebar-box ul { margin: 0; padding: 0;}
|
||||||
ul#toc li { list-style: none; margin: 0 0 4px 0; }
|
.sidebar-box h4 { font-size: 12px; margin-bottom: 11px;}
|
||||||
ul#toc li.h1 { margin-top: 10px; font-weight: bold;}
|
.sidebar-box ul li { list-style: none; }
|
||||||
ul#toc li.h2 { margin: 0 0 0px 10px; font-size: 11px;}
|
.sidebar-box ul li .current { font-weight: bold;}
|
||||||
ul#toc li.h3 { margin-left: 20px; font-size: 10px; }
|
.sidebar-box ul li.h1 { margin-top: 11px; font-weight: bold;}
|
||||||
ul#toc li.h4 { margin-right: 30px; font-size: 10px; }
|
.sidebar-box ul li.h2,
|
||||||
|
.sidebar-box ul ul { margin-top: 8px;}
|
||||||
|
.sidebar-box ul li li { font-size: 11px; margin-left: 10px;}
|
||||||
|
.sidebar-box ul li.h3,
|
||||||
|
.sidebar-box ul li li li { margin-left: 20px; font-size: 10px; margin-left: 20px;}
|
||||||
|
.sidebar-box ul li.h4,
|
||||||
|
.sidebar-box ul li li li li { margin-right: 30px; font-size: 10px; margin-left: 20px; }
|
@ -1,28 +0,0 @@
|
|||||||
# Writing Documentation #
|
|
||||||
|
|
||||||
|
|
||||||
Your documentation needs to go in the specific modules doc folder which it refers mostly too. For example if you want to document
|
|
||||||
a feature of your custom module 'MyModule' you need to create markdown files in mymodule/doc/.
|
|
||||||
|
|
||||||
The files have to end with the __.md__ extension. The documentation viewer will automatically replace hyphens (-) with spaces (since you cannot
|
|
||||||
have spaces easily in some file systems).
|
|
||||||
|
|
||||||
## Syntax ##
|
|
||||||
This uses a customized markdown extra parser. To view the syntax for page formatting check out [http://daringfireball.net/projects/markdown/syntax][Daring Fireball]
|
|
||||||
|
|
||||||
|
|
||||||
## Creating Hierarchy ##
|
|
||||||
|
|
||||||
The document viewer supports folder structure. There is no limit on depth or number of sub categories you can create.
|
|
||||||
|
|
||||||
## Customizing Page Order ##
|
|
||||||
|
|
||||||
Sometimes you will have pages which you want at the top of the documentation viewer summary. Pages like Getting-Started will come after Advanced-Usage
|
|
||||||
due to the default alphabetical ordering.
|
|
||||||
|
|
||||||
To handle this you can use a number prefix for example __01-My-First-Folder__ which would be the first folder in the list.
|
|
||||||
|
|
||||||
DocumentationViewer will remove the __01-__ from the name as well so you don't need to worry about labels for your folders with numbers. It will be
|
|
||||||
outputted in the front end as __My First Folder__
|
|
||||||
|
|
||||||
|
|
22
docs/en/Configuration-Options.md
Normal file
22
docs/en/Configuration-Options.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Helpful Configuration Options
|
||||||
|
|
||||||
|
DocumentationService::set_ignored_files(array());
|
||||||
|
|
||||||
|
If you want to ignore (hide) certain file types from being included.
|
||||||
|
|
||||||
|
DocumentationService::set_automatic_registration(false);
|
||||||
|
|
||||||
|
By default the documentation system will parse all the directories in your project and
|
||||||
|
include the documentation. If you want to only specify a few folders you can disable it
|
||||||
|
with the above.
|
||||||
|
|
||||||
|
DocumentationService::register($module, $path, $version = 'current', $lang = 'en', $major_release = false)
|
||||||
|
|
||||||
|
Registers a module to be included in the system (if automatic registration is off or you need
|
||||||
|
to load a module outside a documentation path).
|
||||||
|
|
||||||
|
DocumentationService::unregister($module, $version = false, $lang = false)
|
||||||
|
|
||||||
|
Unregister a module (removes from documentation list). You can specify the module, the version
|
||||||
|
and the lang. If no version is specified then all folders of that lang are removed. If you do
|
||||||
|
not specify a version or lang the whole module will be removed from the documentation.
|
32
docs/en/Writing-Documentation.md
Normal file
32
docs/en/Writing-Documentation.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Writing Documentation #
|
||||||
|
|
||||||
|
Your documentation needs to go in the specific modules docs folder which it refers mostly too. For example if you want to document
|
||||||
|
a feature of your custom module 'MyModule' you need to create markdown files in mymodule/docs/.
|
||||||
|
|
||||||
|
The files have to end with the __.md__ extension. The documentation viewer will automatically replace hyphens (-) with spaces (since you cannot
|
||||||
|
have spaces web / file systems).
|
||||||
|
|
||||||
|
Also docs folder should be localized. Even if you do not plan on using multiple languages you should at least write your documentation
|
||||||
|
in a 'en' subfolder
|
||||||
|
|
||||||
|
/module/docs/en/
|
||||||
|
|
||||||
|
## Syntax ##
|
||||||
|
|
||||||
|
This uses a customized markdown extra parser. To view the syntax for page formatting check out [http://daringfireball.net/projects/markdown/syntax][Daring Fireball]
|
||||||
|
|
||||||
|
## Creating Hierarchy ##
|
||||||
|
|
||||||
|
The document viewer supports folder structure. There is a 9 folder limit on depth / number of sub categories you can create.
|
||||||
|
Each level deep it will generate the nested urls.
|
||||||
|
|
||||||
|
## Directory Listing ##
|
||||||
|
|
||||||
|
Each folder you create should also contain a __index.md__ file (see sapphiredocs/doc/en/index.md) which contains an overview of the
|
||||||
|
module and related links.
|
||||||
|
|
||||||
|
## Table of Contents ##
|
||||||
|
|
||||||
|
The table of contents on each module page is generated
|
||||||
|
|
||||||
|
|
11
docs/en/index.md
Normal file
11
docs/en/index.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
### Sapphire Documentation Module
|
||||||
|
|
||||||
|
This module has been developed to read and display content from markdown files in webbrowser. It is an easy
|
||||||
|
way to bundle end user documentation within a SilverStripe installation.
|
||||||
|
|
||||||
|
See <a href="dev/docs/en/sapphiredocs/writing-documentation">Writing Documentation</a> for more information on how to write markdown files which
|
||||||
|
are available here.
|
||||||
|
|
||||||
|
To include your docs file here create a __docs/en/index.md__ file. You can also include custom paths and versions. To configure the documentation system the configuration information is available on the <a href="dev/docs/en/sapphiredocs/configuration-options">Configurations</a>
|
||||||
|
page.
|
||||||
|
|
@ -21,5 +21,16 @@
|
|||||||
|
|
||||||
$('#table-of-contents').prepend(toc);
|
$('#table-of-contents').prepend(toc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ---------------------------------------------
|
||||||
|
* LANGAUGE SELECTER
|
||||||
|
*
|
||||||
|
* Hide the change button and do it onclick
|
||||||
|
*/
|
||||||
|
$("#Form_LanguageForm .Actions").hide();
|
||||||
|
|
||||||
|
$("#Form_LanguageForm select").change(function() {
|
||||||
|
$("#Form_LanguageForm").submit();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
@ -15,12 +15,39 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<h1><a href="dev/docs/">SilverStripe Documentation</a></h1>
|
<h1><a href="$Link"><% _t('SILVERSTRIPEDOCUMENTATION', 'SilverStripe Documentation') %></a></h1>
|
||||||
|
|
||||||
$Breadcrumbs
|
<div id="language">
|
||||||
|
$LanguageForm
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="breadcrumbs">
|
||||||
|
<% include DocBreadcrumbs %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="layout">
|
||||||
|
<div id="versions-nav">
|
||||||
|
<h2>Versions:</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<% control Versions %>
|
||||||
|
<% if MajorRelease %>
|
||||||
|
<li class="major-release"><a href="$Link" class="$LinkingMode">$Title</a></li>
|
||||||
|
<% else %>
|
||||||
|
<li class="module-only"><a href="$Link" class="$LinkingMode">$Title</a></li>
|
||||||
|
<% end_if %>
|
||||||
|
<% end_control %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="content">
|
||||||
$Layout
|
$Layout
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
<p>Documentation powered by <a href="http://www.silverstripe.org">SilverStripe</a>. Found a typo? <a href="http://github.com/chillu/silverstripe-doc-restructuring">Contribute to the Documentation Project</a>.</p>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
5
templates/Includes/DocBreadcrumbs.ss
Normal file
5
templates/Includes/DocBreadcrumbs.ss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<p>
|
||||||
|
<% control Breadcrumbs %>
|
||||||
|
<a href="$Link">$Title</a> <% if Last %><% else %>›<% end_if %>
|
||||||
|
<% end_control %>
|
||||||
|
</p>
|
18
templates/Includes/DocInThisModule.ss
Normal file
18
templates/Includes/DocInThisModule.ss
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div id="in-this-module" class="sidebar-box">
|
||||||
|
<h4>In this module</h4>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<% control ModulePages %>
|
||||||
|
<li>
|
||||||
|
<a href="$Link" class="$LinkingMode">$Title</a>
|
||||||
|
<% if Children %>
|
||||||
|
<ul>
|
||||||
|
<% control Children %>
|
||||||
|
<li><a href="$Link" class="$LinkingMode">$Title</a></li>
|
||||||
|
<% end_control %>
|
||||||
|
</ul>
|
||||||
|
<% end_if %>
|
||||||
|
</li>
|
||||||
|
<% end_control %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
1
templates/Includes/DocTableOfContents.ss
Normal file
1
templates/Includes/DocTableOfContents.ss
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div id="table-of-contents" class="sidebar-box"></div>
|
@ -1,11 +1,14 @@
|
|||||||
<div id="left-column">
|
<div id="documentation-page">
|
||||||
|
<div id="left-column">
|
||||||
<% if Content %>
|
<% if Content %>
|
||||||
$Content
|
$Content
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>Woops no documentation for this page</p>
|
<p>Woops page not found</p>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="right-column">
|
<div id="right-column">
|
||||||
<div id="table-of-contents"></div>
|
<% include DocTableOfContents %>
|
||||||
|
<% include DocInThisModule %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
15
templates/Layout/DocumentationViewer_folder.ss
Normal file
15
templates/Layout/DocumentationViewer_folder.ss
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<div id="module-home">
|
||||||
|
|
||||||
|
<div id="left-column">
|
||||||
|
<% if Content %>
|
||||||
|
$Content
|
||||||
|
<% else %>
|
||||||
|
frs
|
||||||
|
<h2>$Title</h2>
|
||||||
|
<% end_if %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="right-column">
|
||||||
|
<% include DocInThisModule %>
|
||||||
|
</div>
|
||||||
|
</div>
|
10
templates/Layout/DocumentationViewer_home.ss
Executable file
10
templates/Layout/DocumentationViewer_home.ss
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
<div id="home">
|
||||||
|
<% control Modules %>
|
||||||
|
<% if Content %>
|
||||||
|
<div class="module">
|
||||||
|
|
||||||
|
$Content
|
||||||
|
</div>
|
||||||
|
<% end_if %>
|
||||||
|
<% end_control %>
|
||||||
|
</div>
|
@ -1,29 +0,0 @@
|
|||||||
<div id="home">
|
|
||||||
<% control DocumentedModules %>
|
|
||||||
<% if First %>
|
|
||||||
<div id="left-column">
|
|
||||||
<div class="box">
|
|
||||||
<h2>$Title $Readme</h2>
|
|
||||||
|
|
||||||
$Content
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="right-column">
|
|
||||||
<% else %>
|
|
||||||
<div class="box">
|
|
||||||
<h2>$Title $Readme</h2>
|
|
||||||
|
|
||||||
$Content
|
|
||||||
</div>
|
|
||||||
<% end_if %>
|
|
||||||
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if UndocumentedModules %>
|
|
||||||
<div class='undocumented-modules'>
|
|
||||||
<p>Undocumented Modules: $UndocumentedModules</p>
|
|
||||||
</div>
|
|
||||||
<% end_if %>
|
|
||||||
</div>
|
|
11
tests/DocumentTests.yml
Normal file
11
tests/DocumentTests.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Permission:
|
||||||
|
admin:
|
||||||
|
Code: ADMIN
|
||||||
|
Group:
|
||||||
|
admins:
|
||||||
|
Code: admins
|
||||||
|
Permissions: =>Permission.admin
|
||||||
|
Member:
|
||||||
|
admin:
|
||||||
|
Email: admin@test.com
|
||||||
|
Groups: =>Group.admins
|
52
tests/DocumentationViewerTests.php
Normal file
52
tests/DocumentationViewerTests.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some of these tests are simply checking that pages load. They should not assume
|
||||||
|
* somethings working.
|
||||||
|
*
|
||||||
|
* @package sapphiredocs
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DocumentationViewerTests extends FunctionalTest {
|
||||||
|
|
||||||
|
static $fixture_file = 'sapphiredocs/tests/DocumentTests.yml';
|
||||||
|
|
||||||
|
function testCleanPageNames() {
|
||||||
|
$names = array(
|
||||||
|
'documentation-Page',
|
||||||
|
'documentation_Page',
|
||||||
|
'documentation.md',
|
||||||
|
'documentation.pdf',
|
||||||
|
'documentation.file.txt',
|
||||||
|
'.hidden'
|
||||||
|
);
|
||||||
|
|
||||||
|
$should = array(
|
||||||
|
'Documentation Page',
|
||||||
|
'Documentation Page',
|
||||||
|
'Documentation',
|
||||||
|
'Documentation',
|
||||||
|
'Documentation',
|
||||||
|
'.hidden' // don't display something without a title
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($names as $key => $value) {
|
||||||
|
$this->assertEquals(DocumentationParser::clean_page_name($value), $should[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDocumentationEntityAccessing() {
|
||||||
|
$entity = new DocumentationEntity('docs', '1.0', '../sapphiredocs/tests/docs/', 'My Test');
|
||||||
|
|
||||||
|
$this->assertEquals($entity->getTitle(), 'My Test');
|
||||||
|
$this->assertEquals($entity->getVersions(), array('1.0'));
|
||||||
|
$this->assertEquals($entity->getLanguages(), array('en', 'de'));
|
||||||
|
$this->assertEquals($entity->getModuleFolder(), 'docs');
|
||||||
|
|
||||||
|
$this->assertTrue($entity->hasVersion('1.0'));
|
||||||
|
$this->assertFalse($entity->hasVersion('2.0'));
|
||||||
|
|
||||||
|
$this->assertTrue($entity->hasLanguage('en'));
|
||||||
|
$this->assertFalse($entity->hasLanguage('fr'));
|
||||||
|
}
|
||||||
|
}
|
5
tests/docs-2/en/index.md
Normal file
5
tests/docs-2/en/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## english test
|
||||||
|
|
||||||
|
index
|
||||||
|
|
||||||
|
2.0
|
5
tests/docs/de/index.md
Normal file
5
tests/docs/de/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## german test
|
||||||
|
|
||||||
|
index
|
||||||
|
|
||||||
|
1.0
|
5
tests/docs/de/test.md
Normal file
5
tests/docs/de/test.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## german test
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
1.0
|
5
tests/docs/en/index.md
Normal file
5
tests/docs/en/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## english test
|
||||||
|
|
||||||
|
index
|
||||||
|
|
||||||
|
1.0
|
5
tests/docs/en/test.md
Normal file
5
tests/docs/en/test.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## english test
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
1.0
|
Loading…
Reference in New Issue
Block a user