Updated to latest sapphiredocs

git-svn-id: http://svn.silverstripe.com/projects/ss2doc/branches/v2@120789 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Will Rossiter 2011-08-11 03:50:01 +00:00
parent 9b37aefefc
commit db7b9f408b
21 changed files with 847 additions and 145 deletions

View File

@ -1,7 +1,7 @@
---
format: 1
handler:
commit: 96ac20a15cc89a336b4fd29b5202589d567efb57
commit: a12169c9e0fd1fd65ccdb2e6f404be590e5920de
branch: master
lock: false
repository_class: Piston::Git::Repository

View File

@ -59,6 +59,21 @@ class DocumentationSearch {
*/
private $outputController;
/**
* Optionally filter by module and version
*
* @var array
*/
private $modules, $versions;
public function setModules($modules) {
$this->modules = $modules;
}
public function setVersions($versions) {
$this->versions = $versions;
}
/**
* Set the current search query
*
@ -131,16 +146,18 @@ class DocumentationSearch {
/**
* Enable searching documentation
*/
public static function enable() {
self::$enabled = true;
public static function enable($enabled = true) {
self::$enabled = $enabled;
// include the zend search functionality
set_include_path(
dirname(dirname(__FILE__)) . '/thirdparty/'. PATH_SEPARATOR .
get_include_path()
);
if($enabled) {
// include the zend search functionality
set_include_path(
dirname(dirname(__FILE__)) . '/thirdparty/'. PATH_SEPARATOR .
get_include_path()
);
require_once 'Zend/Search/Lucene.php';
require_once 'Zend/Search/Lucene.php';
}
}
/**
@ -171,9 +188,37 @@ class DocumentationSearch {
try {
$index = Zend_Search_Lucene::open(self::get_index_location());
Zend_Search_Lucene::setResultSetLimit(200);
$this->results = $index->find($this->getQuery());
Zend_Search_Lucene::setResultSetLimit(100);
$query = new Zend_Search_Lucene_Search_Query_Boolean();
$term = Zend_Search_Lucene_Search_QueryParser::parse($this->getQuery());
$query->addSubquery($term, true);
if($this->modules) {
$moduleQuery = new Zend_Search_Lucene_Search_Query_MultiTerm();
foreach($this->modules as $module) {
$moduleQuery->addTerm(new Zend_Search_Lucene_Index_Term($module, 'Module'));
}
$query->addSubquery($moduleQuery, true);
}
if($this->versions) {
$versionQuery = new Zend_Search_Lucene_Search_Query_MultiTerm();
foreach($this->versions as $version) {
$versionQuery->addTerm(new Zend_Search_Lucene_Index_Term($version, 'Version'));
}
$query->addSubquery($versionQuery, true);
}
$er = error_reporting();
error_reporting('E_ALL ^ E_NOTICE');
$this->results = $index->find($query);
error_reporting($er);
$this->totalResults = $index->numDocs();
}
catch(Zend_Search_Lucene_Exception $e) {
@ -186,10 +231,12 @@ class DocumentationSearch {
*/
public function getSearchResults($request) {
$pageLength = (isset($_GET['length'])) ? (int) $_GET['length'] : 10;
$data = array(
'Results' => null,
'Query' => null,
'Versions' => DBField::create('Text', implode(',', $this->versions)),
'Modules' => DBField::create('Text', implode(',', $this->modules)),
'Title' => _t('DocumentationSearch.SEARCHRESULTS', 'Search Results'),
'TotalResults' => null,
'TotalPages' => null,
@ -214,27 +261,29 @@ class DocumentationSearch {
$results = new DataObjectSet();
foreach($this->results as $k => $hit) {
if($k < ($currentPage-1)*$pageLength || $k >= ($currentPage*$pageLength)) continue;
if($this->results) {
foreach($this->results as $k => $hit) {
if($k < ($currentPage-1)*$pageLength || $k >= ($currentPage*$pageLength)) continue;
$doc = $hit->getDocument();
$doc = $hit->getDocument();
$content = $hit->content;
// do a simple markdown parse of the file
$obj = new ArrayData(array(
'Title' => DBField::create('Varchar', $doc->getFieldValue('Title')),
'BreadcrumbTitle' => DBField::create('HTMLText', $doc->getFieldValue('BreadcrumbTitle')),
'Link' => DBField::create('Varchar',$doc->getFieldValue('Link')),
'Language' => DBField::create('Varchar',$doc->getFieldValue('Language')),
'Version' => DBField::create('Varchar',$doc->getFieldValue('Version')),
'Content' => DBField::create('HTMLText', $content),
'Score' => $hit->score,
'Number' => $k + 1,
'ID' => md5($doc->getFieldValue('Link'))
));
$content = $hit->content;
$obj = new ArrayData(array(
'Title' => DBField::create('Varchar', $doc->getFieldValue('Title')),
'BreadcrumbTitle' => DBField::create('HTMLText', $doc->getFieldValue('BreadcrumbTitle')),
'Link' => DBField::create('Varchar',$doc->getFieldValue('Link')),
'Language' => DBField::create('Varchar',$doc->getFieldValue('Language')),
'Version' => DBField::create('Varchar',$doc->getFieldValue('Version')),
'Module' => DBField::create('Varchar', $doc->getFieldValue('Module')),
'Content' => DBField::create('HTMLText', $content),
'Score' => $hit->score,
'Number' => $k + 1,
'ID' => md5($doc->getFieldValue('Link'))
));
$results->push($obj);
$results->push($obj);
}
}
$data['Results'] = $results;
@ -356,7 +405,7 @@ class DocumentationSearch {
* the search results template or the Atom feed
*/
public function renderResults() {
if(!$this->results) $this->performSearch();
if(!$this->results && $this->query) $this->performSearch();
if(!$this->outputController) return user_error('Call renderResults() on a DocumentationViewer instance.', E_USER_ERROR);
$request = $this->outputController->getRequest();
@ -378,35 +427,4 @@ class DocumentationSearch {
return $this->outputController->customise($data)->renderWith($templates);
}
}
/**
* Public facing controller for handling search.
*
* @package sapphiredocs
*/
class DocumentationOpenSearch_Controller extends Controller {
function index() {
return $this->httpError('404');
}
function description() {
$viewer = new DocumentationViewer();
if(!DocumentationViewer::canView()) return Security::permissionFailure($this);
$data = DocumentationSearch::get_meta_data();
$link = Director::absoluteBaseUrl() .
$data['SearchPageLink'] = Controller::join_links(
$viewer->Link(),
'results/?Search={searchTerms}&amp;start={startIndex}&amp;length={count}&amp;action_results=1'
);
$data['SearchPageAtom'] = $data['SearchPageLink'] . '&amp;format=atom';
return $this->customise(new ArrayData($data))->renderWith(array('OpenSearchDescription'));
}
}

View File

@ -144,7 +144,7 @@ class DocumentationService {
if($version || $lang) {
foreach($entities as $entity) {
if(self::is_registered_entity($entity->getFolder(), $version, $lang)) {
$output[] = $entity;
$output[$entity->getFolder()] = $entity;
}
}
}
@ -212,7 +212,7 @@ class DocumentationService {
}
if($latest)
$output->setLatestVersion($version);
$output->setStableVersion($version);
return $output;
}
@ -265,7 +265,7 @@ class DocumentationService {
if($dir && !$ignored) {
// check to see if it has docs
$docs = Controller::join_links($dir, 'docs');
$docs = Director::baseFolder() . '/' . Controller::join_links($entity, 'docs');
if(is_dir($docs)) {
self::register($entity, $docs, '', $entity, true);

View File

@ -0,0 +1,39 @@
<?php
/**
* Public facing controller for handling an opensearch interface based on
* the standard search form.
*
* @package sapphiredocs
*/
class DocumentationOpenSearchController extends ContentController {
static $allowed_actions = array(
'description'
);
function index() {
return $this->httpError(404);
}
function description() {
$viewer = new DocumentationViewer();
if(!$viewer->canView()) return Security::permissionFailure($this);
if(!DocumentationSearch::enabled()) return $this->httpError('404');
$data = DocumentationSearch::get_meta_data();
$link = Director::absoluteBaseUrl() .
$data['SearchPageLink'] = Controller::join_links(
$viewer->Link(),
'results/?Search={searchTerms}&amp;start={startIndex}&amp;length={count}&amp;action_results=1'
);
$data['SearchPageAtom'] = $data['SearchPageLink'] . '&amp;format=atom';
return $this->customise(
new ArrayData($data)
)->renderWith(array('OpenSearchDescription'));
}
}

View File

@ -77,9 +77,7 @@ class DocumentationViewer extends Controller {
Requirements::javascript('sapphiredocs/javascript/DocumentationViewer.js');
// css
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCore.css');
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shCoreRDark.css');
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shThemeRDark.css');
Requirements::css('sapphiredocs/css/shSilverStripeDocs.css');
Requirements::customScript('jQuery(document).ready(function() {SyntaxHighlighter.all();});');
}
@ -156,7 +154,7 @@ class DocumentationViewer extends Controller {
}
// check to see if the module is a valid module. If it isn't, then we
// check to see if the request is a valid entity. If it isn't, then we
// need to throw a 404.
if(!DocumentationService::is_registered_entity($firstParam)) {
return $this->throw404();
@ -180,7 +178,7 @@ class DocumentationViewer extends Controller {
$entity = DocumentationService::is_registered_entity($this->entity, null, $this->getLang());
if($entity) {
$current = $entity->getLatestVersion();
$current = $entity->getStableVersion();
$version = $this->getVersion();
if(!$version) {
@ -246,7 +244,7 @@ class DocumentationViewer extends Controller {
/**
* Returns the current version. If no version is set then it is the current
* set version so need to pull that from the module.
* set version so need to pull that from the {@link Entity}.
*
* @return String
*/
@ -254,7 +252,7 @@ class DocumentationViewer extends Controller {
if($this->version) return $this->version;
if($entity = $this->getEntity()) {
$this->version = $entity->getLatestVersion();
$this->version = $entity->getStableVersion();
return $this->version;
}
@ -272,10 +270,9 @@ class DocumentationViewer extends Controller {
}
/**
* Return all the available languages for the module.
* Return all the available languages for the {@link Entity}.
*
* @param String - The name of the module
* @return DataObjectSet
* @return array
*/
function getLanguages() {
$entity = $this->getEntity();
@ -291,32 +288,31 @@ class DocumentationViewer extends Controller {
* Get all the versions loaded for the current {@link DocumentationEntity}.
* the filesystem then they are loaded under the 'Current' namespace.
*
* @param String $entity name of module to limit it to eg sapphire
* @param String $entity name of {@link Entity} to limit it to eg sapphire
* @return DataObjectSet
*/
function getVersions($entity = false) {
if(!$entity) $entity = $this->entity;
$entity = DocumentationService::is_registered_entity($entity);
if(!$entity) return false;
$versions = $entity->getVersions();
$output = new DataObjectSet();
if($versions) {
$lang = $this->getLang();
$currentVersion = $this->getVersion();
foreach($versions as $key => $version) {
// work out the link to this version of the documentation.
// @todo Keep the user on their given page rather than redirecting to module.
$linkingMode = ($currentVersion == $version) ? 'current' : 'link';
if(!$version) $version = 'Current';
$output->push(new ArrayData(array(
'Title' => $version,
'Link' => $this->Link(implode('/',$this->Remaining), $entity->getFolder(), $version),
'LinkingMode' => $linkingMode
'LinkingMode' => $linkingMode,
'Version' => $version // separate from title, we may want to make title nicer.
)));
}
}
@ -356,7 +352,7 @@ class DocumentationViewer extends Controller {
)));
}
}
return $output;
}
@ -479,7 +475,7 @@ class DocumentationViewer extends Controller {
}
/**
* Get the module pages under a given page. Recursive call for {@link getEntityPages()}
* Get all the pages under a given page. Recursive call for {@link getEntityPages()}
*
* @todo Need to rethink how to support pages which are pulling content from their children
* i.e if a folder doesn't have 2 then it will load the first file in the folder
@ -606,7 +602,7 @@ class DocumentationViewer extends Controller {
foreach($pages as $i => $title) {
if($title) {
// Don't add module name, already present in Link()
// Don't add entity name, already present in Link()
if($i > 0) $path[] = $title;
$output->push(new ArrayData(array(
@ -650,9 +646,6 @@ class DocumentationViewer extends Controller {
* @return String
*/
public function Link($path = false, $entity = false, $version = false, $lang = false) {
$base = Director::absoluteBaseURL();
// only include the version. Version is optional after all
$version = ($version === null) ? $this->getVersion() : $version;
$lang = (!$lang) ? $this->getLang() : $lang;
@ -667,7 +660,14 @@ class DocumentationViewer extends Controller {
$action = implode('/', $path);
}
$link = Controller::join_links($base, self::get_link_base(), $entity, $lang, $version, $action);
$link = Controller::join_links(
Director::absoluteBaseURL(),
self::get_link_base(),
$entity,
($entity) ? $lang : "", // only include lang for entity - sapphire/en vs en/
($entity) ? $version :"",
$action
);
return $link;
}
@ -680,12 +680,7 @@ class DocumentationViewer extends Controller {
* @return Form
*/
function LanguageForm() {
if($entity = $this->getEntity()) {
$langs = DocumentationService::get_registered_languages($entity->getFolder());
}
else {
$langs = DocumentationService::get_registered_languages();
}
$langs = $this->getLanguages();
$fields = new FieldSet(
$dropdown = new DropdownField(
@ -737,18 +732,19 @@ class DocumentationViewer extends Controller {
}
/**
* Documentation Basic Search Form
* Documentation Search Form. Allows filtering of the results by many entities
* and multiple versions.
*
* Integrates with sphinx
* @return Form
*/
function DocumentationSearchForm() {
if(!DocumentationSearch::enabled()) return false;
$query = (isset($_REQUEST['Search'])) ? Convert::raw2xml($_REQUEST['Search']) : "";
$q = ($q = $this->getSearchQuery()) ? $q->NoHTML() : "";
$fields = new FieldSet(
new TextField('Search', _t('DocumentationViewer.SEARCH', 'Search'), $query)
new TextField('Search', _t('DocumentationViewer.SEARCH', 'Search'), $q),
new HiddenField('Entities', '', implode(',', array_keys($this->getSearchedEntities()))),
new HiddenField('Versions', '', implode(',', $this->getSearchedVersions()))
);
$actions = new FieldSet(
@ -758,24 +754,197 @@ class DocumentationViewer extends Controller {
$form = new Form($this, 'DocumentationSearchForm', $fields, $actions);
$form->disableSecurityToken();
$form->setFormMethod('get');
$form->setFormAction('home/DocumentationSearchForm');
$form->setFormAction(self::$link_base . 'DocumentationSearchForm');
return $form;
}
/**
* Return an array of folders and titles
*
* @return array
*/
function getSearchedEntities() {
$entities = array();
if(isset($_REQUEST['Entities'])) {
if(is_array($_REQUEST['Entities'])) {
$entities = Convert::raw2att($_REQUEST['Entities']);
}
else {
$entities = explode(',', Convert::raw2att($_REQUEST['Entities']));
$entities = array_combine($entities, $entities);
}
}
else if($entity = $this->getEntity()) {
$entities[$entity->getFolder()] = Convert::raw2att($entity->getTitle());
}
return $entities;
}
/**
* Return an array of versions that we're allowed to return
*
* @return array
*/
function getSearchedVersions() {
$versions = array();
if(isset($_REQUEST['Versions'])) {
if(is_array($_REQUEST['Versions'])) {
$versions = Convert::raw2att($_REQUEST['Versions']);
$versions = array_combine($versions, $versions);
}
else {
$version = Convert::raw2att($_REQUEST['Versions']);
$versions[$version] = $version;
}
}
else if($version = $this->getVersion()) {
$version = Convert::raw2att($version);
$versions[$version] = $version;
}
return $versions;
}
/**
* Return the current search query
*
* @return HTMLText|null
*/
function getSearchQuery() {
if(isset($_REQUEST['Search'])) {
return DBField::create('HTMLText', $_REQUEST['Search']);
}
}
/**
* Past straight to results, display and encode the query
*/
function results($data, $form = false) {
$query = (isset($_REQUEST['Search'])) ? $_REQUEST['Search'] : false;
if(!$query) return $this->httpError('404');
$search = new DocumentationSearch();
$search->setQuery($query);
$search->setVersions($this->getSearchedVersions());
$search->setModules($this->getSearchedEntities());
$search->setOutputController($this);
return $search->renderResults();
}
/**
* Returns an search form which allows people to express more complex rules
* and options than the plain search form.
*
* @todo client side filtering of checkable option based on the module selected.
*
* @return Form
*/
function AdvancedSearchForm() {
$entities = DocumentationService::get_registered_entities();
$versions = array();
foreach($entities as $entity) {
$versions[$entity->getFolder()] = $entity->getVersions();
}
// get a list of all the unique versions
$uniqueVersions = array_unique(self::array_flatten(array_values($versions)));
asort($uniqueVersions);
$uniqueVersions = array_combine($uniqueVersions,$uniqueVersions);
$q = ($q = $this->getSearchQuery()) ? $q->NoHTML() : "";
// klude to take an array of objects down to a simple map
$entities = new DataObjectSet($entities);
$entities = $entities->map('Folder', 'Title');
// if we haven't gone any search limit then we're searching everything
$searchedEntities = $this->getSearchedEntities();
if(count($searchedEntities) < 1) $searchedEntities = $entities;
$searchedVersions = $this->getSearchedVersions();
if(count($searchedVersions) < 1) $searchedVersions = $uniqueVersions;
$fields = new FieldSet(
new TextField('Search', _t('DocumentationViewer.KEYWORDS', 'Keywords'), $q),
new CheckboxSetField('Entities', _t('DocumentationViewer.MODULES', 'Modules'), $entities, $searchedEntities),
new CheckboxSetField('Versions', _t('DocumentationViewer.VERSIONS', 'Versions'),
$uniqueVersions, $searchedVersions
)
);
$actions = new FieldSet(
new FormAction('results', _t('DocumentationViewer.SEARCH', 'Search'))
);
$required = new RequiredFields(array('Search'));
$form = new Form($this, 'AdvancedSearchForm', $fields, $actions, $required);
$form->disableSecurityToken();
$form->setFormMethod('get');
$form->setFormAction(self::$link_base . 'DocumentationSearchForm');
return $form;
}
/**
* Check to see if the currently accessed version is out of date or
* perhaps a future version rather than the stable edition
*
* @return false|ArrayData
*/
function VersionWarning() {
$version = $this->getVersion();
$entity = $this->getEntity();
if($entity) {
$compare = $entity->compare($version);
$stable = $entity->getStableVersion();
// same
if($version == $stable) return false;
// check for trunk, if trunk and not the same then it's future
// also run through compare
if($version == "trunk" || $compare > 0) {
return $this->customise(new ArrayData(array(
'FutureRelease' => true,
'StableVersion' => DBField::create('HTMLText', $stable)
)));
}
else {
return $this->customise(new ArrayData(array(
'OutdatedRelease' => true,
'StableVersion' => DBField::create('HTMLText', $stable)
)));
}
}
return false;
}
/**
* Flattens an array
*
* @param array
* @return array
*/
public static function array_flatten($array) {
if(!is_array($array)) return false;
$output = array();
foreach($array as $k => $v) {
if(is_array($v)) {
$output = array_merge($output, self::array_flatten($v));
}
else {
$output[$k] = $v;
}
}
return $output;
}
}

View File

@ -7,11 +7,13 @@
* page. Individual pages are handled by {@link DocumentationPage}
*
* Each folder must have at least one language subfolder, which is automatically
* determined through {@link addVersion()} and should not be included in the $path argument.
* determined through {@link addVersion()} and should not be included in the
* $path argument.
*
* Versions are assumed to be in numeric format (e.g. '2.4'),
*
* They're also parsed through version_compare() in {@link getLatestVersion()} which assumes a certain format.
* They're also parsed through version_compare() in {@link getStableVersion()}
* which assumes a certain format {@link http://php.net/manual/en/function.version-compare.php}
*
* @package sapphiredocs
* @subpackage models
@ -19,6 +21,9 @@
class DocumentationEntity extends ViewableData {
/**
* @var array
*/
static $casting = array(
'Name' => 'Text'
);
@ -41,7 +46,7 @@ class DocumentationEntity extends ViewableData {
/**
* @var array
*/
private $latestVersion;
private $stableVersion;
/**
* @var Array $langs a list of available langauges
@ -123,13 +128,13 @@ class DocumentationEntity extends ViewableData {
}
/**
* @return String|Boolean
* @return string|boo
*/
public function getLatestVersion() {
public function getStableVersion() {
if(!$this->hasVersions()) return false;
if($this->latestVersion) {
return $this->latestVersion;
if($this->stableVersion) {
return $this->stableVersion;
} else {
$sortedVersions = $this->getVersions();
usort($sortedVersions, create_function('$a,$b', 'return version_compare($a,$b);'));
@ -141,9 +146,23 @@ class DocumentationEntity extends ViewableData {
/**
* @param String $version
*/
public function setLatestVersion($version) {
public function setStableVersion($version) {
if(!$this->hasVersion($version)) throw new InvalidArgumentException(sprintf('Version "%s" does not exist', $version));
$this->latestVersion = $version;
$this->stableVersion = $version;
}
/**
* Returns an integer value based on if a given version is the latest
* version. Will return -1 for if the version is older, 0 if versions are
* the same and 1 if the version is greater than.
*
* @param string $version
* @return int
*/
public function compare($version) {
$latest = $this->getStableVersion();
return version_compare($version, $latest);
}
/**
@ -207,7 +226,7 @@ class DocumentationEntity extends ViewableData {
* @return string
*/
public function getPath($version = false, $lang = false) {
if(!$version) $version = $this->getLatestVersion();
if(!$version) $version = $this->getStableVersion();
if(!$lang) $lang = 'en';
if($this->hasVersion($version)) {
@ -235,7 +254,7 @@ class DocumentationEntity extends ViewableData {
function getRelativeLink($version = false, $lang = false) {
if(!$lang) $lang = 'en';
if($version == $this->getLatestVersion()) $version = false;
if($version == $this->getStableVersion()) $version = false;
return Controller::join_links(
DocumentationViewer::get_link_base(),

View File

@ -176,7 +176,7 @@ class DocumentationPage extends ViewableData {
}
function getVersion() {
return $this->version ? $this->version : $this->entity->getLatestVersion();
return $this->version ? $this->version : $this->entity->getStableVersion();
}
function setVersion($version) {

View File

@ -73,15 +73,18 @@ class RebuildLuceneDocsIndex extends BuildTask {
$content = $page->getMarkdown();
if($content) $content = Markdown($content);
$entity = ($entity = $page->getEntity()) ? $entity->getTitle() : "";
$doc->addField(Zend_Search_Lucene_Field::Text('content', $content));
$doc->addField($titleField = Zend_Search_Lucene_Field::Text('Title', $page->getTitle()));
$doc->addField($breadcrumbField = Zend_Search_Lucene_Field::Text('BreadcrumbTitle', $page->getBreadcrumbTitle()));
$doc->addField(Zend_Search_Lucene_Field::Keyword('Version', $page->getVersion()));
$doc->addField(Zend_Search_Lucene_Field::Keyword('Language', $page->getLang()));
$doc->addField(Zend_Search_Lucene_Field::Keyword('Entity', $entity));
$doc->addField(Zend_Search_Lucene_Field::Keyword('Link', $page->Link()));
// custom boosts
$titleField->boost = 1.5;
$titleField->boost = 3;
$breadcrumbField->boost = 1.5;
foreach(DocumentationSearch::$boost_by_path as $pathExpr => $boost) {
if(preg_match($pathExpr, $page->getRelativePath())) $doc->boost = $boost;

View File

@ -1,7 +1,6 @@
/**
* Documentation Viewer Styles.
*
* @author Will Rossiter <will@silverstripe.com>
*/
/* Reset */
@ -63,7 +62,12 @@ fieldset { border: none; }
#footer { width: 960px; margin: 22px auto; }
#footer p { font-size: 11px; line-height: 11px; color: #798D85;}
#footer p a { color: #798D85;}
/* Search */
#search { float: right; }
#search label { display: none; }
/* Breadcrumbs */
#breadcrumbs { float: left; }
/* Content */
#layout { }
#content { }
@ -89,14 +93,14 @@ fieldset { border: none; }
text-decoration: none;
}
#left-column { width: 640px; float: left; }
#content-column { width: 640px; float: left; }
#right-column {
#sidebar-column {
width: 260px;
float: right;
}
#right-column .box {
#sidebar-column .box {
margin: 0 12px 12px 0;
}

View File

@ -0,0 +1,378 @@
.syntaxhighlighter a,
.syntaxhighlighter div,
.syntaxhighlighter code,
.syntaxhighlighter table,
.syntaxhighlighter table td,
.syntaxhighlighter table tr,
.syntaxhighlighter table tbody,
.syntaxhighlighter table thead,
.syntaxhighlighter table caption,
.syntaxhighlighter textarea {
-moz-border-radius: 0 0 0 0 !important;
-webkit-border-radius: 0 0 0 0 !important;
background: none !important;
border: 0 !important;
bottom: auto !important;
float: none !important;
height: auto !important;
left: auto !important;
line-height: 1.3 !important;
margin: 0 !important;
outline: 0 !important;
overflow: visible !important;
padding: 0 !important;
position: static !important;
right: auto !important;
text-align: left !important;
top: auto !important;
vertical-align: baseline !important;
width: auto !important;
box-sizing: content-box !important;
font-weight: normal !important;
font-style: normal !important;
font-size: 1em !important;
min-height: inherit !important;
min-height: auto !important;
font-family:'Bitstream Vera Sans Mono',Monaco, 'Courier New', monospace !important;
}
.syntaxhighlighter {
width: 100% !important;
margin: 1em 0 1em 0 !important;
position: relative !important;
overflow: auto !important;
font-size: 12px !important;
line-height: 20px !important;
background-color: #F8F8FF !important;
}
.syntaxhighlighter.source {
overflow: hidden !important;
}
.syntaxhighlighter .bold {
font-weight: bold !important;
}
.syntaxhighlighter .italic {
font-style: italic !important;
}
.syntaxhighlighter .line {
white-space: pre !important;
}
.syntaxhighlighter table {
width: 100% !important;
}
.syntaxhighlighter table caption {
text-align: left !important;
padding: .5em 0 0.5em 1em !important;
}
.syntaxhighlighter table td.code {
width: 100% !important;
}
.syntaxhighlighter table td.code .container {
position: relative !important;
}
.syntaxhighlighter table td.code .container textarea {
box-sizing: border-box !important;
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
border: none !important;
background: white !important;
padding-left: 1em !important;
overflow: hidden !important;
white-space: pre !important;
}
.syntaxhighlighter table td.gutter .line {
text-align: right !important;
padding: 0 0.5em 0 1em !important;
color: #bbb !important;
}
.syntaxhighlighter table td.code .line {
padding: 0 1em !important;
}
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
padding-left: 0em !important;
}
.syntaxhighlighter.show {
display: block !important;
}
.syntaxhighlighter.collapsed table {
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar {
padding: 0.1em 0.8em 0em 0.8em !important;
font-size: 1em !important;
position: static !important;
width: auto !important;
height: auto !important;
}
.syntaxhighlighter.collapsed .toolbar span {
display: inline !important;
margin-right: 1em !important;
}
.syntaxhighlighter.collapsed .toolbar span a {
padding: 0 !important;
display: none !important;
}
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
display: inline !important;
}
.syntaxhighlighter .toolbar {
position: absolute !important;
right: 1px !important;
top: 1px !important;
width: 11px !important;
height: 11px !important;
font-size: 10px !important;
z-index: 10 !important;
}
.syntaxhighlighter .toolbar span.title {
display: inline !important;
}
.syntaxhighlighter .toolbar a {
display: block !important;
text-align: center !important;
text-decoration: none !important;
padding-top: 1px !important;
}
.syntaxhighlighter .toolbar a.expandSource {
display: none !important;
}
.syntaxhighlighter.ie {
font-size: .9em !important;
padding: 1px 0 1px 0 !important;
}
.syntaxhighlighter.ie .toolbar {
line-height: 8px !important;
}
.syntaxhighlighter.ie .toolbar a {
padding-top: 0px !important;
}
.syntaxhighlighter.printing .line.alt1 .content,
.syntaxhighlighter.printing .line.alt2 .content,
.syntaxhighlighter.printing .line.highlighted .number,
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
background: none !important;
}
.syntaxhighlighter.printing .line .number {
color: #bbbbbb !important;
}
.syntaxhighlighter.printing .line .content {
color: black !important;
}
.syntaxhighlighter.printing .toolbar {
display: none !important;
}
.syntaxhighlighter.printing a {
text-decoration: none !important;
}
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
color: #333 !important;
}
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
color: #008200 !important;
}
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
color: blue !important;
}
.syntaxhighlighter.printing .keyword {
color: #006699 !important;
font-weight: bold !important;
}
.syntaxhighlighter.printing .preprocessor {
color: gray !important;
}
.syntaxhighlighter.printing .variable {
color: #aa7700 !important;
}
.syntaxhighlighter.printing .value {
color: #009900 !important;
}
.syntaxhighlighter.printing .functions {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .constants {
color: #0066cc !important;
}
.syntaxhighlighter.printing .script {
font-weight: bold !important;
}
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
color: gray !important;
}
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
color: #ff1493 !important;
}
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
color: red !important;
}
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
color: black !important;
}
.syntaxhighlighter .line.highlighted .number
{
background-color: #ddd !important;
color: black !important;
}
/* Highlighed line */
.syntaxhighlighter .line.highlighted.alt1 .content,
.syntaxhighlighter .line.highlighted.alt2 .content
{
background-color: #ddd !important;
}
/* Gutter line numbers */
.syntaxhighlighter .line .number
{
color: #aaa !important;
}
/* Add border to the lines */
.syntaxhighlighter .line .content
{
border-left: 2px solid #ccc !important;
color: #000 !important;
}
.syntaxhighlighter.printing .line .content
{
border: 0 !important;
}
/* First line */
.syntaxhighlighter .line.alt1 .content
{
background-color: #fafafa !important;
}
/* Second line */
.syntaxhighlighter .line.alt2 .content
{
background-color: #fafafa !important;
}
.syntaxhighlighter .line .content .block
{
/* background: url(wrapping.png) 0 14px no-repeat !important;*/
}
.syntaxhighlighter .ruler
{
color: silver !important;
background-color: #F8F8F8 !important;
border-left: 3px solid #6CE26C !important;
}
.syntaxhighlighter.nogutter .ruler
{
border: 0 !important;
}
.syntaxhighlighter .toolbar
{
background-color: #ddd !important;
}
.syntaxhighlighter .toolbar a
{
color: #a0a0a0 !important;
}
.syntaxhighlighter .toolbar a:hover
{
color: red !important;
}
.syntaxhighlighter .comments,
.syntaxhighlighter .comments a
{
color: #999988 !important;
font-style: italic !important;
}
.syntaxhighlighter .string,
.syntaxhighlighter .string a
{
color: #D81745 !important;
}
.syntaxhighlighter .keyword
{
font-weight: bold !important;
}
.syntaxhighlighter .preprocessor
{
color: gray !important;
}
.syntaxhighlighter .regex
{
color: #159828;
}
.syntaxhighlighter .numbers
{
color:#1C9898;
}
.syntaxhighlighter .expr
{
color:#D81745;
}
.syntaxhighlighter .method
{
font-style: italic;
}
.syntaxhighlighter .variable
{
color: #177F80 !important;
}
.syntaxhighlighter .value
{
color: red !important;
}
.syntaxhighlighter .functions
{
color: #990000 !important;
font-weight:bold !important;
}
.syntaxhighlighter .constants
{
color: #177F80 !important;
}
.syntaxhighlighter .script
{
background-color: yellow !important;
}
.syntaxhighlighter .color1,
.syntaxhighlighter .color1 a
{
color: #177F80 !important;
}
.syntaxhighlighter .color2,
.syntaxhighlighter .color2 a
{
color: #960B73 !important;
}
.syntaxhighlighter .color3,
.syntaxhighlighter .color3 a
{
color: red !important;
}
/** end ugliness */

View File

@ -12,7 +12,7 @@
// Remove existing anchor redirection in the url
var pageURL = window.location.href.replace(/#[a-zA-Z0-9\-\_]*/g, '');
$('#left-column h1[id], #left-column h2[id], #left-column h3[id], #left-column h4[id]').each(function(i) {
$('#content-column h1[id], #content-column h2[id], #content-column h3[id], #content-column h4[id]').each(function(i) {
var current = $(this);
toc += '<li class="' + current.attr("tagName").toLowerCase() + '"><a id="link' + i + '" href="'+ pageURL +'#' + $(this).attr('id') + '" title="' + current.html() + '">' + current.html() + '</a></li>';
});
@ -29,7 +29,7 @@
*/
var url = window.location.href;
$("#left-column h1[id], #left-column h2[id], #left-column h3[id], #left-column h4[id], #left-column h5[id], #left-column h6[id]").each(function() {
$("#content-column h1[id], #content-column h2[id], #content-column h3[id], #content-column h4[id], #content-column h5[id], #content-column h6[id]").each(function() {
var link = '<a class="heading-anchor-link" title="Link to this section" href="'+ url + '#' + $(this).attr('id') + '">&para;</a>';
$(this).append(' ' + link);
});

View File

@ -1,6 +1,5 @@
<% if EntityPages %>
<div id="sibling-pages" class="sidebar-box">
<h4>In this module:</h4>
<ul>
<% control EntityPages %>
<li>

View File

@ -0,0 +1,13 @@
<div class="warningBox" id="outdated-release">
<div class="warningBoxTop">
<% control VersionWarning %>
<% if OutdatedRelease %>
<p>This document contains information for an <strong>outdated</strong> version <% if Top.Version %>(<strong>$Top.Version</strong>)<% end_if %> and may not be maintained any more.</p>
<p>If some of your projects still use this version, consider upgrading as soon as possible.</p>
<% else_if FutureRelease %>
<p>This document contains information about a <strong>future</strong> release <% if StableVersion %>and not the current stable version (<strong>$StableVersion</strong>)<% end_if %>.</p>
<p>Be aware that information on this page may change and API's may not be stable for production use.</p>
<% end_if %>
<% end_control %>
</div>
</div>

View File

@ -1,10 +1,14 @@
<% if VersionWarning %>
<% include DocumentationVersion_warning %>
<% end_if %>
<div id="documentation-page">
<div id="left-column">
<div id="content-column">
$Content
</div>
<% if Content %>
<div id="right-column">
<div id="sidebar-column">
<% include DocTableOfContents %>
<% include DocInThisModule %>
</div>

View File

@ -1,5 +1,9 @@
<% if VersionWarning %>
<% include DocumentationVersion_warning %>
<% end_if %>
<div id="module-home">
<div id="left-column">
<div id="content-column">
<% if Content %>
$Content
<% else %>
@ -7,7 +11,7 @@
<% end_if %>
</div>
<div id="right-column">
<div id="sidebar-column">
<% include DocInThisModule %>
</div>
</div>

View File

@ -1,8 +1,8 @@
<div id="home">
<h2><% _t('DOCUMENTEDMODULES', 'Documented Modules') %></h2>
<% if Modules %>
<% control Modules %>
<% if Entities %>
<% control Entities %>
<div class="module">
<h3><a href="$Link">$Title</a></h3>
</div>

View File

@ -1,7 +1,10 @@
<div id="documentation-page">
<div id="left-column">
<div id="content-column">
<p>Your search for <strong>&quot;$Query.XML&quot;</strong> found $TotalResults result<% if TotalResults != 1 %>s<% end_if %>.</p>
<% if Modules || Versions %>
<p>Limited search to <% if Modules %>$Modules <% if Versions %>of<% end_if %><% end_if %> <% if Versions %>versions $Versions<% end_if %>
<% end_if %>
<% if Results %>
<p>Showing page $ThisPage of $TotalPages</p>
@ -40,7 +43,14 @@
<% end_if %>
</div>
<div id="right-column">
<div id="sidebar-column">
<<<<<<< HEAD
<!-- needs advanced search options -->
=======
<div class="sidebar-box">
<h4><% _t('ADVANCEDSEARCH', 'Advanced Search') %></h4>
$AdvancedSearchForm
</div>
>>>>>>> origin/master
</div>
</div>

View File

@ -19,15 +19,15 @@ class DocumentationEntityTest extends SapphireTest {
$this->assertFalse($entity->hasLanguage('fr'));
}
function testgetLatestVersion() {
function testgetStableVersion() {
$entity = new DocumentationEntity('docs', '1.0', '../sapphiredocs/tests/docs/', 'My Test');
$entity->addVersion('1.1', '../sapphiredocs/tests/docs-v2.4/');
$entity->addVersion('0.0', '../sapphiredocs/tests/docs-v3.0/');
$this->assertEquals('1.1', $entity->getLatestVersion(), 'Automatic version sorting');
$this->assertEquals('1.1', $entity->getStableVersion(), 'Automatic version sorting');
$entity = new DocumentationEntity('docs', '1.0', '../sapphiredocs/tests/docs/', 'My Test');
$entity->addVersion('1.1.', '../sapphiredocs/tests/docs-v2.4/');
$entity->setLatestVersion('1.0');
$this->assertEquals('1.0', $entity->getLatestVersion(), 'Manual setting');
$entity->setStableVersion('1.0');
$this->assertEquals('1.0', $entity->getStableVersion(), 'Manual setting');
}
}

View File

@ -34,7 +34,7 @@ class DocumentationPageTest extends SapphireTest {
// test with version.
$entity = DocumentationService::register("versionlinks", BASE_PATH . "/sapphiredocs/tests/docs-v2.4/", '1');
$entity->addVersion('2', BASE_PATH . "/sapphiredocs/tests/docs-v3.0/");
$entity->setLatestVersion('2');
$entity->setStableVersion('2');
$page = new DocumentationPage();
$page->setRelativePath('test.md');

View File

@ -5,7 +5,7 @@
* @subpackage tests
*/
class DocumentationSearchTest extends SapphireTest {
class DocumentationSearchTest extends FunctionalTest {
function setUp() {
parent::setUp();
@ -17,7 +17,6 @@ class DocumentationSearchTest extends SapphireTest {
}
function testGetAllPages() {
if(!DocumentationSearch::enabled()) return;
DocumentationService::set_automatic_registration(false);
@ -27,4 +26,25 @@ class DocumentationSearchTest extends SapphireTest {
$this->assertEquals(7, $search->Count(), '5 pages. 5 pages in entire folder');
}
function testOpenSearchControllerAccessible() {
$c = new DocumentationOpenSearchController();
$response = $c->handleRequest(new SS_HTTPRequest('GET', ''));
$this->assertEquals(404, $response->getStatusCode());
// test accessing it when the search isn't active
DocumentationSearch::enable(false);
$response = $c->handleRequest(new SS_HTTPRequest('GET', 'description/'));
$this->assertEquals(404, $response->getStatusCode());
// test we get a response to the description. The meta data test will check
// that the individual fields are valid but we should check urls are there
DocumentationSearch::enable(true);
$response = $c->handleRequest(new SS_HTTPRequest('GET', 'description'));
$this->assertEquals(200, $response->getStatusCode());
$desc = new SimpleXMLElement($response->getBody());
$this->assertEquals(2, count($desc->Url));
}
}

View File

@ -250,4 +250,26 @@ class DocumentationViewerTest extends FunctionalTest {
$this->assertStringEndsWith($expected, $page->Link);
}
}
function testVersionWarning() {
$v = new DocumentationViewer();
// the current version is set to 2.4, no notice should be shown on that page
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4'));
$this->assertFalse($v->VersionWarning());
// 2.3 is an older release, hitting that should return us an outdated flag
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.3'));
$warn = $v->VersionWarning();
$this->assertTrue($warn->OutdatedRelease);
$this->assertNull($warn->FutureRelease);
// 3.0 is a future release
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/3.0'));
$warn = $v->VersionWarning();
$this->assertNull($warn->OutdatedRelease);
$this->assertTrue($warn->FutureRelease);
}
}