@@ -175,6 +175,16 @@ TActiveTextAttrNames = record
175175 // / <summary>Appends elements from another given active text object to the
176176 // / current object.</summary>
177177 procedure Append (const ActiveText: IActiveText);
178+ // / <summary>Returns a new IActiveText instance containing just the first
179+ // / block of the current object.</summary>
180+ // / <remarks>
181+ // / <para>The first block is the content of the block level tag that starts
182+ // / the active text. If this block has child blocks (for e.g. an unordered
183+ // / list) then they are included.</para>
184+ // / <para>If the current object is empty then an empty object is returned.
185+ // / </para>
186+ // / </remarks>
187+ function FirstBlock : IActiveText;
178188 // / <summary>Checks if the active text object contains any elements.
179189 // / </summary>
180190 function IsEmpty : Boolean;
@@ -474,6 +484,17 @@ TActiveText = class(TInterfacedObject,
474484 // / </summary>
475485 // / <remarks>Method of IActiveText.</remarks>
476486 procedure Append (const ActiveText: IActiveText);
487+ // / <summary>Returns a new IActiveText instance containing just the first
488+ // / block of the current object.</summary>
489+ // / <remarks>
490+ // / <para>The first block is the content of the block level tag that starts
491+ // / the active text. If this block has child blocks (for e.g. an unordered
492+ // / list) then they are included.</para>
493+ // / <para>If the current object is empty then an empty object is returned.
494+ // / </para>
495+ // / <para>Method of IActiveText.</para>
496+ // / </remarks>
497+ function FirstBlock : IActiveText;
477498 // / <summary>Checks if the element list is empty.</summary>
478499 // / <remarks>Method of IActiveText.</remarks>
479500 function IsEmpty : Boolean;
@@ -719,6 +740,67 @@ destructor TActiveText.Destroy;
719740 inherited ;
720741end ;
721742
743+ function TActiveText.FirstBlock : IActiveText;
744+
745+ function IsBlockWithState (Elem: IActiveTextElem; State: TActiveTextElemState):
746+ Boolean;
747+ var
748+ ActionElem: IActiveTextActionElem;
749+ begin
750+ Result := False;
751+ if not Supports(Elem, IActiveTextActionElem, ActionElem) then
752+ Exit;
753+ if TActiveTextElemCaps.DisplayStyleOf(ActionElem.Kind) <> dsBlock then
754+ Exit;
755+ if ActionElem.State <> State then
756+ Exit;
757+ Result := True;
758+ end ;
759+
760+ function IsBlockOpener (Elem: IActiveTextElem): Boolean; inline;
761+ begin
762+ Result := IsBlockWithState(Elem, fsOpen);
763+ end ;
764+
765+ function IsBlockCloser (Elem: IActiveTextElem): Boolean; inline;
766+ begin
767+ Result := IsBlockWithState(Elem, fsClose);
768+ end ;
769+
770+ var
771+ Depth: Cardinal;
772+ Elem: IActiveTextElem;
773+ Idx: Integer;
774+ begin
775+ Result := TActiveText.Create;
776+ if IsEmpty then
777+ Exit;
778+
779+ Elem := GetElem(0 );
780+
781+ if not IsBlockOpener(Elem) then
782+ begin
783+ Result.Append(Self);
784+ Exit;
785+ end ;
786+
787+ Depth := 1 ;
788+ Result.AddElem(Elem);
789+ for Idx := 1 to Pred(GetCount) do
790+ begin
791+ Elem := GetElem(Idx);
792+ Result.AddElem(Elem);
793+ // NOTE: we're not checking for matching openers and closers
794+ if IsBlockOpener(Elem) then
795+ Inc(Depth);
796+ if IsBlockCloser(Elem) then
797+ Dec(Depth);
798+ if Depth = 0 then
799+ Break;
800+ end ;
801+ // We're not checking for balancing block closer here either:
802+ end ;
803+
722804function TActiveText.GetCount : Integer;
723805begin
724806 Result := fElems.Count;
0 commit comments