1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Add an "{anchor #xyz}" rule to Remarkup

Summary: Ref T13410. Fixes T4280. Allows you to put a named anchor into a document explicitly.

Test Plan: Used `{anchor ...}` in Remarkup, used location bar to jump to anchors.

Maniphest Tasks: T13410, T4280

Differential Revision: https://secure.phabricator.com/D20825
This commit is contained in:
epriestley 2019-09-24 10:10:10 -07:00
parent bff72ce3b5
commit b1d4d5c00c
5 changed files with 85 additions and 6 deletions

View file

@ -5598,6 +5598,7 @@ phutil_register_library_map(array(
'PhutilQsprintfInterface' => 'infrastructure/storage/xsprintf/PhutilQsprintfInterface.php', 'PhutilQsprintfInterface' => 'infrastructure/storage/xsprintf/PhutilQsprintfInterface.php',
'PhutilQueryString' => 'infrastructure/storage/xsprintf/PhutilQueryString.php', 'PhutilQueryString' => 'infrastructure/storage/xsprintf/PhutilQueryString.php',
'PhutilRealNameContextFreeGrammar' => 'infrastructure/lipsum/PhutilRealNameContextFreeGrammar.php', 'PhutilRealNameContextFreeGrammar' => 'infrastructure/lipsum/PhutilRealNameContextFreeGrammar.php',
'PhutilRemarkupAnchorRule' => 'infrastructure/markup/markuprule/PhutilRemarkupAnchorRule.php',
'PhutilRemarkupBlockInterpreter' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockInterpreter.php', 'PhutilRemarkupBlockInterpreter' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockInterpreter.php',
'PhutilRemarkupBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php', 'PhutilRemarkupBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php',
'PhutilRemarkupBlockStorage' => 'infrastructure/markup/PhutilRemarkupBlockStorage.php', 'PhutilRemarkupBlockStorage' => 'infrastructure/markup/PhutilRemarkupBlockStorage.php',
@ -12391,6 +12392,7 @@ phutil_register_library_map(array(
'PhutilPhabricatorAuthAdapter' => 'PhutilOAuthAuthAdapter', 'PhutilPhabricatorAuthAdapter' => 'PhutilOAuthAuthAdapter',
'PhutilQueryString' => 'Phobject', 'PhutilQueryString' => 'Phobject',
'PhutilRealNameContextFreeGrammar' => 'PhutilContextFreeGrammar', 'PhutilRealNameContextFreeGrammar' => 'PhutilContextFreeGrammar',
'PhutilRemarkupAnchorRule' => 'PhutilRemarkupRule',
'PhutilRemarkupBlockInterpreter' => 'Phobject', 'PhutilRemarkupBlockInterpreter' => 'Phobject',
'PhutilRemarkupBlockRule' => 'Phobject', 'PhutilRemarkupBlockRule' => 'Phobject',
'PhutilRemarkupBlockStorage' => 'Phobject', 'PhutilRemarkupBlockStorage' => 'Phobject',

View file

@ -715,6 +715,18 @@ Press {key down down-right right LP} to activate the hadoken technique.
> Press {key down down-right right LP} to activate the hadoken technique. > Press {key down down-right right LP} to activate the hadoken technique.
Anchors
========
You can use `{anchor #xyz}` to create a document anchor and later link to
it directly with `#xyz` in the URI.
Headers also automatically create named anchors.
If you navigate to `#xyz` in your browser location bar, the page will scroll
to the first anchor with "xyz" as a prefix of the anchor name.
= Fullscreen Mode = = Fullscreen Mode =
Remarkup editors provide a fullscreen composition mode. This can make it easier Remarkup editors provide a fullscreen composition mode. This can make it easier

View file

@ -539,6 +539,7 @@ final class PhabricatorMarkupEngine extends Phobject {
$rules[] = new PhutilRemarkupDelRule(); $rules[] = new PhutilRemarkupDelRule();
$rules[] = new PhutilRemarkupUnderlineRule(); $rules[] = new PhutilRemarkupUnderlineRule();
$rules[] = new PhutilRemarkupHighlightRule(); $rules[] = new PhutilRemarkupHighlightRule();
$rules[] = new PhutilRemarkupAnchorRule();
foreach (self::loadCustomInlineRules() as $rule) { foreach (self::loadCustomInlineRules() as $rule) {
$rules[] = clone $rule; $rules[] = clone $rule;

View file

@ -162,12 +162,7 @@ final class PhutilRemarkupHeaderBlockRule extends PhutilRemarkupBlockRule {
public static function getAnchorNameFromHeaderText($text) { public static function getAnchorNameFromHeaderText($text) {
$anchor = phutil_utf8_strtolower($text); $anchor = phutil_utf8_strtolower($text);
$anchor = PhutilRemarkupAnchorRule::normalizeAnchor($anchor);
// Replace all latin characters which are not "a-z" or "0-9" with "-".
// Preserve other characters, since non-latin letters and emoji work
// fine in anchors.
$anchor = preg_replace('/[\x00-\x2F\x3A-\x60\x7B-\x7F]+/', '-', $anchor);
$anchor = trim($anchor, '-');
// Truncate the fragment to something reasonable. // Truncate the fragment to something reasonable.
$anchor = id(new PhutilUTF8StringTruncator()) $anchor = id(new PhutilUTF8StringTruncator())

View file

@ -0,0 +1,69 @@
<?php
final class PhutilRemarkupAnchorRule extends PhutilRemarkupRule {
public function getPriority() {
return 200.0;
}
public function apply($text) {
return preg_replace_callback(
'/{anchor\s+#([^\s}]+)}/s',
array($this, 'markupAnchor'),
$text);
}
protected function markupAnchor(array $matches) {
$engine = $this->getEngine();
if ($engine->isTextMode()) {
return null;
}
if ($engine->isHTMLMailMode()) {
return null;
}
if ($engine->isAnchorMode()) {
return null;
}
if (!$this->isFlatText($matches[0])) {
return $matches[0];
}
if (!self::isValidAnchorName($matches[1])) {
return $matches[0];
}
$tag_view = phutil_tag(
'a',
array(
'name' => $matches[1],
),
'');
return $this->getEngine()->storeText($tag_view);
}
public static function isValidAnchorName($anchor_name) {
$normal_anchor = self::normalizeAnchor($anchor_name);
if ($normal_anchor === $anchor_name) {
return true;
}
return false;
}
public static function normalizeAnchor($anchor) {
// Replace all latin characters which are not "a-z" or "0-9" with "-".
// Preserve other characters, since non-latin letters and emoji work
// fine in anchors.
$anchor = preg_replace('/[\x00-\x2F\x3A-\x60\x7B-\x7F]+/', '-', $anchor);
$anchor = trim($anchor, '-');
return $anchor;
}
}