Skip to content

Commit c7a6444

Browse files
committed
Merge branch 'feature/81+82-reml-lists-not-rendered-in-plain-text-or-rtf' into develop
Resolved conflicts: * Src/ActiveText.UHTMLRenderer.pas * Src/ActiveText.UMain.pas * Src/ActiveText.UTextRenderer.pas * Src/USourceGen.pas * Src/UTextSnippetDoc.pas All resolved in favour of the incoming changes from the feature branch. Fixes #81. Fixes #82.
2 parents c233195 + d0cb0dd commit c7a6444

19 files changed

+1321
-827
lines changed

Docs/Design/reml.html

+14-11
Original file line numberDiff line numberDiff line change
@@ -279,19 +279,19 @@ <h2>
279279
</p>
280280
<ul class="half-spaced">
281281
<li>
282-
<code class="value">&lt;p&gt;...&lt;/p&gt;</code> &ndash; Renders the enclosed markup as a simple paragraph.
282+
<code class="value">&lt;p&gt;...&lt;/p&gt;</code> &ndash; Renders the enclosed markup as a simple paragraph.
283283
</li>
284284
<li>
285285
<code class="value">&lt;heading&gt;...&lt;/heading&gt;</code> &ndash; Renders the enclosed markup as a heading.
286286
</li>
287287
<li>
288-
<code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> &ndash; Renders the enclosed HTML as an ordered list. <span class="very-strong">Must</span> contain <code class="value">&lt;li&gt;...&lt;/li&gt</code> blocks and nothing else.
288+
<code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> &ndash; Renders the enclosed markup as an ordered list.
289289
</li>
290290
<li>
291-
<code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> &ndash; Renders the enclosed HTML as an unordered list. <span class="very-strong">Must</span> contain <code class="value">&lt;li&gt;...&lt;/li&gt</code> blocks and nothing else.
291+
<code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> &ndash; Renders the enclosed markup as an unordered list.
292292
</li>
293293
<li>
294-
<code class="value">&lt;li&gt;...&lt;/li&gt;</code> &ndash; Renders the enclosed HTML as a list item. <span class="very-strong">Must</span> only be used within <code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> and <code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> blocks.
294+
<code class="value">&lt;li&gt;...&lt;/li&gt;</code> &ndash; Renders the enclosed markup as a list item.
295295
</li>
296296
</ul>
297297
<p>
@@ -308,7 +308,7 @@ <h2>
308308
<code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> and <code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> blocks <span class="very-strong">must only</span> contain one or more <code class="value">&lt;li&gt;...&lt;/li&gt;</code> blocks.
309309
</li>
310310
<li>
311-
<code class="value">&lt;li&gt;...&lt;/li&gt;</code> blocks <span class="very-strong">must not</span> contain <code class="value">&lt;p&gt;...&lt;/p&gt;</code>, <code class="value">&lt;heading&gt;...&lt;/heading&gt;</code> or other <code class="value">&lt;li&gt;...&lt;/li&gt;</code> blocks directly, but <em>may</em> contain <code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> and <code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> blocks.
311+
<code class="value">&lt;li&gt;...&lt;/li&gt;</code> blocks <span class="very-strong">must</span> only be used within <code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> and <code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> blocks. <em>May</em> contain <code class="value">&lt;p&gt;...&lt;/p&gt;</code> and <code class="value">&lt;heading&gt;...&lt;/heading&gt;</code> blocks, but it is permitted to include text and inline tags directly without enclosing them one of the permitted blocks. Nested lists are permitted by including further <code class="value">&lt;ul&gt;...&lt;/ul&gt;</code> and <code class="value">&lt;ol&gt;...&lt;/ol&gt;</code> blocks.
312312
</li>
313313
<li>
314314
All text <em>should</em> be embedded within <code class="value">&lt;p&gt;...&lt;/p&gt;</code>, <code class="value">&lt;heading&gt;...&lt;/heading&gt;</code> or <code class="value">&lt;li&gt;...&lt;/li&gt;</code> block level tags, e.g. <code class="value">&lt;heading&gt;heading&lt;/heading&gt;&lt;p&gt;text&lt;/p&gt;</code> or simply <code class="value">&lt;p&gt;text&lt;/p&gt;</code>.
@@ -320,20 +320,23 @@ <h2>
320320
<p>
321321
Here is a valid example:
322322
</p>
323-
<pre class="sample">&lt;p&gt;Hello World&lt;/p&gt;
324-
&lt;heading&gt;Hello&lt;/heading&gt;
323+
<pre class="sample">&lt;heading&gt;Hello&lt;/heading&gt;
325324
&lt;p&gt;Hello World&lt;/p&gt;
326325
&lt;ol&gt;
327326
&lt;li&gt;one&lt;/li&gt;
328-
&lt;li&gt;two&lt;/li&gt;
327+
&lt;li&gt;&lt;p&gt;two&lt;/p&gt;&lt;/li&gt;
328+
&lt;ul&gt;
329+
&lt;li&gt;two A&lt;/li&gt;
330+
&lt;li&gt;two B&lt;/li&gt;
331+
&lt;ul&gt;
329332
&lt;li&gt;three&lt;/li&gt;
330333
&lt;/ol&gt;</pre>
331334
<p>
332335
Strictly speaking, the following example is invalid code &ndash; all occurrences of <code class="value">wrong</code> are in error because they are not contained within block tags.
333336
</p>
334337
<pre class="sample">wrong &lt;heading&gt;blah&lt;/heading&gt; wrong &lt;p&gt;blah&lt;/p&gt; wrong</pre>
335338
<p>
336-
However interpreting code <em>may</em> interpret this permissively. If this is done the text outside blocks <span class="very-strong">must</span> be interpreted as if it was enclosed in <code class="value">&lt;p&gt;</code> and <code class="value">&lt;/p&gt;</code> tags. Therefore the above code would be interpreted as:
339+
However interpreting code <em>may</em> interpret this permissively. If this is done the text outside blocks <em>should</em> be interpreted as if it was enclosed in <code class="value">&lt;p&gt;</code> and <code class="value">&lt;/p&gt;</code> tags. Therefore the above code would be interpreted as:
337340
</p>
338341
<pre class="sample">&lt;p&gt;wrong &lt;/p&gt;&lt;heading&gt;blah&lt;/heading&gt;&lt;p&gt;wrong &lt;/p&gt;&lt;p&gt;blah&lt;/p&gt;&lt;p&gt;wrong&lt;/p&gt;</pre>
339342
<aside>
@@ -375,13 +378,13 @@ <h2>
375378
</p>
376379
<ul class="unspaced">
377380
<li>
378-
In-line tags <span class="very-strong">must</span> be embedded inside a block level tag. E.g. <code class="value">&lt;p&gt;one&lt;strong&gt;two&lt;/strong&gt;three&lt;/p&gt;</code>.
381+
In-line tags <span class="very-strong">must</span> be embedded inside a valid block level tag. E.g. <code class="value">&lt;p&gt;one&lt;strong&gt;two&lt;/strong&gt;three&lt;/p&gt;</code>.
379382
</li>
380383
<li>
381384
Tags <span class="very-strong">must</span> match. E.g. <code class="value">&lt;em&gt;</code> must be matched with <code class="value">&lt;/em&gt;</code>.
382385
</li>
383386
<li>
384-
Tags may be nested, providing the tags match. E.g. <code class="value">&lt;em&gt;blah &lt;var&gt;blah&lt;/var&gt;&lt;/em&gt;</code> is valid but <code class="value">&lt;em&gt;blah &lt;var&gt;blah&lt;/em&gt;&lt;/var&gt;</code> is not.
387+
Tags may be nested, providing the tags are balanced. E.g. <code class="value">&lt;em&gt;blah &lt;var&gt;blah&lt;/var&gt;&lt;/em&gt;</code> is valid but <code class="value">&lt;em&gt;blah &lt;var&gt;blah&lt;/em&gt;&lt;/var&gt;</code> is not.
385388
</li>
386389
</ul>
387390
<p>

Src/ActiveText.UHTMLRenderer.pas

+79-72
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,43 @@ TTagInfo = class(TObject)
4747
TCSSStyles = class(TObject)
4848
strict private
4949
var
50-
fWrapperClass: string;
5150
fElemClassMap: array[TActiveTextActionElemKind] of string;
5251
procedure SetElemClass(ElemKind: TActiveTextActionElemKind;
5352
const Value: string); inline;
5453
function GetElemClass(ElemKind: TActiveTextActionElemKind): string;
5554
inline;
5655
public
5756
constructor Create;
58-
property WrapperClass: string read fWrapperClass write fWrapperClass;
5957
property ElemClasses[Kind: TActiveTextActionElemKind]: string
6058
read GetElemClass write SetElemClass;
6159
end;
6260
strict private
6361
var
6462
fCSSStyles: TCSSStyles;
6563
fBuilder: TStringBuilder;
66-
fInBlock: Boolean;
64+
fLevel: Integer;
6765
fTagInfoMap: TTagInfoMap;
66+
fIsStartOfTextLine: Boolean;
6867
fLINestingDepth: Cardinal;
68+
const
69+
IndentMult = 2;
6970
procedure InitialiseTagInfoMap;
70-
procedure InitialiseRender;
71-
procedure RenderTextElem(Elem: IActiveTextTextElem);
72-
procedure RenderBlockActionElem(Elem: IActiveTextActionElem);
73-
procedure RenderInlineActionElem(Elem: IActiveTextActionElem);
74-
procedure FinaliseRender;
71+
function RenderTag(const TagElem: IActiveTextActionElem): string;
72+
function RenderText(const TextElem: IActiveTextTextElem): string;
7573
function MakeOpeningTag(const Elem: IActiveTextActionElem): string;
7674
function MakeClosingTag(const Elem: IActiveTextActionElem): string;
7775
public
7876
constructor Create;
7977
destructor Destroy; override;
8078
function Render(ActiveText: IActiveText): string;
81-
property Styles: TCSSStyles read fCSSStyles;
8279
end;
8380

8481

8582
implementation
8683

84+
uses
85+
UConsts, UIStringList, UStrUtils;
86+
8787

8888
{ TActiveTextHTML }
8989

@@ -107,22 +107,6 @@ destructor TActiveTextHTML.Destroy;
107107
inherited;
108108
end;
109109

110-
procedure TActiveTextHTML.FinaliseRender;
111-
begin
112-
fBuilder.AppendLine(THTML.ClosingTag('div'));
113-
end;
114-
115-
procedure TActiveTextHTML.InitialiseRender;
116-
var
117-
WrapperClassAttr: IHTMLAttributes;
118-
begin
119-
if fCSSStyles.WrapperClass <> '' then
120-
WrapperClassAttr := THTMLAttributes.Create('class', fCSSStyles.WrapperClass)
121-
else
122-
WrapperClassAttr := nil;
123-
fBuilder.AppendLine(THTML.OpeningTag('div', WrapperClassAttr));
124-
end;
125-
126110
procedure TActiveTextHTML.InitialiseTagInfoMap;
127111
var
128112
NullAttrs: TTagInfo.TTagAttrCallback;
@@ -131,7 +115,10 @@ procedure TActiveTextHTML.InitialiseTagInfoMap;
131115
ElemKind: TActiveTextActionElemKind;
132116
const
133117
Tags: array[TActiveTextActionElemKind] of string = (
134-
'a', 'strong', 'em', 'var', 'p', 'span', 'h2', 'code', 'ul', 'ol', 'li'
118+
'a' {ekLink}, 'strong' {ekStrong}, 'em' {ekEm}, 'var' {ekVar}, 'p' {ekPara},
119+
'span' {ekWarning}, 'h2' {ekHeading}, 'code' {ekMono},
120+
'ul' {ekUnorderedList}, 'ol' {ekUnorderedList}, 'li' {ekListItem},
121+
'div' {ekBlock}, 'div' {ekDocument}
135122
);
136123
begin
137124
NullAttrs := function(Elem: IActiveTextActionElem): IHTMLAttributes
@@ -178,80 +165,100 @@ function TActiveTextHTML.MakeOpeningTag(const Elem: IActiveTextActionElem):
178165

179166
function TActiveTextHTML.Render(ActiveText: IActiveText): string;
180167
var
181-
Elem: IActiveTextElem;
182-
TextElem: IActiveTextTextElem;
183-
ActionElem: IActiveTextActionElem;
168+
Elem: IActiveTextElem; // each element in active text object
169+
TextElem: IActiveTextTextElem; // an active text text element
170+
TagElem: IActiveTextActionElem; // an active text action element
171+
Text: string;
172+
SrcLines: IStringList;
173+
SrcLine: string;
174+
DestLines: IStringList;
175+
DestLine: string;
184176
begin
185-
fBuilder.Clear;
186-
fInBlock := False;
187-
InitialiseRender;
177+
if ActiveText.IsEmpty then
178+
Exit('');
179+
Text := '';
180+
fLevel := 0;
188181
for Elem in ActiveText do
189182
begin
190183
if Supports(Elem, IActiveTextTextElem, TextElem) then
191-
RenderTextElem(TextElem)
192-
else if Supports(Elem, IActiveTextActionElem, ActionElem) then
193-
begin
194-
if TActiveTextElemCaps.DisplayStyleOf(ActionElem.Kind) = dsBlock then
195-
RenderBlockActionElem(ActionElem)
196-
else
197-
RenderInlineActionElem(ActionElem);
198-
end;
184+
Text := Text + RenderText(TextElem)
185+
else if Supports(Elem, IActiveTextActionElem, TagElem) then
186+
Text := Text + RenderTag(TagElem);
199187
end;
200-
FinaliseRender;
201-
Result := fBuilder.ToString;
188+
SrcLines := TIStringList.Create(Text, EOL, False);
189+
DestLines := TIStringList.Create;
190+
for SrcLine in SrcLines do
191+
begin
192+
DestLine := StrTrimRight(SrcLine);
193+
if not StrIsEmpty(DestLine) then
194+
DestLines.Add(DestLine);
195+
end;
196+
Result := DestLines.GetText(EOL, False);
202197
end;
203198

204-
procedure TActiveTextHTML.RenderBlockActionElem(Elem: IActiveTextActionElem);
199+
function TActiveTextHTML.RenderTag(const TagElem: IActiveTextActionElem):
200+
string;
205201
begin
206-
case Elem.State of
207-
fsOpen:
208-
begin
209-
if Elem.Kind = ekListItem then
210-
Inc(fLINestingDepth);
211-
fBuilder.Append(MakeOpeningTag(Elem));
212-
fInBlock := True;
213-
end;
202+
Result := '';
203+
case TagElem.State of
214204
fsClose:
215205
begin
216-
fInBlock := False;
217-
fBuilder.AppendLine(MakeClosingTag(Elem));
218-
if Elem.Kind = ekListItem then
219-
Dec(fLINestingDepth);
206+
Result := MakeClosingTag(TagElem);
207+
if TActiveTextElemCaps.DisplayStyleOf(TagElem.Kind) = dsBlock then
208+
begin
209+
Dec(fLevel);
210+
Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
211+
fIsStartOfTextLine := True;
212+
end;
220213
end;
221-
end;
222-
end;
223-
224-
procedure TActiveTextHTML.RenderInlineActionElem(Elem: IActiveTextActionElem);
225-
begin
226-
if not fInBlock and (fLINestingDepth = 0) then
227-
Exit;
228-
case Elem.State of
229214
fsOpen:
230-
fBuilder.Append(MakeOpeningTag(Elem));
231-
fsClose:
232-
fBuilder.Append(MakeClosingTag(Elem));
215+
begin
216+
Result := MakeOpeningTag(TagElem);
217+
if TActiveTextElemCaps.DisplayStyleOf(TagElem.Kind) = dsBlock then
218+
begin
219+
Result := EOL + StrOfSpaces(IndentMult * fLevel) + Result + EOL;
220+
Inc(fLevel);
221+
fIsStartOfTextLine := True;
222+
end
223+
else if TActiveTextElemCaps.DisplayStyleOf(TagElem.Kind) = dsInline then
224+
begin
225+
if fIsStartOfTextLine then
226+
begin
227+
Result := StrOfSpaces(IndentMult * fLevel) + Result;
228+
fIsStartOfTextLine := False;
229+
end;
230+
end;
231+
end;
233232
end;
234233
end;
235234

236-
procedure TActiveTextHTML.RenderTextElem(Elem: IActiveTextTextElem);
235+
function TActiveTextHTML.RenderText(const TextElem: IActiveTextTextElem):
236+
string;
237237
begin
238-
if not fInBlock and (fLINestingDepth = 0) then
239-
Exit;
240-
fBuilder.Append(THTML.Entities(Elem.Text));
238+
if fIsStartOfTextLine then
239+
begin
240+
Result := StrOfSpaces(IndentMult * fLevel);
241+
fIsStartOfTextLine := False;
242+
end
243+
else
244+
Result := '';
245+
Result := Result + THTML.Entities(TextElem.Text);
241246
end;
242247

243248
{ TActiveTextHTML.TCSSStyles }
244249

245250
constructor TActiveTextHTML.TCSSStyles.Create;
246251
const
247252
DefaultClasses: array[TActiveTextActionElemKind] of string = (
248-
'external-link', '', '', '', '', 'warning', '', '', '', '', ''
253+
'external-link' {ekLink}, '' {ekStrong}, '' {ekEm}, '' {ekVar}, '' {ekPara},
254+
'warning' {ekWarning}, '' {ekHeading}, '' {ekMono}, '' {ekUnorderedList},
255+
'' {ekOrderedList}, '' {ekListItem}, '' {ekBlock},
256+
'active-text' {ekDocument}
249257
);
250258
var
251259
ElemKind: TActiveTextActionElemKind;
252260
begin
253261
inherited Create;
254-
fWrapperClass := 'active-text';
255262
for ElemKind := Low(TActiveTextActionElemKind)
256263
to High(TActiveTextActionElemKind) do
257264
SetElemClass(ElemKind, DefaultClasses[ElemKind]);

0 commit comments

Comments
 (0)