@@ -120,14 +120,17 @@ TActiveTextAttrNames = record
120120type
121121 // / <summary>Supported types of active text action elements.</summary>
122122 TActiveTextActionElemKind = (
123- ekLink, // link element: has a URL (inline)
124- ekStrong, // text formatted as strong (inline)
125- ekEm, // text formatted as emphasised (inline)
126- ekVar, // text formatted as variable (inline)
127- ekPara, // delimits a paragraph (block level)
128- ekWarning, // text formatted as a warning (inline)
129- ekHeading, // delimits a heading (block level)
130- ekMono // text formatted as mono spaced (inline)
123+ ekLink, // link element: has a URL (inline)
124+ ekStrong, // text formatted as strong (inline)
125+ ekEm, // text formatted as emphasised (inline)
126+ ekVar, // text formatted as variable (inline)
127+ ekPara, // delimits a paragraph (block level)
128+ ekWarning, // text formatted as a warning (inline)
129+ ekHeading, // delimits a heading (block level)
130+ ekMono, // text formatted as mono spaced (inline)
131+ ekUnorderedList, // container for unordered lists (block level)
132+ ekOrderedList, // container for ordered list (block level)
133+ ekListItem // list item (block level)
131134 );
132135
133136type
@@ -157,12 +160,6 @@ TActiveTextAttrNames = record
157160 function GetAttrs : IActiveTextAttrs;
158161 // / <summary>Object describing element's attributes.</summary>
159162 property Attrs: IActiveTextAttrs read GetAttrs;
160- // / <summary>Returns value that indicates whether element is an inline or
161- // / block element.</summary>
162- function GetDisplayStyle : TActiveTextDisplayStyle;
163- // / <summary>Indicates whether element displays inline or as a block.
164- // / </summary>
165- property DisplayStyle: TActiveTextDisplayStyle read GetDisplayStyle;
166163 end ;
167164
168165type
@@ -273,6 +270,162 @@ TActiveTextFactory = class(TNoConstructObject)
273270 IActiveTextAttrs; overload;
274271 end ;
275272
273+ type
274+ // / <summary>Provides information about the capabilities of each supported
275+ // / active text element.</summary>
276+ TActiveTextElemCaps = record
277+ strict private
278+ type
279+ // / <summary>Fields used to define an active text element's capabilities.
280+ // / </summary>
281+ TCaps = record
282+ public
283+ var
284+ // / <summary>Determines how element is to be displayed.</summary>
285+ DisplayStyle: TActiveTextDisplayStyle;
286+ // / <summary>Set of elements that may not occur inside the element.
287+ // / </summary>
288+ Exclusions: TActiveTextActionElemKinds;
289+ // / <summary>Set of elements that are permitted as parents of the
290+ // / element.</summary>
291+ // / <remarks>An empty set is taken to mean any element is permitted.
292+ // / </remarks>
293+ RequiredParents: TActiveTextActionElemKinds;
294+ // / <summary>Specifies whether plain text can be contained within the
295+ // / element.</summary>
296+ PermitsText: Boolean;
297+ end ;
298+ const
299+ // / <summary>Set of block level elements.</summary>
300+ BlockElems = [
301+ ekPara, ekHeading, ekUnorderedList, ekOrderedList, ekListItem
302+ ];
303+ // / <summary>Set of inline elements.</summary>
304+ InlineElems = [
305+ ekLink, ekStrong, ekEm, ekVar, ekWarning, ekMono
306+ ];
307+ // / <summary>Set of all elements.</summary>
308+ AllElems = BlockElems + InlineElems;
309+ // / <summary>Map of all elements to their capabilities.</summary>
310+ Map: array [TActiveTextActionElemKind] of TCaps =
311+ (
312+ (
313+ // ekLink
314+ // may contain any inline elements but no block elements
315+ DisplayStyle: dsInline;
316+ Exclusions: BlockElems;
317+ RequiredParents: [];
318+ PermitsText: True;
319+ ),
320+ (
321+ // ekStrong
322+ // may contain any inline elements but no block elements
323+ DisplayStyle: dsInline;
324+ Exclusions: BlockElems;
325+ RequiredParents: [];
326+ PermitsText: True;
327+ ),
328+ (
329+ // ekEm
330+ // may contain any inline elements but no block elements
331+ DisplayStyle: dsInline;
332+ Exclusions: BlockElems;
333+ RequiredParents: [];
334+ PermitsText: True;
335+ ),
336+ (
337+ // ekVar
338+ // may contain any inline elements but no block elements
339+ DisplayStyle: dsInline;
340+ Exclusions: BlockElems;
341+ RequiredParents: [];
342+ PermitsText: True;
343+ ),
344+ (
345+ // ekPara
346+ // may contain any inline elements but no block elements
347+ DisplayStyle: dsBlock;
348+ Exclusions: BlockElems;
349+ RequiredParents: [];
350+ PermitsText: True;
351+ ),
352+ (
353+ // ekWarning
354+ // may contain any inline elements but no block elements
355+ DisplayStyle: dsInline;
356+ Exclusions: BlockElems;
357+ RequiredParents: [];
358+ PermitsText: True;
359+ ),
360+ (
361+ // ekHeading
362+ // may contain any inline elements but no block elements
363+ DisplayStyle: dsBlock;
364+ Exclusions: BlockElems;
365+ RequiredParents: [];
366+ PermitsText: True;
367+ ),
368+ (
369+ // ekMono
370+ // may contain any inline elements but no block elements
371+ DisplayStyle: dsInline;
372+ Exclusions: BlockElems;
373+ RequiredParents: [];
374+ PermitsText: True;
375+ ),
376+ (
377+ // ekUnorderedList
378+ // may contain only list item elements
379+ DisplayStyle: dsBlock;
380+ Exclusions: AllElems - [ekListItem];
381+ RequiredParents: [];
382+ PermitsText: False
383+ ),
384+ (
385+ // ekOrderedList
386+ // may contain only list item elements
387+ DisplayStyle: dsBlock;
388+ Exclusions: AllElems - [ekListItem];
389+ RequiredParents: [];
390+ PermitsText: False;
391+ ),
392+ (
393+ // ekListItem
394+ // may contain any inline or block elements except another list
395+ // item
396+ DisplayStyle: dsBlock;
397+ Exclusions: [ekListItem];
398+ RequiredParents: [ekOrderedList, ekUnorderedList];
399+ PermitsText: True;
400+ )
401+ );
402+ public
403+ // / <summary>Returns the display type of the given element.</summary>
404+ class function DisplayStyleOf (const Elem: TActiveTextActionElemKind):
405+ TActiveTextDisplayStyle; static;
406+ // / <summary>Checks whether the given element can contain text.</summary>
407+ class function CanContainText (const Elem: TActiveTextActionElemKind):
408+ Boolean; static;
409+ // / <summary>Checks whether the given Parent element can contain the given
410+ // / Child element.</summary>
411+ class function CanContainElem (
412+ const Parent, Child: TActiveTextActionElemKind): Boolean; static;
413+ // / <summary>Checks whether the given Parent element is required as a
414+ // / parent of the given Child element.</summary>
415+ class function IsRequiredParent (
416+ const Parent, Child: TActiveTextActionElemKind): Boolean; static;
417+ // / <summary>Checks whether the given element is permitted in the root of
418+ // / an active text document, i.e. outside any other block level element.
419+ // / </summary>
420+ class function IsElemPermittedInRoot (const Elem: TActiveTextActionElemKind):
421+ Boolean; static;
422+ // / <summary>Checks whether the given child element is excluded from being
423+ // / a child of the given parent element.</summary>
424+ class function IsExcludedElem (
425+ const Parent, Child: TActiveTextActionElemKind): Boolean; static;
426+
427+ end ;
428+
276429
277430implementation
278431
@@ -354,7 +507,7 @@ TActiveTextTextElem = class(TInterfacedObject,
354507 fText: string;
355508 public
356509 // / <summary>Object constructor. Records given element text and sets
357- // / required kind for a text element.</summary>
510+ // / required Elem for a text element.</summary>
358511 constructor Create(const Text: string);
359512 // / <summary>Assigns properties of another object to this object.</summary>
360513 // / <param name="Src">IInterface [in] Object whose properties are to be
@@ -375,15 +528,15 @@ TActiveTextActionElem = class(TInterfacedObject,
375528 IActiveTextElem, IActiveTextActionElem, IAssignable, IClonable
376529 )
377530 strict private
378- // / <summary>Kind of element encapsulated by this object.</summary>
531+ // / <summary>Elem of element encapsulated by this object.</summary>
379532 fKind: TActiveTextActionElemKind;
380533 // / <summary>State of element: opening or closing.</summary>
381534 fState: TActiveTextElemState;
382535 // / <summary>Attributes associated with element.</summary>
383536 fAttrs: IActiveTextAttrs;
384537 public
385538 // / <summary>Object constructor. Creates an action element.</summary>
386- // / <param name="AKind">TActiveTextElemKind [in] Required kind of element.
539+ // / <param name="AKind">TActiveTextElemKind [in] Required Elem of element.
387540 // / </param>
388541 // / <param name="AAttrs">IActiveTextAttrs [in] Element's attributes.
389542 // / </param>
@@ -402,7 +555,7 @@ TActiveTextActionElem = class(TInterfacedObject,
402555 // / <summary>Returns a cloned instance of this object.</summary>
403556 // / <remarks>Method of IClonable.</remarks>
404557 function Clone : IInterface;
405- // / <summary>Returns kind of action represented by this element.</summary>
558+ // / <summary>Returns Elem of action represented by this element.</summary>
406559 // / <remarks>Method of IActiveTextActionElem.</remarks>
407560 function GetKind : TActiveTextActionElemKind;
408561 // / <summary>Returns state of element.</summary>
@@ -411,10 +564,6 @@ TActiveTextActionElem = class(TInterfacedObject,
411564 // / <summary>Returns object describing element's attributes.</summary>
412565 // / <remarks>Method of IActiveTextActionElem.</remarks>
413566 function GetAttrs : IActiveTextAttrs;
414- // / <summary>Returns value that indicates whether element is an inline or
415- // / block element.</summary>
416- // / <remarks>Method of IActiveTextActionElem.</remarks>
417- function GetDisplayStyle : TActiveTextDisplayStyle;
418567 end ;
419568
420569type
@@ -618,7 +767,7 @@ function TActiveText.ToString: string;
618767 if Supports(Elem, IActiveTextTextElem, TextElem) then
619768 SB.Append(TextElem.Text);
620769 if Supports(Elem, IActiveTextActionElem, ActionElem)
621- and (ActionElem.DisplayStyle = dsBlock)
770+ and (TActiveTextElemCaps.DisplayStyleOf( ActionElem.Kind) = dsBlock)
622771 and (ActionElem.State = fsClose) then
623772 // new line at end of block to separate text at end of closing block
624773 // from text at start of following block
@@ -689,14 +838,6 @@ function TActiveTextActionElem.GetAttrs: IActiveTextAttrs;
689838 Result := fAttrs;
690839end ;
691840
692- function TActiveTextActionElem.GetDisplayStyle : TActiveTextDisplayStyle;
693- begin
694- if GetKind in [ekPara, ekHeading] then
695- Result := dsBlock
696- else
697- Result := dsInline;
698- end ;
699-
700841function TActiveTextActionElem.GetKind : TActiveTextActionElemKind;
701842begin
702843 Result := fKind;
@@ -756,5 +897,45 @@ function TActiveTextAttrs.GetEnumerator: TEnumerator<TPair<string, string>>;
756897 Result := fMap.GetEnumerator;
757898end ;
758899
900+ { TActiveTextElemCapsMap }
901+
902+ class function TActiveTextElemCaps.CanContainElem (const Parent,
903+ Child: TActiveTextActionElemKind): Boolean;
904+ begin
905+ Result := not (Child in Map[Parent].Exclusions);
906+ end ;
907+
908+ class function TActiveTextElemCaps.CanContainText (
909+ const Elem: TActiveTextActionElemKind): Boolean;
910+ begin
911+ Result := Map[Elem].PermitsText;
912+ end ;
913+
914+ class function TActiveTextElemCaps.DisplayStyleOf (
915+ const Elem: TActiveTextActionElemKind): TActiveTextDisplayStyle;
916+ begin
917+ Result := Map[Elem].DisplayStyle;
918+ end ;
919+
920+ class function TActiveTextElemCaps.IsElemPermittedInRoot (
921+ const Elem: TActiveTextActionElemKind): Boolean;
922+ begin
923+ Result := Map[Elem].RequiredParents = [];
924+ end ;
925+
926+ class function TActiveTextElemCaps.IsExcludedElem (const Parent,
927+ Child: TActiveTextActionElemKind): Boolean;
928+ begin
929+ Result := Child in Map[Parent].Exclusions;
930+ end ;
931+
932+ class function TActiveTextElemCaps.IsRequiredParent (
933+ const Parent, Child: TActiveTextActionElemKind): Boolean;
934+ begin
935+ if Map[Child].RequiredParents = [] then
936+ Exit(True);
937+ Result := Parent in Map[Child].RequiredParents;
938+ end ;
939+
759940end .
760941
0 commit comments