@@ -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