@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<?php
2
3final class DifferentialChangesetOneUpMailRenderer
4 extends DifferentialChangesetRenderer {
5
6 public function isOneUpRenderer() {
7 return true;
8 }
9
10 protected function getRendererTableClass() {
11 return 'diff-1up-mail';
12 }
13
14 public function getRendererKey() {
15 return '1up-mail';
16 }
17
18 protected function renderChangeTypeHeader($force) {
19 return null;
20 }
21
22 protected function renderUndershieldHeader() {
23 return null;
24 }
25
26 public function renderShield($message, $force = 'default') {
27 return null;
28 }
29
30 protected function renderPropertyChangeHeader() {
31 return null;
32 }
33
34 public function renderTextChange(
35 $range_start,
36 $range_len,
37 $rows) {
38
39 $primitives = $this->buildPrimitives($range_start, $range_len);
40 return $this->renderPrimitives($primitives, $rows);
41 }
42
43 protected function renderPrimitives(array $primitives, $rows) {
44 $out = array();
45
46 $viewer = $this->getUser();
47 $old_bright = $viewer->getCSSValue('old-bright');
48 $new_bright = $viewer->getCSSValue('new-bright');
49
50 $context_style = array(
51 'background: #F7F7F7;',
52 'color: #74777D;',
53 'border-style: dashed;',
54 'border-color: #C7CCD9;',
55 'border-width: 1px 0;',
56 );
57
58 $context_style = implode(' ', $context_style);
59
60 foreach ($primitives as $k => $p) {
61 $type = $p['type'];
62 switch ($type) {
63 case 'old':
64 case 'new':
65 case 'old-file':
66 case 'new-file':
67 $is_old = ($type == 'old' || $type == 'old-file');
68
69 if ($is_old) {
70 if ($p['htype']) {
71 $style = "background: {$old_bright};";
72 } else {
73 $style = null;
74 }
75 } else {
76 if ($p['htype']) {
77 $style = "background: {$new_bright};";
78 } else {
79 $style = null;
80 }
81 }
82
83 $out[] = array(
84 'style' => $style,
85 'render' => $p['render'],
86 'text' => (string)$p['render'],
87 );
88 break;
89 case 'context':
90 // NOTE: These are being included with no text so they get stripped
91 // in the header and footer.
92 $out[] = array(
93 'style' => $context_style,
94 'render' => '...',
95 'text' => '',
96 );
97 break;
98 default:
99 break;
100 }
101 }
102
103 // Remove all leading and trailing empty lines, since these just look kind
104 // of weird in mail.
105 foreach ($out as $key => $line) {
106 if (!strlen(trim($line['text']))) {
107 unset($out[$key]);
108 } else {
109 break;
110 }
111 }
112
113 $keys = array_reverse(array_keys($out));
114 foreach ($keys as $key) {
115 $line = $out[$key];
116 if (!strlen(trim($line['text']))) {
117 unset($out[$key]);
118 } else {
119 break;
120 }
121 }
122
123 // If the user has commented on an empty line in the middle of a bunch of
124 // other empty lines, emit an explicit marker instead of just rendering
125 // nothing.
126 if (!$out) {
127 $out[] = array(
128 'style' => 'color: #888888;',
129 'render' => pht('(Empty.)'),
130 );
131 }
132
133 $render = array();
134 foreach ($out as $line) {
135 $style = $line['style'];
136 $style = "padding: 0 8px; margin: 0 4px; {$style}";
137
138 $render[] = phutil_tag(
139 'div',
140 array(
141 'style' => $style,
142 ),
143 $line['render']);
144 }
145
146 $style_map = id(new PhabricatorDefaultSyntaxStyle())
147 ->getRemarkupStyleMap();
148
149 $styled_body = id(new PhutilPygmentizeParser())
150 ->setMap($style_map)
151 ->parse((string)hsprintf('%s', $render));
152
153 return phutil_safe_html($styled_body);
154 }
155
156}