diff --git a/src/applications/diviner/controller/DivinerAtomController.php b/src/applications/diviner/controller/DivinerAtomController.php index 21779c8a63..02de0a92d0 100644 --- a/src/applications/diviner/controller/DivinerAtomController.php +++ b/src/applications/diviner/controller/DivinerAtomController.php @@ -33,7 +33,7 @@ final class DivinerAtomController extends DivinerController { return new Aphront404Response(); } - $atom = id(new DivinerAtomQuery()) + $symbol = id(new DivinerAtomQuery()) ->setViewer($viewer) ->withBookPHIDs(array($book->getPHID())) ->withTypes(array($this->atomType)) @@ -43,31 +43,91 @@ final class DivinerAtomController extends DivinerController { ->needAtoms(true) ->executeOne(); - if (!$atom) { + if (!$symbol) { return new Aphront404Response(); } + $atom = $symbol->getAtom(); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addCrumb( id(new PhabricatorCrumbView()) - ->setName($book->getName()) + ->setName($book->getShortTitle()) ->setHref('/book/'.$book->getName().'/')); + $atom_short_title = $atom->getDocblockMetaValue( + 'short', + $symbol->getTitle()); + $crumbs->addCrumb( id(new PhabricatorCrumbView()) - ->setName($atom->getName())); + ->setName($atom_short_title)); - $header = id(new PhabricatorHeaderView())->setHeader($atom->getName()); + $header = id(new PhabricatorHeaderView()) + ->setHeader($symbol->getTitle()) + ->addTag( + id(new PhabricatorTagView()) + ->setType(PhabricatorTagView::TYPE_STATE) + ->setBackgroundColor(PhabricatorTagView::COLOR_BLUE) + ->setName($this->renderAtomTypeName($atom->getType()))); + + $properties = id(new PhabricatorPropertyListView()); + + $group = $atom->getDocblockMetaValue('group'); + if ($group) { + $group_name = $book->getGroupName($group); + } else { + $group_name = null; + } + + $properties->addProperty( + pht('Defined'), + $atom->getFile().':'.$atom->getLine()); + + $field = 'default'; + $engine = id(new PhabricatorMarkupEngine()) + ->setViewer($viewer) + ->addObject($symbol, $field) + ->process(); + + $content = $engine->getOutput($symbol, $field); + + $toc = $engine->getEngineMetadata( + $symbol, + $field, + PhutilRemarkupEngineRemarkupHeaderBlockRule::KEY_HEADER_TOC, + array()); $document = id(new PHUIDocumentView()) + ->setBook($book->getTitle(), $group_name) + ->setHeader($header) + ->appendChild($properties) ->appendChild( phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), - phutil_safe_html($atom->getContent()))); + array( + $content, + ))); + + if ($toc) { + $side = new PHUIListView(); + $side->addMenuItem( + id(new PHUIListItemView()) + ->setName(pht('Contents')) + ->setType(PHUIListItemView::TYPE_LABEL)); + foreach ($toc as $key => $entry) { + $side->addMenuItem( + id(new PHUIListItemView()) + ->setName($entry[1]) + ->setHref('#'.$key)); + } + + $document->setSideNav($side); + } return $this->buildApplicationPage( array( @@ -75,10 +135,14 @@ final class DivinerAtomController extends DivinerController { $document, ), array( - 'title' => $atom->getName(), + 'title' => $symbol->getTitle(), 'dust' => true, 'device' => true, )); } + private function renderAtomTypeName($name) { + return phutil_utf8_ucwords($name); + } + } diff --git a/src/applications/diviner/controller/DivinerBookController.php b/src/applications/diviner/controller/DivinerBookController.php index 18bcfa3b9d..31c21c78b7 100644 --- a/src/applications/diviner/controller/DivinerBookController.php +++ b/src/applications/diviner/controller/DivinerBookController.php @@ -29,7 +29,7 @@ final class DivinerBookController extends DivinerController { $crumbs->addCrumb( id(new PhabricatorCrumbView()) - ->setName($book->getTitle()) + ->setName($book->getShortTitle()) ->setHref('/book/'.$book->getName().'/')); $header = id(new PhabricatorHeaderView())->setHeader($book->getTitle()); @@ -56,19 +56,7 @@ final class DivinerBookController extends DivinerController { $out = array(); foreach ($groups as $group => $atoms) { - $group_info = idx($group_spec, $group); - if (!is_array($group_info)) { - $group_info = array(); - } - - $group_name = idx($group_info, 'name'); - if (!strlen($group_name)) { - if (strlen($group)) { - $group_name = $group; - } else { - $group_name = pht('Free Radicals'); - } - } + $group_name = $book->getGroupName($group); $out[] = id(new PhabricatorHeaderView()) ->setHeader($group_name); diff --git a/src/applications/diviner/publisher/DivinerLivePublisher.php b/src/applications/diviner/publisher/DivinerLivePublisher.php index 9e1c7b6e8b..317739180f 100644 --- a/src/applications/diviner/publisher/DivinerLivePublisher.php +++ b/src/applications/diviner/publisher/DivinerLivePublisher.php @@ -113,14 +113,12 @@ final class DivinerLivePublisher extends DivinerPublisher { ->setGroupName($ref->getGroup()); if ($is_documentable) { - $renderer = $this->getRenderer(); - $content = $renderer->renderAtom($atom); - $storage = $this->loadAtomStorageForSymbol($symbol) ->setAtomData($atom->toDictionary()) - ->setContent((string)phutil_safe_html($content)) + ->setContent(null) ->save(); + $renderer = $this->getRenderer(); $summary = $renderer->renderAtomSummary($atom); $summary = (string)phutil_safe_html($summary); $symbol->setSummary($summary); diff --git a/src/applications/diviner/renderer/DivinerDefaultRenderer.php b/src/applications/diviner/renderer/DivinerDefaultRenderer.php index 0cc129437a..c6d7b35806 100644 --- a/src/applications/diviner/renderer/DivinerDefaultRenderer.php +++ b/src/applications/diviner/renderer/DivinerDefaultRenderer.php @@ -182,12 +182,13 @@ final class DivinerDefaultRenderer extends DivinerRenderer { } protected function getBlockMarkupEngine() { - $engine = PhabricatorMarkupEngine::newMarkupEngine( - array( - 'preserve-linebreaks' => false, - )); + $engine = PhabricatorMarkupEngine::newMarkupEngine(array()); + + $engine->setConfig('preserve-linebreaks', false); $engine->setConfig('viewer', new PhabricatorUser()); $engine->setConfig('diviner.renderer', $this); + $engine->setConfig('header.generate-toc', true); + return $engine; } diff --git a/src/applications/diviner/storage/DivinerLiveAtom.php b/src/applications/diviner/storage/DivinerLiveAtom.php index f682c15d6d..933d81bcad 100644 --- a/src/applications/diviner/storage/DivinerLiveAtom.php +++ b/src/applications/diviner/storage/DivinerLiveAtom.php @@ -10,6 +10,7 @@ final class DivinerLiveAtom extends DivinerDAO { return array( self::CONFIG_TIMESTAMPS => false, self::CONFIG_SERIALIZATION => array( + 'content' => self::SERIALIZATION_JSON, 'atomData' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); diff --git a/src/applications/diviner/storage/DivinerLiveBook.php b/src/applications/diviner/storage/DivinerLiveBook.php index 2155a5b7e4..25e2cbaf49 100644 --- a/src/applications/diviner/storage/DivinerLiveBook.php +++ b/src/applications/diviner/storage/DivinerLiveBook.php @@ -35,6 +35,16 @@ final class DivinerLiveBook extends DivinerDAO return $this->getConfig('title', $this->getName()); } + public function getShortTitle() { + return $this->getConfig('short', $this->getTitle()); + } + + public function getGroupName($group) { + $groups = $this->getConfig('groups'); + $spec = idx($groups, $group, array()); + return idx($spec, 'name', pht('Free Radicals')); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php index 06dee25667..aee5aa3203 100644 --- a/src/applications/diviner/storage/DivinerLiveSymbol.php +++ b/src/applications/diviner/storage/DivinerLiveSymbol.php @@ -1,7 +1,7 @@ content === null) { - throw new Exception("Call attachAtom() before getContent()!"); - } - return $this->content; - } - public function getAtom() { if ($this->atom === null) { throw new Exception("Call attachAtom() before getAtom()!"); @@ -60,7 +52,6 @@ final class DivinerLiveSymbol extends DivinerDAO } public function attachAtom(DivinerLiveAtom $atom) { - $this->content = $atom->getContent(); $this->atom = DivinerAtom::newFromDictionary($atom->getAtomData()); return $this; } @@ -135,4 +126,41 @@ final class DivinerLiveSymbol extends DivinerDAO return $this->getBook()->hasAutomaticCapability($capability, $viewer); } + +/* -( Markup Interface )--------------------------------------------------- */ + + + public function getMarkupFieldKey($field) { + return $this->getPHID().':'.$field.':'.$this->getGraphHash(); + } + + + public function newMarkupEngine($field) { + $engine = PhabricatorMarkupEngine::newMarkupEngine(array()); + + $engine->setConfig('preserve-linebreaks', false); +// $engine->setConfig('diviner.renderer', new DivinerDefaultRenderer()); + $engine->setConfig('header.generate-toc', true); + + return $engine; + } + + + public function getMarkupText($field) { + return $this->getAtom()->getDocblockText(); + } + + + public function didMarkupText( + $field, + $output, + PhutilMarkupEngine $engine) { + return $output; + } + + + public function shouldUseMarkupCache($field) { + return true; + } + } diff --git a/src/docs/book/user.book b/src/docs/book/user.book index a8f23f2cf3..e0c062fae5 100644 --- a/src/docs/book/user.book +++ b/src/docs/book/user.book @@ -1,6 +1,7 @@ { "name" : "phabricator", "title" : "Phabricator User Documentation", + "short" : "Phabricator User Docs", "root" : "../../../", "groups" : { "intro" : { diff --git a/src/docs/feedback.diviner b/src/docs/feedback.diviner index 4caf6c31db..216482030d 100644 --- a/src/docs/feedback.diviner +++ b/src/docs/feedback.diviner @@ -1,4 +1,5 @@ @title Give Feedback! Get Support! +@short Feedback/Support @group intro How to give us feedback, report bugs, and request features, and get support for diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php index a117112a0e..f929c111fd 100644 --- a/src/infrastructure/markup/PhabricatorMarkupEngine.php +++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php @@ -120,15 +120,17 @@ final class PhabricatorMarkupEngine { // Load or build the preprocessor caches. $blocks = $this->loadPreprocessorCaches($engines, $objects); + $blocks = mpull($blocks, 'getCacheData'); + + $this->engineCaches = $blocks; // Finalize the output. foreach ($objects as $key => $info) { - $data = $blocks[$key]->getCacheData(); $engine = $engines[$key]; $field = $info['field']; $object = $info['object']; - $output = $engine->postprocessText($data); + $output = $engine->postprocessText($blocks[$key]); $output = $object->didMarkupText($field, $output, $engine); $this->objects[$key]['output'] = $output; } @@ -149,18 +151,47 @@ final class PhabricatorMarkupEngine { */ public function getOutput(PhabricatorMarkupInterface $object, $field) { $key = $this->getMarkupFieldKey($object, $field); + $this->requireKeyProcessed($key); + return $this->objects[$key]['output']; + } + + + /** + * Retrieve engine metadata for a given field. + * + * @param PhabricatorMarkupInterface The object to retrieve. + * @param string The field to retrieve. + * @param string The engine metadata field to retrieve. + * @param wild Optional default value. + * @task markup + */ + public function getEngineMetadata( + PhabricatorMarkupInterface $object, + $field, + $metadata_key, + $default = null) { + + $key = $this->getMarkupFieldKey($object, $field); + $this->requireKeyProcessed($key); + + return idx($this->engineCaches[$key]['metadata'], $metadata_key, $default); + } + + + /** + * @task markup + */ + private function requireKeyProcessed($key) { if (empty($this->objects[$key])) { throw new Exception( - "Call addObject() before getOutput() (key = '{$key}')."); + "Call addObject() before using results (key = '{$key}')."); } if (!isset($this->objects[$key]['output'])) { throw new Exception( - "Call process() before getOutput()."); + "Call process() before using results."); } - - return $this->objects[$key]['output']; } diff --git a/src/view/phui/PHUIDocumentView.php b/src/view/phui/PHUIDocumentView.php index 48be6946ea..cae4cf5b5a 100644 --- a/src/view/phui/PHUIDocumentView.php +++ b/src/view/phui/PHUIDocumentView.php @@ -21,11 +21,13 @@ final class PHUIDocumentView extends AphrontTagView { } public function setSideNav(PHUIListView $list) { + $list->setType(PHUIListView::SIDENAV_LIST); $this->sidenav = $list; return $this; } public function setTopNav(PHUIListView $list) { + $list->setType(PHUIListView::NAVBAR_LIST); $this->topnav = $list; return $this; }