@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+85 -6
+2
src/__phutil_library_map__.php
··· 5598 5598 'PhutilQsprintfInterface' => 'infrastructure/storage/xsprintf/PhutilQsprintfInterface.php', 5599 5599 'PhutilQueryString' => 'infrastructure/storage/xsprintf/PhutilQueryString.php', 5600 5600 'PhutilRealNameContextFreeGrammar' => 'infrastructure/lipsum/PhutilRealNameContextFreeGrammar.php', 5601 + 'PhutilRemarkupAnchorRule' => 'infrastructure/markup/markuprule/PhutilRemarkupAnchorRule.php', 5601 5602 'PhutilRemarkupBlockInterpreter' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockInterpreter.php', 5602 5603 'PhutilRemarkupBlockRule' => 'infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php', 5603 5604 'PhutilRemarkupBlockStorage' => 'infrastructure/markup/PhutilRemarkupBlockStorage.php', ··· 12391 12392 'PhutilPhabricatorAuthAdapter' => 'PhutilOAuthAuthAdapter', 12392 12393 'PhutilQueryString' => 'Phobject', 12393 12394 'PhutilRealNameContextFreeGrammar' => 'PhutilContextFreeGrammar', 12395 + 'PhutilRemarkupAnchorRule' => 'PhutilRemarkupRule', 12394 12396 'PhutilRemarkupBlockInterpreter' => 'Phobject', 12395 12397 'PhutilRemarkupBlockRule' => 'Phobject', 12396 12398 'PhutilRemarkupBlockStorage' => 'Phobject',
+12
src/docs/user/userguide/remarkup.diviner
··· 715 715 > Press {key down down-right right LP} to activate the hadoken technique. 716 716 717 717 718 + Anchors 719 + ======== 720 + 721 + You can use `{anchor #xyz}` to create a document anchor and later link to 722 + it directly with `#xyz` in the URI. 723 + 724 + Headers also automatically create named anchors. 725 + 726 + If you navigate to `#xyz` in your browser location bar, the page will scroll 727 + to the first anchor with "xyz" as a prefix of the anchor name. 728 + 729 + 718 730 = Fullscreen Mode = 719 731 720 732 Remarkup editors provide a fullscreen composition mode. This can make it easier
+1
src/infrastructure/markup/PhabricatorMarkupEngine.php
··· 539 539 $rules[] = new PhutilRemarkupDelRule(); 540 540 $rules[] = new PhutilRemarkupUnderlineRule(); 541 541 $rules[] = new PhutilRemarkupHighlightRule(); 542 + $rules[] = new PhutilRemarkupAnchorRule(); 542 543 543 544 foreach (self::loadCustomInlineRules() as $rule) { 544 545 $rules[] = clone $rule;
+1 -6
src/infrastructure/markup/blockrule/PhutilRemarkupHeaderBlockRule.php
··· 162 162 163 163 public static function getAnchorNameFromHeaderText($text) { 164 164 $anchor = phutil_utf8_strtolower($text); 165 - 166 - // Replace all latin characters which are not "a-z" or "0-9" with "-". 167 - // Preserve other characters, since non-latin letters and emoji work 168 - // fine in anchors. 169 - $anchor = preg_replace('/[\x00-\x2F\x3A-\x60\x7B-\x7F]+/', '-', $anchor); 170 - $anchor = trim($anchor, '-'); 165 + $anchor = PhutilRemarkupAnchorRule::normalizeAnchor($anchor); 171 166 172 167 // Truncate the fragment to something reasonable. 173 168 $anchor = id(new PhutilUTF8StringTruncator())
+69
src/infrastructure/markup/markuprule/PhutilRemarkupAnchorRule.php
··· 1 + <?php 2 + 3 + final class PhutilRemarkupAnchorRule extends PhutilRemarkupRule { 4 + 5 + public function getPriority() { 6 + return 200.0; 7 + } 8 + 9 + public function apply($text) { 10 + return preg_replace_callback( 11 + '/{anchor\s+#([^\s}]+)}/s', 12 + array($this, 'markupAnchor'), 13 + $text); 14 + } 15 + 16 + protected function markupAnchor(array $matches) { 17 + $engine = $this->getEngine(); 18 + 19 + if ($engine->isTextMode()) { 20 + return null; 21 + } 22 + 23 + if ($engine->isHTMLMailMode()) { 24 + return null; 25 + } 26 + 27 + if ($engine->isAnchorMode()) { 28 + return null; 29 + } 30 + 31 + if (!$this->isFlatText($matches[0])) { 32 + return $matches[0]; 33 + } 34 + 35 + if (!self::isValidAnchorName($matches[1])) { 36 + return $matches[0]; 37 + } 38 + 39 + $tag_view = phutil_tag( 40 + 'a', 41 + array( 42 + 'name' => $matches[1], 43 + ), 44 + ''); 45 + 46 + return $this->getEngine()->storeText($tag_view); 47 + } 48 + 49 + public static function isValidAnchorName($anchor_name) { 50 + $normal_anchor = self::normalizeAnchor($anchor_name); 51 + 52 + if ($normal_anchor === $anchor_name) { 53 + return true; 54 + } 55 + 56 + return false; 57 + } 58 + 59 + public static function normalizeAnchor($anchor) { 60 + // Replace all latin characters which are not "a-z" or "0-9" with "-". 61 + // Preserve other characters, since non-latin letters and emoji work 62 + // fine in anchors. 63 + $anchor = preg_replace('/[\x00-\x2F\x3A-\x60\x7B-\x7F]+/', '-', $anchor); 64 + $anchor = trim($anchor, '-'); 65 + 66 + return $anchor; 67 + } 68 + 69 + }