@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
at upstream/main 181 lines 4.6 kB view raw
1<?php 2 3abstract class PhutilRemarkupBlockRule extends Phobject { 4 5 private $engine; 6 private $rules = array(); 7 8 /** 9 * Determine the order in which blocks execute. Blocks with smaller priority 10 * numbers execute sooner than blocks with larger priority numbers. The 11 * default priority for blocks is `500`. 12 * 13 * Priorities are used to disambiguate syntax which can match multiple 14 * patterns. For example, ` - Lorem ipsum...` may be a code block or a 15 * list. 16 * 17 * @return int Priority at which this block should execute. 18 */ 19 public function getPriority() { 20 return 500; 21 } 22 23 final public function getPriorityVector() { 24 return id(new PhutilSortVector()) 25 ->addInt($this->getPriority()) 26 ->addString(get_class($this)); 27 } 28 29 abstract public function markupText($text, $children); 30 31 /** 32 * This will get an array of unparsed lines and return the number of lines 33 * from the first array value that it can parse. 34 * 35 * @param array $lines 36 * @param int $cursor 37 * 38 * @return int 39 */ 40 abstract public function getMatchingLineCount(array $lines, $cursor); 41 42 protected function didMarkupText() { 43 return; 44 } 45 46 public function willMarkupChildBlocks() { 47 return; 48 } 49 50 public function didMarkupChildBlocks() { 51 return; 52 } 53 54 final public function setEngine(PhutilRemarkupEngine $engine) { 55 $this->engine = $engine; 56 $this->updateRules(); 57 return $this; 58 } 59 60 final protected function getEngine() { 61 return $this->engine; 62 } 63 64 /** 65 * @param array<PhutilRemarkupRule> $rules 66 */ 67 public function setMarkupRules(array $rules) { 68 assert_instances_of($rules, PhutilRemarkupRule::class); 69 $this->rules = $rules; 70 $this->updateRules(); 71 return $this; 72 } 73 74 private function updateRules() { 75 $engine = $this->getEngine(); 76 if ($engine) { 77 $this->rules = msort($this->rules, 'getPriority'); 78 foreach ($this->rules as $rule) { 79 $rule->setEngine($engine); 80 } 81 } 82 return $this; 83 } 84 85 final public function getMarkupRules() { 86 return $this->rules; 87 } 88 89 final public function postprocess() { 90 $this->didMarkupText(); 91 } 92 93 final protected function applyRules($text) { 94 foreach ($this->getMarkupRules() as $rule) { 95 $text = $rule->apply($text); 96 } 97 return $text; 98 } 99 100 public function supportsChildBlocks() { 101 return false; 102 } 103 104 public function extractChildText($text) { 105 throw new PhutilMethodNotImplementedException(); 106 } 107 108 protected function renderRemarkupTable(array $out_rows) { 109 assert_instances_of($out_rows, 'array'); 110 111 if ($this->getEngine()->isTextMode()) { 112 $lengths = array(); 113 foreach ($out_rows as $r => $row) { 114 foreach ($row['content'] as $c => $cell) { 115 $text = $this->getEngine()->restoreText($cell['content']); 116 $lengths[$c][$r] = phutil_utf8_strlen($text); 117 } 118 } 119 $max_lengths = array_map('max', $lengths); 120 121 $out = array(); 122 foreach ($out_rows as $r => $row) { 123 $headings = false; 124 foreach ($row['content'] as $c => $cell) { 125 $length = $max_lengths[$c] - $lengths[$c][$r]; 126 $out[] = '| '.$cell['content'].str_repeat(' ', $length).' '; 127 if ($cell['type'] == 'th') { 128 $headings = true; 129 } 130 } 131 $out[] = "|\n"; 132 133 if ($headings) { 134 foreach ($row['content'] as $c => $cell) { 135 $char = ($cell['type'] == 'th' ? '-' : ' '); 136 $out[] = '| '.str_repeat($char, $max_lengths[$c]).' '; 137 } 138 $out[] = "|\n"; 139 } 140 } 141 142 return rtrim(implode('', $out), "\n"); 143 } 144 145 if ($this->getEngine()->isHTMLMailMode()) { 146 $table_attributes = array( 147 'style' => 'border-collapse: separate; 148 border-spacing: 1px; 149 background: #d3d3d3; 150 margin: 12px 0;', 151 ); 152 $cell_attributes = array( 153 'style' => 'background: #ffffff; 154 padding: 3px 6px;', 155 ); 156 } else { 157 $table_attributes = array( 158 'class' => 'remarkup-table', 159 ); 160 $cell_attributes = array(); 161 } 162 163 $out = array(); 164 $out[] = "\n"; 165 foreach ($out_rows as $row) { 166 $cells = array(); 167 foreach ($row['content'] as $cell) { 168 $cells[] = phutil_tag( 169 $cell['type'], 170 $cell_attributes, 171 $cell['content']); 172 } 173 $out[] = phutil_tag($row['type'], array(), $cells); 174 $out[] = "\n"; 175 } 176 177 $table = phutil_tag('table', $table_attributes, $out); 178 return phutil_tag_div('remarkup-table-wrap', $table); 179 } 180 181}