From dd1023e5a8f8aca512c798b9645e5dfe33edb87d Mon Sep 17 00:00:00 2001 From: June Rhodes Date: Sat, 16 Apr 2016 02:07:03 +0000 Subject: [PATCH] Support relative links in Phriction Summary: Resolves T7691. This turned out more complex than I really wanted, mainly because I needed to feed the slug information through to both the document renderer and the preview window that appears in the edit controller. After this change, you can now create relative links in Phriction by doing `[[ ./../some/relative/path ]]`. Relative paths aren't handled anywhere else (they'll still render, but the dots are turned into a literal 'dot' as per existing behaviour). Test Plan: Created some Phriction documents with relative links, saw them all link correctly. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin Maniphest Tasks: T7691 Differential Revision: https://secure.phabricator.com/D15732 --- src/__phutil_library_map__.php | 2 ++ .../PhabricatorPhrictionApplication.php | 2 +- .../controller/PhrictionEditController.php | 2 +- .../PhrictionMarkupPreviewController.php | 28 ++++++++++++++++ .../markup/PhrictionRemarkupRule.php | 33 +++++++++++++++++++ .../phriction/storage/PhrictionContent.php | 3 +- 6 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 src/applications/phriction/controller/PhrictionMarkupPreviewController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e76e768774..ac506ce0f5 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3905,6 +3905,7 @@ phutil_register_library_map(array( 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 'PhrictionInfoConduitAPIMethod' => 'applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php', 'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php', + 'PhrictionMarkupPreviewController' => 'applications/phriction/controller/PhrictionMarkupPreviewController.php', 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', 'PhrictionRemarkupRule' => 'applications/phriction/markup/PhrictionRemarkupRule.php', @@ -8702,6 +8703,7 @@ phutil_register_library_map(array( 'PhrictionHistoryController' => 'PhrictionController', 'PhrictionInfoConduitAPIMethod' => 'PhrictionConduitAPIMethod', 'PhrictionListController' => 'PhrictionController', + 'PhrictionMarkupPreviewController' => 'PhabricatorController', 'PhrictionMoveController' => 'PhrictionController', 'PhrictionNewController' => 'PhrictionController', 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', diff --git a/src/applications/phriction/application/PhabricatorPhrictionApplication.php b/src/applications/phriction/application/PhabricatorPhrictionApplication.php index 7721749c36..c996365c67 100644 --- a/src/applications/phriction/application/PhabricatorPhrictionApplication.php +++ b/src/applications/phriction/application/PhabricatorPhrictionApplication.php @@ -59,7 +59,7 @@ final class PhabricatorPhrictionApplication extends PhabricatorApplication { 'new/' => 'PhrictionNewController', 'move/(?P[1-9]\d*)/' => 'PhrictionMoveController', - 'preview/' => 'PhabricatorMarkupPreviewController', + 'preview/(?P.+/)' => 'PhrictionMarkupPreviewController', 'diff/(?P[1-9]\d*)/' => 'PhrictionDiffController', ), ); diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php index fd88bf9408..e0e27ad796 100644 --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -272,7 +272,7 @@ final class PhrictionEditController $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader($content->getTitle()) - ->setPreviewURI('/phriction/preview/') + ->setPreviewURI('/phriction/preview/'.$document->getSlug()) ->setControlID('document-textarea') ->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT); diff --git a/src/applications/phriction/controller/PhrictionMarkupPreviewController.php b/src/applications/phriction/controller/PhrictionMarkupPreviewController.php new file mode 100644 index 0000000000..b5c97e5c64 --- /dev/null +++ b/src/applications/phriction/controller/PhrictionMarkupPreviewController.php @@ -0,0 +1,28 @@ +getRequest(); + $viewer = $request->getUser(); + + $text = $request->getStr('text'); + $slug = $request->getURIData('slug'); + + $output = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff()) + ->setPreserveLinebreaks(true) + ->setDisableCache(true) + ->setContent($text), + 'default', + $viewer, + array( + 'phriction.isPreview' => true, + 'phriction.slug' => $slug, + )); + + return id(new AphrontAjaxResponse()) + ->setContent($output); + } +} diff --git a/src/applications/phriction/markup/PhrictionRemarkupRule.php b/src/applications/phriction/markup/PhrictionRemarkupRule.php index 6b66dd95d1..c3d9aaf6a0 100644 --- a/src/applications/phriction/markup/PhrictionRemarkupRule.php +++ b/src/applications/phriction/markup/PhrictionRemarkupRule.php @@ -15,6 +15,39 @@ final class PhrictionRemarkupRule extends PhutilRemarkupRule { public function markupDocumentLink(array $matches) { $link = trim($matches[1]); + + // Handle relative links. + if (substr($link, 0, 2) === './') { + $base = null; + $context = $this->getEngine()->getConfig('contextObject'); + if ($context !== null && $context instanceof PhrictionContent) { + // Handle content when it's being rendered in document view. + $base = $context->getSlug(); + } + if ($context !== null && is_array($context) && + idx($context, 'phriction.isPreview')) { + // Handle content when it's a preview for the Phriction editor. + $base = idx($context, 'phriction.slug'); + } + if ($base !== null) { + $base_parts = explode('/', rtrim($base, '/')); + $rel_parts = explode('/', substr(rtrim($link, '/'), 2)); + foreach ($rel_parts as $part) { + if ($part === '.') { + // Consume standalone dots in a relative path, and do + // nothing with them. + } else if ($part === '..') { + if (count($base_parts) > 0) { + array_pop($base_parts); + } + } else { + array_push($base_parts, $part); + } + } + $link = implode('/', $base_parts).'/'; + } + } + $name = trim(idx($matches, 2, $link)); if (empty($matches[2])) { $name = explode('/', trim($name, '/')); diff --git a/src/applications/phriction/storage/PhrictionContent.php b/src/applications/phriction/storage/PhrictionContent.php index 99aaf0c7ec..3a2e20aa29 100644 --- a/src/applications/phriction/storage/PhrictionContent.php +++ b/src/applications/phriction/storage/PhrictionContent.php @@ -27,7 +27,8 @@ final class PhrictionContent extends PhrictionDAO return PhabricatorMarkupEngine::renderOneObject( $this, self::MARKUP_FIELD_BODY, - $viewer); + $viewer, + $this); } protected function getConfiguration() {