@@ -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
8582implementation
8683
84+ uses
85+ UConsts, UIStringList, UStrUtils;
86+
8787
8888{ TActiveTextHTML }
8989
@@ -107,22 +107,6 @@ destructor TActiveTextHTML.Destroy;
107107 inherited;
108108end;
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-
126110procedure TActiveTextHTML.InitialiseTagInfoMap;
127111var
128112 NullAttrs: TTagInfo.TTagAttrCallback;
@@ -131,7 +115,10 @@ procedure TActiveTextHTML.InitialiseTagInfoMap;
131115 ElemKind: TActiveTextActionElemKind;
132116const
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 );
136123begin
137124 NullAttrs := function(Elem: IActiveTextActionElem): IHTMLAttributes
@@ -178,80 +165,100 @@ function TActiveTextHTML.MakeOpeningTag(const Elem: IActiveTextActionElem):
178165
179166function TActiveTextHTML.Render(ActiveText: IActiveText): string;
180167var
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;
184176begin
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);
202197end;
203198
204- procedure TActiveTextHTML.RenderBlockActionElem(Elem: IActiveTextActionElem);
199+ function TActiveTextHTML.RenderTag(const TagElem: IActiveTextActionElem):
200+ string;
205201begin
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;
234233end;
235234
236- procedure TActiveTextHTML.RenderTextElem(Elem: IActiveTextTextElem);
235+ function TActiveTextHTML.RenderText(const TextElem: IActiveTextTextElem):
236+ string;
237237begin
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);
241246end;
242247
243248{ TActiveTextHTML.TCSSStyles }
244249
245250constructor TActiveTextHTML.TCSSStyles.Create;
246251const
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 );
250258var
251259 ElemKind: TActiveTextActionElemKind;
252260begin
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