|
@@ -322,6 +322,7 @@ type
|
|
|
private
|
|
|
FCSSResolver: TCSSResolver;
|
|
|
FStyle: TCSSString;
|
|
|
+ procedure OnResolverLog(Sender: TObject; Entry: TCSSResolverLogEntry);
|
|
|
protected
|
|
|
procedure ApplyTypeStyles; virtual;
|
|
|
procedure SetStyle(const AValue: TCSSString); virtual;
|
|
@@ -344,6 +345,8 @@ type
|
|
|
protected
|
|
|
procedure SetUp; override;
|
|
|
procedure TearDown; override;
|
|
|
+ procedure ApplyStyle; virtual;
|
|
|
+ procedure CheckWarnings; virtual;
|
|
|
public
|
|
|
property Doc: TDemoDocument read FDoc;
|
|
|
end;
|
|
@@ -421,6 +424,8 @@ type
|
|
|
procedure Test_Origin_Id_Class;
|
|
|
|
|
|
// var()
|
|
|
+ procedure Test_Var;
|
|
|
+ // todo: Test_Var_Inline; // var() in inline, custom attr in inline
|
|
|
|
|
|
// skipping for forward compatibility
|
|
|
// ToDo: invalid token in selector makes selector invalid
|
|
@@ -459,2121 +464,2180 @@ begin
|
|
|
Result:=s;
|
|
|
end;
|
|
|
|
|
|
-{ TCustomTestNewCSSResolver }
|
|
|
+{ TDemoDiv }
|
|
|
|
|
|
-procedure TCustomTestNewCSSResolver.SetUp;
|
|
|
-var
|
|
|
- AttrDesc: TCSSAttributeDesc;
|
|
|
+class function TDemoDiv.CSSTypeName: TCSSString;
|
|
|
begin
|
|
|
- inherited SetUp;
|
|
|
-
|
|
|
- TDemoNode.CSSRegistry:=TDemoCSSRegistry.Create();
|
|
|
+ Result:=DemoElementTypeNames[detDiv];
|
|
|
+end;
|
|
|
|
|
|
- // register button attribute 'caption'
|
|
|
- AttrDesc:=TDemoNode.CSSRegistry.AddAttribute('caption');
|
|
|
- TDemoButton.CSSCaptionID:=AttrDesc.Index;
|
|
|
+class function TDemoDiv.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
+begin
|
|
|
+ Result:=FDemoDivTypeID;
|
|
|
+end;
|
|
|
|
|
|
- FDoc:=TDemoDocument.Create(nil);
|
|
|
+class procedure TDemoDiv.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
+begin
|
|
|
+ FDemoDivTypeID:=aID;
|
|
|
end;
|
|
|
|
|
|
-procedure TCustomTestNewCSSResolver.TearDown;
|
|
|
+class function TDemoDiv.GetCSSTypeStyle: TCSSString;
|
|
|
begin
|
|
|
- FreeAndNil(FDoc);
|
|
|
- FreeAndNil(TDemoNode.CSSRegistry);
|
|
|
- inherited TearDown;
|
|
|
+ Result:='div{ display: block }';
|
|
|
end;
|
|
|
|
|
|
-{ TTestNewCSSResolver }
|
|
|
+{ TDemoSpan }
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_ParseAttr_Keyword;
|
|
|
+class function TDemoSpan.CSSTypeName: TCSSString;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Style:='* { direction: ltr; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.direction','ltr',Doc.Root.Direction);
|
|
|
+ Result:=DemoElementTypeNames[detSpan];
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_ParseAttr_Keyword_SkipInvalid;
|
|
|
+class function TDemoSpan.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Style:='* { direction: something ltr; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.direction','ltr',Doc.Root.Direction);
|
|
|
+ Result:=FDemoSpanTypeID;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_ParseAttr_Float;
|
|
|
-var
|
|
|
- Div1: TDemoDiv;
|
|
|
+class procedure TDemoSpan.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Style:=
|
|
|
- ':root {'
|
|
|
- +' left: 10px;'
|
|
|
- +' top: .1px;'
|
|
|
- +' width: 3e2em;'
|
|
|
- +' height: 3e-2px;'
|
|
|
- +'}'
|
|
|
- +'div {'
|
|
|
- +' left: -4mm;'
|
|
|
- +' top: -.5pc;'
|
|
|
- +' width: .6cm;'
|
|
|
- +' height: 6E+1rem;'
|
|
|
- +'}';
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','10px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','0.1px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','300em',Doc.Root.Width);
|
|
|
- AssertEquals('Root.Height','0.03px',Doc.Root.Height);
|
|
|
- AssertEquals('Div1.Left','-4mm',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','-0.5pc',Div1.Top);
|
|
|
- AssertEquals('Div1.Width','0.6cm',Div1.Width);
|
|
|
- AssertEquals('Div1.Height','60rem',Div1.Height);
|
|
|
+ FDemoSpanTypeID:=aID;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_ParseAttr_Float_SkipInvalid;
|
|
|
+class function TDemoSpan.GetCSSTypeStyle: TCSSString;
|
|
|
begin
|
|
|
- exit;
|
|
|
+ Result:='span{display: inline-block }';
|
|
|
+end;
|
|
|
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Style:=
|
|
|
- ':root {'
|
|
|
- +' left: something 10px;'
|
|
|
- +' top: 1 px;' // no space between number
|
|
|
- +' width: 0 px;' // the px is ignored because of the space, 0 without unit is allowed
|
|
|
- +' height: -4cm;' // no negative
|
|
|
- +'}';
|
|
|
+{ TDemoButton }
|
|
|
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','10px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','invalid',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','0',Doc.Root.Width);
|
|
|
- AssertEquals('Root.Height','invalid',Doc.Root.Height);
|
|
|
+procedure TDemoButton.SetCaption(const AValue: TCSSString);
|
|
|
+begin
|
|
|
+ if FCaption=AValue then Exit;
|
|
|
+ FCaption:=AValue;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Universal;
|
|
|
+class function TDemoButton.CSSTypeName: TCSSString;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Style:='* { left: 10px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','10px',Doc.Root.Left);
|
|
|
+ Result:=DemoElementTypeNames[detButton];
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Type;
|
|
|
-var
|
|
|
- Button: TDemoButton;
|
|
|
+class function TDemoButton.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Button:=TDemoButton.Create(nil);
|
|
|
- Button.Parent:=Doc.Root;
|
|
|
- Doc.Style:='button { left: 11px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button.left','11px',Button.Left);
|
|
|
+ Result:=FDemoButtonTypeID;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Type_Spaces;
|
|
|
-var
|
|
|
- Button1, Button2: TDemoButton;
|
|
|
+class procedure TDemoButton.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.Style:='div, button ,span { left: 11px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','11px',Button1.Left);
|
|
|
- AssertEquals('Button2.left','11px',Button2.Left);
|
|
|
+ FDemoButtonTypeID:=aID;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Id;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+class function TDemoButton.GetCSSTypeStyle: TCSSString;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Doc.Style:='#Button1 { left: 12px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','12px',Button1.Left);
|
|
|
+ Result:='button{display: inline-block }';
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Class;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+function TDemoButton.HasCSSExplicitAttribute(const AttrID: TCSSNumericalID
|
|
|
+ ): boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.CSSClasses.Add('west');
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Doc.Style:='.west { left: 13px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','13px',Button1.Left);
|
|
|
+ //writeln('TDemoButton.HasCSSExplicitAttribute ',AttrID,' CSSCaptionID=',CSSCaptionID);
|
|
|
+ if AttrID=CSSCaptionID then
|
|
|
+ Result:=ExplicitCaption<>''
|
|
|
+ else
|
|
|
+ Result:=inherited HasCSSExplicitAttribute(AttrID);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_ClassClass;
|
|
|
-var
|
|
|
- Button1, Button2: TDemoButton;
|
|
|
+function TDemoButton.GetCSSExplicitAttribute(const AttrID: TCSSNumericalID
|
|
|
+ ): TCSSString;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.CSSClasses.Add('west');
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
+ if AttrID=CSSCaptionID then
|
|
|
+ Result:=ExplicitCaption
|
|
|
+ else
|
|
|
+ Result:=inherited GetCSSExplicitAttribute(AttrID);
|
|
|
+end;
|
|
|
|
|
|
- Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.CSSClasses.DelimitedText:='west south';
|
|
|
- AssertEquals('Button2.CSSClasses.Count',2,Button2.CSSClasses.Count);
|
|
|
- Button2.Parent:=Doc.Root;
|
|
|
+{ TDemoDocument }
|
|
|
|
|
|
- Doc.Style:='.west.south { left: 10px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','',Button1.Left);
|
|
|
- AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
+procedure TDemoDocument.SetStyle(const AValue: TCSSString);
|
|
|
+begin
|
|
|
+ if FStyle=AValue then Exit;
|
|
|
+ FStyle:=AValue;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_ClassSpaceClass;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+constructor TDemoDocument.Create(AOwner: TComponent);
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.CSSClasses.Add('bird');
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.CSSClasses.Add('west');
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
+ inherited Create(AOwner);
|
|
|
|
|
|
- Doc.Style:='.bird .west { left: 10px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','10px',Button1.Left);
|
|
|
+ // create the css resolver
|
|
|
+ FCSSResolver:=TCSSResolver.Create(nil);
|
|
|
+ FCSSResolver.CSSRegistry:=TDemoNode.CSSRegistry;
|
|
|
+ FCSSResolver.OnLog:=@OnResolverLog;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_TypeCommaType;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
- Div1: TDemoDiv;
|
|
|
+destructor TDemoDocument.Destroy;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ FreeAndNil(Root);
|
|
|
+ FreeAndNil(FCSSResolver);
|
|
|
+ inherited Destroy;
|
|
|
+end;
|
|
|
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
+procedure TDemoDocument.ApplyStyle;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+ procedure Traverse(Node: TDemoNode);
|
|
|
+ var
|
|
|
+ i: Integer;
|
|
|
+ begin
|
|
|
+ Node.ApplyCSS(CSSResolver);
|
|
|
+ for i:=0 to Node.NodeCount-1 do
|
|
|
+ Traverse(Node[i]);
|
|
|
+ end;
|
|
|
|
|
|
- Doc.Style:='div, button { left: 10px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','10px',Button1.Left);
|
|
|
- AssertEquals('Div1.left','10px',Div1.Left);
|
|
|
+begin
|
|
|
+ ApplyTypeStyles;
|
|
|
+
|
|
|
+ CSSResolver.AddStyleSheet(cssoAuthor,'test.css',Style);
|
|
|
+ CSSResolver.Init;
|
|
|
+ Traverse(Root);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_ClassGTClass;
|
|
|
-var
|
|
|
- Div1, Div2: TDemoDiv;
|
|
|
+procedure TDemoDocument.OnResolverLog(Sender: TObject; Entry: TCSSResolverLogEntry);
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
- Doc.Root.CSSClasses.Add('lvl1');
|
|
|
+ if Sender=nil then ;
|
|
|
+ if Entry=nil then ;
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.CSSClasses.Add('lvl2');
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.CSSClasses.Add('lvl3');
|
|
|
- Div2.Parent:=Div1;
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '.lvl1>.lvl2 { left: 10px; }', // set
|
|
|
- '.lvl1>.lvl3 { top: 11px; }', // not set, not direct children
|
|
|
- '.lvl2>.lvl3 { width: 12px; }', // set
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Root.top','',Doc.Root.Top);
|
|
|
- AssertEquals('Root.width','',Doc.Root.Width);
|
|
|
- AssertEquals('Div1.left','10px',Div1.Left);
|
|
|
- AssertEquals('Div1.top','',Div1.Top);
|
|
|
- AssertEquals('Div1.width','',Div1.Width);
|
|
|
- AssertEquals('Div2.left','',Div2.Left);
|
|
|
- AssertEquals('Div2.top','',Div2.Top);
|
|
|
- AssertEquals('Div2.width','12px',Div2.Width);
|
|
|
-end;
|
|
|
-
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_TypePlusType;
|
|
|
+procedure TDemoDocument.ApplyTypeStyles;
|
|
|
var
|
|
|
- Button1, Button2, Button3: TDemoButton;
|
|
|
- Div1: TDemoDiv;
|
|
|
-begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
+ FoundStyles: array of TDemoNodeClass;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+ procedure AddTypeStyle(NodeClass: TDemoNodeClass);
|
|
|
+ var
|
|
|
+ i: Integer;
|
|
|
+ Src, ParentSrc: TCSSString;
|
|
|
+ ParentNodeClass: TDemoNodeClass;
|
|
|
+ begin
|
|
|
+ for i:=0 to length(FoundStyles)-1 do
|
|
|
+ if FoundStyles[i]=NodeClass then exit;
|
|
|
+ Insert(NodeClass,FoundStyles,length(FoundStyles));
|
|
|
|
|
|
- Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.Name:='Button2';
|
|
|
- Button2.Parent:=Doc.Root;
|
|
|
+ Src:=NodeClass.GetCSSTypeStyle;
|
|
|
+ //writeln('AddTypeStyle ',NodeClass.ClassName,' Src="',Src,'"');
|
|
|
+ if Src='' then exit;
|
|
|
+ if NodeClass.ClassType<>TDemoNode then
|
|
|
+ begin
|
|
|
+ ParentNodeClass:=TDemoNodeClass(NodeClass.ClassParent);
|
|
|
+ AddTypeStyle(ParentNodeClass);
|
|
|
+ ParentSrc:=ParentNodeClass.GetCSSTypeStyle;
|
|
|
+ if Src=ParentSrc then exit;
|
|
|
+ end;
|
|
|
+ //writeln('AddTypeStyle ',NodeClass.ClassName,' [',Src,']');
|
|
|
+ FCSSResolver.AddStyleSheet(cssoUserAgent,NodeClass.ClassName,Src);
|
|
|
+ end;
|
|
|
|
|
|
- Button3:=TDemoButton.Create(nil);
|
|
|
- Button3.Name:='Button3';
|
|
|
- Button3.Parent:=Doc.Root;
|
|
|
+ procedure CollectTypeStyles(Node: TDemoNode);
|
|
|
+ var
|
|
|
+ NodeClass: TDemoNodeClass;
|
|
|
+ i: Integer;
|
|
|
+ begin
|
|
|
+ NodeClass:=TDemoNodeClass(Node.ClassType);
|
|
|
+ AddTypeStyle(NodeClass);
|
|
|
+ for i:=0 to Node.NodeCount-1 do
|
|
|
+ CollectTypeStyles(Node[i]);
|
|
|
+ end;
|
|
|
|
|
|
- Doc.Style:='div+button { left: 10px; }'; // only Button2 has a prev sibling div
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','',Button1.Left);
|
|
|
- AssertEquals('Div1.left','',Div1.Left);
|
|
|
- AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
- AssertEquals('Button3.left','',Button3.Left);
|
|
|
+begin
|
|
|
+ FoundStyles:=[];
|
|
|
+ CollectTypeStyles(Root);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_TypeTildeType;
|
|
|
+{ TDemoCSSRegistry }
|
|
|
+
|
|
|
+function TDemoCSSRegistry.OnCheck_Border(Resolver: TCSSBaseResolver): boolean;
|
|
|
var
|
|
|
- Button1, Button2, Button3: TDemoButton;
|
|
|
- Div1: TDemoDiv;
|
|
|
+ HasWidth, HasColor: Boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Button3:=TDemoButton.Create(nil);
|
|
|
- Button3.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.Style:='div~button { left: 10px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
- AssertEquals('Button1.left','',Button1.Left);
|
|
|
- AssertEquals('Div1.left','',Div1.Left);
|
|
|
- AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
- AssertEquals('Button3.left','10px',Button3.Left);
|
|
|
+ HasWidth:=false;
|
|
|
+ HasColor:=false;
|
|
|
+ repeat
|
|
|
+ case Resolver.CurComp.Kind of
|
|
|
+ rvkFloat:
|
|
|
+ if not HasWidth then
|
|
|
+ HasWidth:=Resolver.CurComp.FloatUnit in ([cuNONE,cuPERCENT]+cuAllLengths);
|
|
|
+ rvkKeyword:
|
|
|
+ if not HasColor then
|
|
|
+ HasColor:=(Resolver.CurComp.KeywordID>=kwFirstColor) and (Resolver.CurComp.KeywordID<=kwLastColor);
|
|
|
+ end;
|
|
|
+ until not Resolver.ReadNext;
|
|
|
+ Result:=HasWidth or HasColor;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_HasAttribute;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+function TDemoCSSRegistry.OnCheck_BorderColor(Resolver: TCSSBaseResolver): boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='100px';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='2px';
|
|
|
- Button1.ExplicitCaption:='Click Button1';
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left] { top: 3px; }',
|
|
|
- '[caption] { width: 4px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','3px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Button1.Top','3px',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','4px',Button1.Width);
|
|
|
+ Result:=Resolver.CheckAttribute_Color([]);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeEquals;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+function TDemoCSSRegistry.OnCheck_BorderWidth(Resolver: TCSSBaseResolver): boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='2px';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='3px';
|
|
|
- Button1.ExplicitAttributes[naColor]:='maybe black';
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left=2px] { top: 4px; }',
|
|
|
- '[color="maybe black"] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Button1.Top','',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
+ Result:=Resolver.CheckAttribute_Dimension(Chk_BorderWidth);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeEqualsI;
|
|
|
+procedure TDemoCSSRegistry.OnSplit_Border(Resolver: TCSSBaseResolver;
|
|
|
+ var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
|
|
|
var
|
|
|
- Button1: TDemoButton;
|
|
|
+ aWidth, aColor: TCSSString;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='2px';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='3px';
|
|
|
- Button1.ExplicitAttributes[naColor]:='maybe Black';
|
|
|
+ aWidth:='';
|
|
|
+ aColor:='';
|
|
|
+ repeat
|
|
|
+ case Resolver.CurComp.Kind of
|
|
|
+ rvkFloat:
|
|
|
+ if aWidth='' then begin
|
|
|
+ if Resolver.CurComp.FloatUnit in ([cuNONE,cuPERCENT]+cuAllLengths) then
|
|
|
+ aWidth:=Resolver.CurComp.FloatAsString;
|
|
|
+ end;
|
|
|
+ rvkKeyword:
|
|
|
+ if aColor='' then
|
|
|
+ begin
|
|
|
+ if (Resolver.CurComp.KeywordID>=kwFirstColor) and (Resolver.CurComp.KeywordID<=kwLastColor) then
|
|
|
+ aColor:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ until not Resolver.ReadNext;
|
|
|
+ SetLength(AttrIDs,2);
|
|
|
+ SetLength(Values,2);
|
|
|
+ AttrIDs[0]:=DemoAttrs[naBorderWidth].Index;
|
|
|
+ Values[0]:=aWidth;
|
|
|
+ AttrIDs[1]:=DemoAttrs[naBorderColor].Index;
|
|
|
+ Values[1]:=aColor;
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left="2Px" i] { top: 4px; }',
|
|
|
- '[color="Maybe bLack" i] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Button1.Top','',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
+function TDemoCSSRegistry.OnCheck_Direction(Resolver: TCSSBaseResolver): boolean;
|
|
|
+begin
|
|
|
+ Result:=Resolver.CheckAttribute_Keyword(Chk_DirectionAllowedKeywordIDs);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeBeginsWith;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
+function TDemoCSSRegistry.OnCheck_Display(Resolver: TCSSBaseResolver): boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
+ Result:=Resolver.CheckAttribute_Keyword(Chk_DisplayAllowedKeywordIDs);
|
|
|
+end;
|
|
|
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
+function TDemoCSSRegistry.OnCheck_LeftTop(Resolver: TCSSBaseResolver): boolean;
|
|
|
+begin
|
|
|
+ Result:=Resolver.CheckAttribute_Dimension(Chk_LeftTop);
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left^=Fo] { top: 4px; }',
|
|
|
- '[left^="Foo B"] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
+function TDemoCSSRegistry.OnCheck_WidthHeight(Resolver: TCSSBaseResolver): boolean;
|
|
|
+begin
|
|
|
+ Result:=Resolver.CheckAttribute_Dimension(Chk_WidthHeight);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeEndsWith;
|
|
|
+procedure TDemoCSSRegistry.OnCompute_Direction(Resolver: TCSSResolver;
|
|
|
+ Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
var
|
|
|
- Button1: TDemoButton;
|
|
|
+ Invalid: boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left$=o] { top: 4px; }',
|
|
|
- '[left$="o Bar"] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Button1.Top','',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
+ if Resolver.ReadAttribute_Keyword(Invalid,Chk_DirectionAllowedKeywordIDs) then
|
|
|
+ begin
|
|
|
+ Value.Value:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
+ Value.State:=cavsComputed;
|
|
|
+ end
|
|
|
+ else begin
|
|
|
+ Value.Value:='invalid';
|
|
|
+ Value.State:=cavsInvalid;
|
|
|
+ end;
|
|
|
+ if Node=nil then ;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeBeginsWithHyphen;
|
|
|
+procedure TDemoCSSRegistry.OnCompute_LeftTop(Resolver: TCSSResolver;
|
|
|
+ Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
var
|
|
|
- Button1: TDemoButton;
|
|
|
+ Invalid: boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='Foo-Bar';
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left|=Foo] { top: 4px; }',
|
|
|
- '[left|="Fo"] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','',Button1.Width);
|
|
|
+ if Resolver.ReadAttribute_Dimension(Invalid,Chk_LeftTop) then
|
|
|
+ begin
|
|
|
+ case Resolver.CurComp.Kind of
|
|
|
+ rvkFloat:
|
|
|
+ Value.Value:=Resolver.CurComp.FloatAsString;
|
|
|
+ rvkKeyword:
|
|
|
+ Value.Value:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
+ end;
|
|
|
+ Value.State:=cavsComputed;
|
|
|
+ end
|
|
|
+ else begin
|
|
|
+ Value.Value:='invalid';
|
|
|
+ Value.State:=cavsInvalid;
|
|
|
+ end;
|
|
|
+ if Node=nil then ;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeContainsWord;
|
|
|
+procedure TDemoCSSRegistry.OnCompute_WidthHeight(Resolver: TCSSResolver;
|
|
|
+ Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
var
|
|
|
- Button1: TDemoButton;
|
|
|
+ Invalid: boolean;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='One Two Three';
|
|
|
-
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='Four Five';
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left~=One] { top: 4px; }',
|
|
|
- '[left~=Two] { width: 5px; }',
|
|
|
- '[left~=Three] { height: 6px; }',
|
|
|
- '[left~="Four Five"] { color: #123; }', // not one word, so does not match!
|
|
|
- '[left~=our] { display: none; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','5px',Doc.Root.Width);
|
|
|
- AssertEquals('Root.Height','6px',Doc.Root.Height);
|
|
|
- AssertEquals('Root.Color','',Doc.Root.Color);
|
|
|
- AssertEquals('Root.Display','',Doc.Root.Display);
|
|
|
- AssertEquals('Button1.Top','',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','',Button1.Width);
|
|
|
- AssertEquals('Button1.Height','',Button1.Height);
|
|
|
- AssertEquals('Button1.Color','',Button1.Color);
|
|
|
- AssertEquals('Button1.Display','inline-block',Button1.Display);
|
|
|
+ if Resolver.ReadAttribute_Dimension(Invalid,Chk_WidthHeight) then
|
|
|
+ begin
|
|
|
+ Value.Value:=Resolver.CurComp.FloatAsString;
|
|
|
+ Value.State:=cavsComputed;
|
|
|
+ end
|
|
|
+ else begin
|
|
|
+ Value.Value:='invalid';
|
|
|
+ Value.State:=cavsInvalid;
|
|
|
+ end;
|
|
|
+ if Node=nil then ;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_AttributeContainsSubstring;
|
|
|
-var
|
|
|
- Button1: TDemoButton;
|
|
|
-begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
+constructor TDemoCSSRegistry.Create;
|
|
|
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
- Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
+ procedure SetDemoElementTypeID(aClass: TDemoNodeClass);
|
|
|
+ var
|
|
|
+ Desc: TCSSTypeDesc;
|
|
|
+ begin
|
|
|
+ Desc:=FindType(aClass.CSSTypeName);
|
|
|
+ if Desc=nil then
|
|
|
+ raise Exception.Create('20240625190912');
|
|
|
+ aClass.SetClassCSSTypeID(Desc.Index);
|
|
|
+ end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '[left*=oo] { top: 4px; }',
|
|
|
- '[left*="o B"] { width: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
- AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
-end;
|
|
|
+ procedure SetCompProps(ShorthandID: TDemoNodeAttribute; Longhands: array of TDemoNodeAttribute);
|
|
|
+ var
|
|
|
+ i: Integer;
|
|
|
+ begin
|
|
|
+ SetLength(DemoAttrs[ShorthandID].CompProps,length(Longhands));
|
|
|
+ for i:=0 to length(Longhands)-1 do
|
|
|
+ DemoAttrs[ShorthandID].CompProps[i]:=DemoAttrs[Longhands[i]];
|
|
|
+ end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Root;
|
|
|
var
|
|
|
- Button1: TDemoButton;
|
|
|
+ Attr: TDemoNodeAttribute;
|
|
|
+ PseudoClass: TDemoPseudoClass;
|
|
|
+ aType: TDemoElementType;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
+ inherited Create;
|
|
|
+ Init;
|
|
|
|
|
|
- Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Parent:=Doc.Root;
|
|
|
+ // register demo attributes
|
|
|
+ for Attr in TDemoNodeAttribute do
|
|
|
+ AddDemoAttr(Attr);
|
|
|
+ DemoAttrIDBase:=DemoAttrs[low(TDemoNodeAttribute)].Index;
|
|
|
+ if FindAttribute(DemoAttributeNames[naBackground]).Index<>DemoAttrIDBase+ord(naBackground) then
|
|
|
+ raise Exception.Create('20240617200337');
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':roOt { top: 4px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
- AssertEquals('Button1.Top','',Button1.Top);
|
|
|
-end;
|
|
|
+ // register demo pseudo classes
|
|
|
+ for PseudoClass in TDemoPseudoClass do
|
|
|
+ AddDemoPseudoClass(PseudoClass);
|
|
|
+ DemoPseudoClassIDBase:=DemoPseudoClasses[low(TDemoPseudoClass)].Index;
|
|
|
+ if FindPseudoClass(DemoPseudoClassNames[pcHover]).Index<>DemoPseudoClassIDBase+ord(pcHover) then
|
|
|
+ raise Exception.Create('20231008232201');
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Empty;
|
|
|
-var
|
|
|
- Div1, Div11, Div2: TDemoDiv;
|
|
|
-begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ // register demo element types
|
|
|
+ for aType in TDemoElementType do
|
|
|
+ AddDemoType(aType);
|
|
|
+ DemoElementTypeIDBase:=DemoTypes[low(TDemoElementType)].Index;
|
|
|
+ if FindType(DemoElementTypeNames[detButton]).Index<>DemoElementTypeIDBase+ord(detButton) then
|
|
|
+ raise Exception.Create('20240625181725');
|
|
|
+ SetDemoElementTypeID(TDemoNode);
|
|
|
+ SetDemoElementTypeID(TDemoDiv);
|
|
|
+ SetDemoElementTypeID(TDemoSpan);
|
|
|
+ SetDemoElementTypeID(TDemoButton);
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+ kwRed:=AddKeyword('red');
|
|
|
+ kwFirstColor:=kwRed;
|
|
|
+ kwGreen:=AddKeyword('green');
|
|
|
+ kwBlue:=AddKeyword('blue');
|
|
|
+ kwWhite:=AddKeyword('white');
|
|
|
+ kwBlack:=AddKeyword('black');
|
|
|
+ kwLastColor:=kwBlack;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
+ kwBlock:=AddKeyword('block');
|
|
|
+ kwInline_Block:=AddKeyword('inline-block');
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+ kwLTR:=AddKeyword('ltr');
|
|
|
+ kwRTL:=AddKeyword('rtl');
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':eMpty { left: 1px; }',
|
|
|
- 'div:emPty { top: 2px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','1px',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','2px',Div11.Top);
|
|
|
- AssertEquals('Div2.Left','1px',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','2px',Div2.Top);
|
|
|
-end;
|
|
|
+ // check parameters - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_FirstChild;
|
|
|
-var
|
|
|
- Div1, Div11, Div12, Div2: TDemoDiv;
|
|
|
-begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ // border-color
|
|
|
+ DemoAttrs[naBorderColor].OnCheck:=@OnCheck_BorderColor;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+ // border-width
|
|
|
+ DemoAttrs[naBorderWidth].OnCheck:=@OnCheck_BorderWidth;
|
|
|
+ Chk_BorderWidth.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
+ Chk_BorderWidth.AllowFrac:=true;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
+ // border shorthand
|
|
|
+ SetCompProps(naBorder,[naBorderColor,naBorderWidth]);
|
|
|
+ DemoAttrs[naBorder].OnCheck:=@OnCheck_Border;
|
|
|
+ DemoAttrs[naBorder].OnSplitShorthand:=@OnSplit_Border;
|
|
|
|
|
|
- Div12:=TDemoDiv.Create(nil);
|
|
|
- Div12.Parent:=Div1;
|
|
|
+ // direction
|
|
|
+ DemoAttrs[naDirection].OnCheck:=@OnCheck_Direction;
|
|
|
+ Chk_DirectionAllowedKeywordIDs:=[kwLTR,kwRTL];
|
|
|
+ DemoAttrs[naDirection].OnCompute:=@OnCompute_Direction;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+ // display
|
|
|
+ DemoAttrs[naDisplay].OnCheck:=@OnCheck_Display;
|
|
|
+ Chk_DisplayAllowedKeywordIDs:=[kwBlock,kwInline_Block];
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':first-child { left: 1px; }',
|
|
|
- 'div:first-child { top: 2px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','1px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','2px',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','1px',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','2px',Div11.Top);
|
|
|
- AssertEquals('Div12.Left','',Div12.Left);
|
|
|
- AssertEquals('Div12.Top','',Div12.Top);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','',Div2.Top);
|
|
|
+ // left, top
|
|
|
+ DemoAttrs[naLeft].OnCheck:=@OnCheck_LeftTop;
|
|
|
+ DemoAttrs[naLeft].OnCompute:=@OnCompute_LeftTop;
|
|
|
+ DemoAttrs[naTop].OnCheck:=@OnCheck_LeftTop;
|
|
|
+ DemoAttrs[naTop].OnCompute:=@OnCompute_LeftTop;
|
|
|
+ Chk_LeftTop.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
+ Chk_LeftTop.AllowNegative:=true;
|
|
|
+ Chk_LeftTop.AllowFrac:=true;
|
|
|
+
|
|
|
+ // width, height
|
|
|
+ DemoAttrs[naWidth].OnCheck:=@OnCheck_WidthHeight;
|
|
|
+ DemoAttrs[naWidth].OnCompute:=@OnCompute_WidthHeight;
|
|
|
+ DemoAttrs[naHeight].OnCheck:=@OnCheck_WidthHeight;
|
|
|
+ DemoAttrs[naHeight].OnCompute:=@OnCompute_WidthHeight;
|
|
|
+ Chk_WidthHeight.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
+ Chk_WidthHeight.AllowFrac:=true;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_LastChild;
|
|
|
-var
|
|
|
- Div1, Div11, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+function TDemoCSSRegistry.AddDemoAttr(Attr: TDemoNodeAttribute
|
|
|
+ ): TDemoCSSAttributeDesc;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
-
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Parent:=Div1;
|
|
|
+ Result:=TDemoCSSAttributeDesc(AddAttribute(DemoAttributeNames[Attr],
|
|
|
+ DemoAttributeInitialValues[Attr],
|
|
|
+ Attr in DemoAttributesInherited,
|
|
|
+ not (Attr in DemoAttributesNotAll),
|
|
|
+ TDemoCSSAttributeDesc));
|
|
|
+ Result.DemoID:=Attr;
|
|
|
+ DemoAttrs[Attr]:=Result;
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+function TDemoCSSRegistry.AddDemoPseudoClass(PC: TDemoPseudoClass
|
|
|
+ ): TDemoCSSPseudoClassDesc;
|
|
|
+begin
|
|
|
+ Result:=TDemoCSSPseudoClassDesc(AddPseudoClass(DemoPseudoClassNames[PC],
|
|
|
+ TDemoCSSPseudoClassDesc));
|
|
|
+ Result.DemoID:=PC;
|
|
|
+ DemoPseudoClasses[PC]:=Result;
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':last-child { left: 6px; }',
|
|
|
- 'div:last-child { top: 7px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','',Div11.Top);
|
|
|
- AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','',Button12.Top);
|
|
|
- AssertEquals('Div2.Left','6px',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','7px',Div2.Top);
|
|
|
+function TDemoCSSRegistry.AddDemoType(aType: TDemoElementType
|
|
|
+ ): TDemoCSSTypeDesc;
|
|
|
+begin
|
|
|
+ Result:=TDemoCSSTypeDesc(AddType(DemoElementTypeNames[aType],
|
|
|
+ TDemoCSSTypeDesc));
|
|
|
+ Result.DemoID:=aType;
|
|
|
+ DemoTypes[aType]:=Result;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_OnlyChild;
|
|
|
+{ TDemoNode }
|
|
|
+
|
|
|
+function TDemoNode.GetAttribute(DemoAttr: TDemoNodeAttribute): TCSSString;
|
|
|
var
|
|
|
- Div1, Div11, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+ AttrDesc: TDemoCSSAttributeDesc;
|
|
|
+ i: Integer;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
+ AttrDesc:=CSSRegistry.DemoAttrs[DemoAttr];
|
|
|
+ i:=Values.IndexOf(AttrDesc.Index);
|
|
|
+ if i>=0 then
|
|
|
+ Result:=Values.Values[i].Value
|
|
|
+ else
|
|
|
+ Result:='';
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetNodeCount: integer;
|
|
|
+begin
|
|
|
+ Result:=FNodes.Count;
|
|
|
+end;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Name:='Div11';
|
|
|
- Div11.Parent:=Div1;
|
|
|
+function TDemoNode.GetNodes(Index: integer): TDemoNode;
|
|
|
+begin
|
|
|
+ Result:=TDemoNode(FNodes[Index]);
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetPseudoClasses(PseudoClass: TDemoPseudoClass): boolean;
|
|
|
+begin
|
|
|
+ Result:=FPseudoClasses[PseudoClass];
|
|
|
+end;
|
|
|
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Name:='Button12';
|
|
|
- Button12.Parent:=Div2;
|
|
|
+procedure TDemoNode.SetParent(const AValue: TDemoNode);
|
|
|
+begin
|
|
|
+ if FParent=AValue then Exit;
|
|
|
+ if AValue=Self then
|
|
|
+ raise Exception.Create('cycle');
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':only-child { left: 8px; }',
|
|
|
- 'div:only-child { top: 9px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','8px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','8px',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','9px',Div11.Top);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','',Div2.Top);
|
|
|
- AssertEquals('Button12.Left','8px',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','',Button12.Top);
|
|
|
+ if FParent<>nil then
|
|
|
+ begin
|
|
|
+ FParent.FNodes.Remove(Self);
|
|
|
+ end;
|
|
|
+ FParent:=AValue;
|
|
|
+ if FParent<>nil then
|
|
|
+ begin
|
|
|
+ FParent.FNodes.Add(Self);
|
|
|
+ FreeNotification(FParent);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Not;
|
|
|
-var
|
|
|
- Div1, Div11, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+procedure TDemoNode.SetInlineStyleElements(const AValue: TCSSRuleElement);
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
+ if FInlineStyleElements=AValue then Exit;
|
|
|
+ FreeAndNil(FInlineStyleElements);
|
|
|
+ FInlineStyleElements:=AValue;
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+procedure TDemoNode.SetInlineStyle(const AValue: TCSSString);
|
|
|
+begin
|
|
|
+ if FInlineStyle=AValue then Exit;
|
|
|
+ FInlineStyle:=AValue;
|
|
|
+ FreeAndNil(FInlineStyleElements);
|
|
|
+end;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Name:='Div11';
|
|
|
- Div11.Parent:=Div1;
|
|
|
+procedure TDemoNode.SetPseudoClasses(PseudoClass: TDemoPseudoClass;
|
|
|
+ const AValue: boolean);
|
|
|
+begin
|
|
|
+ FPseudoClasses[PseudoClass]:=AValue;
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+procedure TDemoNode.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
+begin
|
|
|
+ inherited Notification(AComponent, Operation);
|
|
|
+ if AComponent=Self then exit;
|
|
|
+ if Operation=opRemove then
|
|
|
+ begin
|
|
|
+ if FNodes<>nil then
|
|
|
+ FNodes.Remove(AComponent);
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Name:='Button12';
|
|
|
- Button12.Parent:=Div2;
|
|
|
+constructor TDemoNode.Create(AOwner: TComponent);
|
|
|
+begin
|
|
|
+ inherited Create(AOwner);
|
|
|
+ FNodes:=TFPObjectList.Create(false);
|
|
|
+ FCSSClasses:=TStringList.Create;
|
|
|
+ FCSSClasses.Delimiter:=' ';
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':not(:only-child) { left: 8px; }',
|
|
|
- ':not(div:only-child) { top: 9px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','9px',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','9px',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','',Div11.Top);
|
|
|
- AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','9px',Div2.Top);
|
|
|
- AssertEquals('Button12.Left','',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','9px',Button12.Top);
|
|
|
+destructor TDemoNode.Destroy;
|
|
|
+begin
|
|
|
+ Clear;
|
|
|
+ FreeAndNil(FNodes);
|
|
|
+ FreeAndNil(FCSSClasses);
|
|
|
+ inherited Destroy;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_NthChild;
|
|
|
+procedure TDemoNode.Clear;
|
|
|
var
|
|
|
- Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
+ i: Integer;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Rules:=nil;
|
|
|
+ FreeAndNil(Values);
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+ FCSSClasses.Clear;
|
|
|
+ FreeAndNil(FInlineStyleElements);
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+ for i:=NodeCount-1 downto 0 do
|
|
|
+ Nodes[i].Free;
|
|
|
+ if FNodes.Count>0 then
|
|
|
+ raise Exception.Create('20240710174459');
|
|
|
+end;
|
|
|
|
|
|
- Div3:=TDemoDiv.Create(nil);
|
|
|
- Div3.Parent:=Doc.Root;
|
|
|
+procedure TDemoNode.ApplyCSS(Resolver: TCSSResolver);
|
|
|
+var
|
|
|
+ AttrDesc: TDemoCSSAttributeDesc;
|
|
|
+ i: Integer;
|
|
|
+ AttrID: TCSSNumericalID;
|
|
|
+ CurValue: TCSSAttributeValue;
|
|
|
+begin
|
|
|
+ if (InlineStyleElement=nil) and (InlineStyle<>'') then
|
|
|
+ InlineStyleElement:=Resolver.ParseInlineStyle(InlineStyle) as TCSSRuleElement;
|
|
|
|
|
|
- Div4:=TDemoDiv.Create(nil);
|
|
|
- Div4.Parent:=Doc.Root;
|
|
|
+ Resolver.Compute(Self,InlineStyleElement,Rules,Values);
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- 'div:nth-child(2n+1) { left: 8px; }',
|
|
|
- 'div:nth-child(n+3) { border-width: 6px; }',
|
|
|
- 'div:nth-child(-n+2) { height: 7em; }',
|
|
|
- 'div:nth-child(even) { top: 3px; }',
|
|
|
- 'div:nth-child(odd) { width: 4px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Root.BorderWidth','',Doc.Root.BorderWidth);
|
|
|
- AssertEquals('Root.Height','',Doc.Root.Height);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
- AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
- AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
- AssertEquals('Div1.Height','7em',Div1.Height);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div1.Width','4px',Div1.Width);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div2.BorderWidth','',Div2.BorderWidth);
|
|
|
- AssertEquals('Div2.Height','7em',Div2.Height);
|
|
|
- AssertEquals('Div2.Top','3px',Div2.Top);
|
|
|
- AssertEquals('Div2.Width','',Div2.Width);
|
|
|
- AssertEquals('Div3.Left','8px',Div3.Left);
|
|
|
- AssertEquals('Div3.BorderWidth','6px',Div3.BorderWidth);
|
|
|
- AssertEquals('Div3.Height','',Div3.Height);
|
|
|
- AssertEquals('Div3.Top','',Div3.Top);
|
|
|
- AssertEquals('Div3.Width','4px',Div3.Width);
|
|
|
- AssertEquals('Div4.Left','',Div4.Left);
|
|
|
- AssertEquals('Div4.BorderWidth','6px',Div4.BorderWidth);
|
|
|
- AssertEquals('Div4.Height','',Div4.Height);
|
|
|
- AssertEquals('Div4.Top','3px',Div4.Top);
|
|
|
- AssertEquals('Div4.Width','',Div4.Width);
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
+ writeln('TDemoNode.ApplyCSS ',Name,' length(Values)=',length(Values.Values),' All="',CSSRegistry.Keywords[Values.AllValue],'"');
|
|
|
+ for i:=0 to length(Values.Values)-1 do begin
|
|
|
+ AttrID:=Values.Values[i].AttrID;
|
|
|
+ writeln('TDemoNode.ApplyCSS ',Name,' resolved ',CSSRegistry.Attributes[AttrID].Name,'/',AttrID,':="',Values.Values[i].Value,'"');
|
|
|
+ end;
|
|
|
+ {$ENDIF}
|
|
|
+ // compute values
|
|
|
+ for i:=0 to length(Values.Values)-1 do
|
|
|
+ begin
|
|
|
+ CurValue:=Values.Values[i];
|
|
|
+ case CurValue.State of
|
|
|
+ cavsSource, cavsBaseKeywords:
|
|
|
+ begin
|
|
|
+ AttrID:=CurValue.AttrID;
|
|
|
+ AttrDesc:=CSSRegistry.Attributes[AttrID] as TDemoCSSAttributeDesc;
|
|
|
+ if AttrDesc.OnCompute<>nil then
|
|
|
+ begin
|
|
|
+ Resolver.CurComp.EndP:=PChar(CurValue.Value);
|
|
|
+ Resolver.ReadNext;
|
|
|
+ AttrDesc.OnCompute(Resolver,Self,CurValue);
|
|
|
+ {$IFDEF VerboseCSSResolver}
|
|
|
+ writeln('TDemoNode.ApplyCSS ',Name,' computed ',CSSRegistry.Attributes[AttrID].Name,'/',AttrID,':="',CurValue.Value,'"');
|
|
|
+ {$ENDIF}
|
|
|
+ end else
|
|
|
+ CurValue.State:=cavsComputed;
|
|
|
+ end;
|
|
|
+ cavsComputed: ;
|
|
|
+ cavsInvalid: ;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_NthLastChild;
|
|
|
+function TDemoNode.GetCSSID: TCSSString;
|
|
|
+begin
|
|
|
+ Result:=Name;
|
|
|
+end;
|
|
|
+
|
|
|
+class function TDemoNode.CSSTypeName: TCSSString;
|
|
|
+begin
|
|
|
+ Result:=DemoElementTypeNames[detNode];
|
|
|
+end;
|
|
|
+
|
|
|
+function TDemoNode.HasCSSClass(const aClassName: TCSSString): boolean;
|
|
|
var
|
|
|
- Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
+ i: Integer;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ for i:=0 to CSSClasses.Count-1 do
|
|
|
+ if aClassName=CSSClasses[i] then
|
|
|
+ exit(true);
|
|
|
+ Result:=false;
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSParent: ICSSNode;
|
|
|
+begin
|
|
|
+ Result:=Parent;
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSIndex: integer;
|
|
|
+begin
|
|
|
+ if Parent=nil then
|
|
|
+ Result:=-1
|
|
|
+ else
|
|
|
+ Result:=Parent.FNodes.IndexOf(Self);
|
|
|
+end;
|
|
|
|
|
|
- Div3:=TDemoDiv.Create(nil);
|
|
|
- Div3.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSNextSibling: ICSSNode;
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+begin
|
|
|
+ i:=GetCSSIndex;
|
|
|
+ if (i<0) or (i+1>=Parent.NodeCount) then
|
|
|
+ Result:=nil
|
|
|
+ else
|
|
|
+ Result:=Parent.Nodes[i+1];
|
|
|
+end;
|
|
|
|
|
|
- Div4:=TDemoDiv.Create(nil);
|
|
|
- Div4.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSPreviousSibling: ICSSNode;
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+begin
|
|
|
+ i:=GetCSSIndex;
|
|
|
+ if i<1 then
|
|
|
+ Result:=nil
|
|
|
+ else
|
|
|
+ Result:=Parent.Nodes[i-1];
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':nth-last-child(2n+1) { left: 8px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
- AssertEquals('Div3.Left','',Div3.Left);
|
|
|
- AssertEquals('Div4.Left','8px',Div4.Left);
|
|
|
+function TDemoNode.GetCSSChildCount: integer;
|
|
|
+begin
|
|
|
+ Result:=NodeCount;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_NthChildOf;
|
|
|
+function TDemoNode.GetCSSChild(const anIndex: integer): ICSSNode;
|
|
|
+begin
|
|
|
+ Result:=Nodes[anIndex];
|
|
|
+end;
|
|
|
+
|
|
|
+function TDemoNode.GetCSSNextOfType: ICSSNode;
|
|
|
var
|
|
|
- Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
+ i, Cnt: Integer;
|
|
|
+ MyID: TCSSNumericalID;
|
|
|
+ aNode: TDemoNode;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
+ Result:=nil;
|
|
|
+ i:=GetCSSIndex;
|
|
|
+ if i<0 then exit;
|
|
|
+ inc(i);
|
|
|
+ MyID:=GetClassCSSTypeID;
|
|
|
+ Cnt:=Parent.NodeCount;
|
|
|
+ while i<Cnt do
|
|
|
+ begin
|
|
|
+ aNode:=Parent.Nodes[i];
|
|
|
+ if aNode.GetClassCSSTypeID=MyID then
|
|
|
+ exit(aNode);
|
|
|
+ inc(i);
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSPreviousOfType: ICSSNode;
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+ MyID: TCSSNumericalID;
|
|
|
+ aNode: TDemoNode;
|
|
|
+begin
|
|
|
+ Result:=nil;
|
|
|
+ i:=GetCSSIndex;
|
|
|
+ if i<0 then exit;
|
|
|
+ dec(i);
|
|
|
+ MyID:=GetClassCSSTypeID;
|
|
|
+ while i>=0 do
|
|
|
+ begin
|
|
|
+ aNode:=Parent.Nodes[i];
|
|
|
+ if aNode.GetClassCSSTypeID=MyID then
|
|
|
+ exit(aNode);
|
|
|
+ dec(i);
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
- Div2.ExplicitAttributes[naTop]:='3px';
|
|
|
+function TDemoNode.GetCSSAttributeClass: TCSSString;
|
|
|
+begin
|
|
|
+ FCSSClasses.Delimiter:=' ';
|
|
|
+ Result:=FCSSClasses.DelimitedText;
|
|
|
+end;
|
|
|
|
|
|
- Div3:=TDemoDiv.Create(nil);
|
|
|
- Div3.Name:='Div3';
|
|
|
- Div3.Parent:=Doc.Root;
|
|
|
- Div3.ExplicitAttributes[naTop]:='3px';
|
|
|
+function TDemoNode.HasCSSExplicitAttribute(const AttrID: TCSSNumericalID): boolean;
|
|
|
+var
|
|
|
+ b: TCSSNumericalID;
|
|
|
+ Attr: TDemoNodeAttribute;
|
|
|
+begin
|
|
|
+ b:=CSSRegistry.DemoAttrIDBase;
|
|
|
+ if (AttrID<b) or (AttrID>b+ord(High(TDemoNodeAttribute))) then
|
|
|
+ exit(false);
|
|
|
+ Attr:=TDemoNodeAttribute(AttrID-b);
|
|
|
+ Result:=ExplicitAttributes[Attr]<>'';
|
|
|
+end;
|
|
|
|
|
|
- Div4:=TDemoDiv.Create(nil);
|
|
|
- Div4.Name:='Div4';
|
|
|
- Div4.Parent:=Doc.Root;
|
|
|
- Div4.ExplicitAttributes[naTop]:='3px';
|
|
|
+function TDemoNode.GetCSSExplicitAttribute(const AttrID: TCSSNumericalID): TCSSString;
|
|
|
+var
|
|
|
+ Attr: TDemoNodeAttribute;
|
|
|
+ b: TCSSNumericalID;
|
|
|
+begin
|
|
|
+ b:=CSSRegistry.DemoAttrIDBase;
|
|
|
+ if (AttrID<b) or (AttrID>b+ord(High(TDemoNodeAttribute))) then
|
|
|
+ exit('');
|
|
|
+ Attr:=TDemoNodeAttribute(AttrID-b);
|
|
|
+ Result:=ExplicitAttributes[Attr];
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':nth-child(2n+1 of [top=3px]) { left: 5px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div2.Left','5px',Div2.Left);
|
|
|
- AssertEquals('Div3.Left','',Div3.Left);
|
|
|
- AssertEquals('Div4.Left','5px',Div4.Left);
|
|
|
+function TDemoNode.HasCSSPseudoClass(const AttrID: TCSSNumericalID): boolean;
|
|
|
+var
|
|
|
+ b: TCSSNumericalID;
|
|
|
+begin
|
|
|
+ b:=CSSRegistry.DemoPseudoClassIDBase;
|
|
|
+ if (AttrID>=b) and (AttrID<=b+ord(High(TDemoPseudoClass))) then
|
|
|
+ Result:=HasPseudoClass[TDemoPseudoClass(AttrID-b)]
|
|
|
+ else
|
|
|
+ Result:=false;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_FirstOfType;
|
|
|
+function TDemoNode.GetCSSEmpty: boolean;
|
|
|
+begin
|
|
|
+ Result:=NodeCount=0;
|
|
|
+end;
|
|
|
+
|
|
|
+function TDemoNode.GetCSSDepth: integer;
|
|
|
var
|
|
|
- Div1, Div11, Div13, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+ Node: TDemoNode;
|
|
|
begin
|
|
|
- Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Result:=0;
|
|
|
+ Node:=Parent;
|
|
|
+ while Node<>nil do
|
|
|
+ begin
|
|
|
+ inc(Result);
|
|
|
+ Node:=Node.Parent;
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
+function TDemoNode.GetCSSTypeName: TCSSString;
|
|
|
+begin
|
|
|
+ Result:=CSSTypeName;
|
|
|
+end;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
+class function TDemoNode.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
+begin
|
|
|
+ Result:=FDemoNodeTypeID;
|
|
|
+end;
|
|
|
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Parent:=Div1;
|
|
|
+class procedure TDemoNode.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
+begin
|
|
|
+ FDemoNodeTypeID:=aID;
|
|
|
+end;
|
|
|
|
|
|
- Div13:=TDemoDiv.Create(nil);
|
|
|
- Div13.Parent:=Div1;
|
|
|
+function TDemoNode.GetCSSTypeID: TCSSNumericalID;
|
|
|
+begin
|
|
|
+ Result:=GetClassCSSTypeID;
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+class function TDemoNode.GetCSSTypeStyle: TCSSString;
|
|
|
+begin
|
|
|
+ Result:='';
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':first-of-type { left: 6px; }',
|
|
|
- 'div:first-of-type { top: 7px; }',
|
|
|
- '']);
|
|
|
+{ TCustomTestNewCSSResolver }
|
|
|
+
|
|
|
+procedure TCustomTestNewCSSResolver.SetUp;
|
|
|
+var
|
|
|
+ AttrDesc: TCSSAttributeDesc;
|
|
|
+begin
|
|
|
+ inherited SetUp;
|
|
|
+
|
|
|
+ TDemoNode.CSSRegistry:=TDemoCSSRegistry.Create();
|
|
|
+
|
|
|
+ // register button attribute 'caption'
|
|
|
+ AttrDesc:=TDemoNode.CSSRegistry.AddAttribute('caption');
|
|
|
+ TDemoButton.CSSCaptionID:=AttrDesc.Index;
|
|
|
+
|
|
|
+ FDoc:=TDemoDocument.Create(nil);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCustomTestNewCSSResolver.TearDown;
|
|
|
+begin
|
|
|
+ FreeAndNil(FDoc);
|
|
|
+ FreeAndNil(TDemoNode.CSSRegistry);
|
|
|
+ inherited TearDown;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCustomTestNewCSSResolver.ApplyStyle;
|
|
|
+begin
|
|
|
Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','6px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','7px',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','6px',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','7px',Div11.Top);
|
|
|
- AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','',Button12.Top);
|
|
|
- AssertEquals('Div13.Left','',Div13.Left);
|
|
|
- AssertEquals('Div13.Top','',Div13.Top);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','',Div2.Top);
|
|
|
+ CheckWarnings;
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_LastOfType;
|
|
|
+procedure TCustomTestNewCSSResolver.CheckWarnings;
|
|
|
var
|
|
|
- Div1, Div11, Div13, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+ aResolver: TCSSResolver;
|
|
|
+ i: Integer;
|
|
|
+ Entry: TCSSResolverLogEntry;
|
|
|
+ s: String;
|
|
|
+begin
|
|
|
+ aResolver:=FDoc.CSSResolver;
|
|
|
+ if aResolver.LogCount=0 then exit;
|
|
|
+ writeln('TCustomTestNewCSSResolver.CheckWarnings LogCount=',aResolver.LogCount);
|
|
|
+ for i:=0 to aResolver.LogCount-1 do
|
|
|
+ begin
|
|
|
+ Entry:=aResolver.LogEntries[i];
|
|
|
+ s:='';
|
|
|
+ if Entry.PosEl<>nil then
|
|
|
+ s:=' at '+Entry.PosEl.SourceFileName+'('+IntToStr(Entry.PosEl.SourceRow)+','+IntToStr(Entry.PosEl.SourceRow)+')';
|
|
|
+ writeln(' ',Entry.MsgType,': ',Entry.ID,' ',Entry.Msg,s);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+{ TTestNewCSSResolver }
|
|
|
+
|
|
|
+procedure TTestNewCSSResolver.Test_ParseAttr_Keyword;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Style:='* { direction: ltr; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.direction','ltr',Doc.Root.Direction);
|
|
|
+end;
|
|
|
|
|
|
+procedure TTestNewCSSResolver.Test_ParseAttr_Keyword_SkipInvalid;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Style:='* { direction: something ltr; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.direction','ltr',Doc.Root.Direction);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestNewCSSResolver.Test_ParseAttr_Float;
|
|
|
+var
|
|
|
+ Div1: TDemoDiv;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Style:=
|
|
|
+ ':root {'
|
|
|
+ +' left: 10px;'
|
|
|
+ +' top: .1px;'
|
|
|
+ +' width: 3e2em;'
|
|
|
+ +' height: 3e-2px;'
|
|
|
+ +'}'
|
|
|
+ +'div {'
|
|
|
+ +' left: -4mm;'
|
|
|
+ +' top: -.5pc;'
|
|
|
+ +' width: .6cm;'
|
|
|
+ +' height: 6E+1rem;'
|
|
|
+ +'}';
|
|
|
Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','10px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','0.1px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','300em',Doc.Root.Width);
|
|
|
+ AssertEquals('Root.Height','0.03px',Doc.Root.Height);
|
|
|
+ AssertEquals('Div1.Left','-4mm',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','-0.5pc',Div1.Top);
|
|
|
+ AssertEquals('Div1.Width','0.6cm',Div1.Width);
|
|
|
+ AssertEquals('Div1.Height','60rem',Div1.Height);
|
|
|
+end;
|
|
|
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Parent:=Div1;
|
|
|
+procedure TTestNewCSSResolver.Test_ParseAttr_Float_SkipInvalid;
|
|
|
+begin
|
|
|
+ exit;
|
|
|
|
|
|
- Div13:=TDemoDiv.Create(nil);
|
|
|
- Div13.Parent:=Div1;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Style:=
|
|
|
+ ':root {'
|
|
|
+ +' left: something 10px;'
|
|
|
+ +' top: 1 px;' // no space between number
|
|
|
+ +' width: 0 px;' // the px is ignored because of the space, 0 without unit is allowed
|
|
|
+ +' height: -4cm;' // no negative
|
|
|
+ +'}';
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','10px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','invalid',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','0',Doc.Root.Width);
|
|
|
+ AssertEquals('Root.Height','invalid',Doc.Root.Height);
|
|
|
+end;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':last-of-type { left: 6px; }',
|
|
|
- 'div:last-of-type { top: 7px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','',Div11.Top);
|
|
|
- AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','',Button12.Top);
|
|
|
- AssertEquals('Div13.Left','6px',Div13.Left);
|
|
|
- AssertEquals('Div13.Top','7px',Div13.Top);
|
|
|
- AssertEquals('Div2.Left','6px',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','7px',Div2.Top);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Universal;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Style:='* { left: 10px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','10px',Doc.Root.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_OnlyOfType;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Type;
|
|
|
var
|
|
|
- Div1, Div11, Div2: TDemoDiv;
|
|
|
- Button12: TDemoButton;
|
|
|
+ Button: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Parent:=Div1;
|
|
|
-
|
|
|
- Button12:=TDemoButton.Create(nil);
|
|
|
- Button12.Parent:=Div1;
|
|
|
-
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':only-of-type { left: 6px; }',
|
|
|
- 'div:only-of-type { top: 7px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Div11.Left','6px',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','7px',Div11.Top);
|
|
|
- AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
- AssertEquals('Button12.Top','',Button12.Top);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div2.Top','',Div2.Top);
|
|
|
+ Button:=TDemoButton.Create(nil);
|
|
|
+ Button.Parent:=Doc.Root;
|
|
|
+ Doc.Style:='button { left: 11px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button.left','11px',Button.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_NthOfType;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Type_Spaces;
|
|
|
var
|
|
|
- Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
Button1, Button2: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
|
|
|
Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div3:=TDemoDiv.Create(nil);
|
|
|
- Div3.Name:='Div3';
|
|
|
- Div3.Parent:=Doc.Root;
|
|
|
-
|
|
|
Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.Name:='Button2';
|
|
|
Button2.Parent:=Doc.Root;
|
|
|
|
|
|
- Div4:=TDemoDiv.Create(nil);
|
|
|
- Div4.Name:='Div4';
|
|
|
- Div4.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':nth-of-type(2n+1) { left: 8px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
- AssertEquals('Button1.Left','8px',Button1.Left);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Div3.Left','8px',Div3.Left);
|
|
|
- AssertEquals('Button2.Left','',Button2.Left);
|
|
|
- AssertEquals('Div4.Left','',Div4.Left);
|
|
|
+ Doc.Style:='div, button ,span { left: 11px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','11px',Button1.Left);
|
|
|
+ AssertEquals('Button2.left','11px',Button2.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_NthLastOfType;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Id;
|
|
|
var
|
|
|
- Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
- Button1, Button2: TDemoButton;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
Button1.Parent:=Doc.Root;
|
|
|
+ Doc.Style:='#Button1 { left: 12px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','12px',Button1.Left);
|
|
|
+end;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div3:=TDemoDiv.Create(nil);
|
|
|
- Div3.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Button2:=TDemoButton.Create(nil);
|
|
|
- Button2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Div4:=TDemoDiv.Create(nil);
|
|
|
- Div4.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':nth-last-of-type(2n+1) { left: 8px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','',Div1.Left);
|
|
|
- AssertEquals('Button1.Left','',Button1.Left);
|
|
|
- AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
- AssertEquals('Div3.Left','',Div3.Left);
|
|
|
- AssertEquals('Button2.Left','8px',Button2.Left);
|
|
|
- AssertEquals('Div4.Left','8px',Div4.Left);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Class;
|
|
|
+var
|
|
|
+ Button1: TDemoButton;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.CSSClasses.Add('west');
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Doc.Style:='.west { left: 13px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','13px',Button1.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Is;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_ClassClass;
|
|
|
var
|
|
|
- Div1, Div2: TDemoDiv;
|
|
|
Button1, Button2: TDemoButton;
|
|
|
- Span1: TDemoSpan;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
+ Button1.CSSClasses.Add('west');
|
|
|
Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
-
|
|
|
- Span1:=TDemoSpan.Create(nil);
|
|
|
- Span1.Parent:=Doc.Root;
|
|
|
- Span1.ExplicitAttributes[naTop]:='3px';
|
|
|
-
|
|
|
Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.CSSClasses.DelimitedText:='west south';
|
|
|
+ AssertEquals('Button2.CSSClasses.Count',2,Button2.CSSClasses.Count);
|
|
|
Button2.Parent:=Doc.Root;
|
|
|
- Button2.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':is(div, button)[top=3px] { left: 7px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','7px',Div1.Left);
|
|
|
- AssertEquals('Button1.Left','',Button1.Left);
|
|
|
- AssertEquals('Div2.Left','',Div2.Left);
|
|
|
- AssertEquals('Span1.Left','',Div2.Left);
|
|
|
- AssertEquals('Button2.Left','7px',Button2.Left);
|
|
|
+ Doc.Style:='.west.south { left: 10px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','',Button1.Left);
|
|
|
+ AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Where;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_ClassSpaceClass;
|
|
|
var
|
|
|
- Div1, Div2: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.ExplicitAttributes[naTop]:='3px';
|
|
|
+ Doc.Root.CSSClasses.Add('bird');
|
|
|
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Div1;
|
|
|
- Div2.ExplicitAttributes[naTop]:='3px';
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.CSSClasses.Add('west');
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':where(div[top=3px]) { left: 1px; }',
|
|
|
- 'div div { left: 2px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
- AssertEquals('Div2.Left','2px',Div2.Left);
|
|
|
+ Doc.Style:='.bird .west { left: 10px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','10px',Button1.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Selector_Hover;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_TypeCommaType;
|
|
|
var
|
|
|
- Div1, Div11: TDemoDiv;
|
|
|
Button1: TDemoButton;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
- Doc.Root.Name:='root';
|
|
|
-
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.Hover:=true;
|
|
|
|
|
|
Button1:=TDemoButton.Create(nil);
|
|
|
- Button1.Name:='Button1';
|
|
|
- Button1.Parent:=Div1;
|
|
|
- Button1.Hover:=true;
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- Div11:=TDemoDiv.Create(nil);
|
|
|
- Div11.Name:='Div11';
|
|
|
- Div11.Parent:=Div1;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- ':hover { left: 1px; }',
|
|
|
- 'button:hover { top: 2px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
- AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','',Div1.Top);
|
|
|
- AssertEquals('Button1.Left','1px',Button1.Left);
|
|
|
- AssertEquals('Button1.Top','2px',Button1.Top);
|
|
|
- AssertEquals('Div11.Left','',Div11.Left);
|
|
|
- AssertEquals('Div11.Top','',Div11.Top);
|
|
|
+ Doc.Style:='div, button { left: 10px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','10px',Button1.Left);
|
|
|
+ AssertEquals('Div1.left','10px',Div1.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_InlineStyle;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_ClassGTClass;
|
|
|
var
|
|
|
- Div1: TDemoDiv;
|
|
|
+ Div1, Div2: TDemoDiv;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
+ Doc.Root.CSSClasses.Add('lvl1');
|
|
|
|
|
|
Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.CSSClasses.Add('lvl2');
|
|
|
Div1.Parent:=Doc.Root;
|
|
|
- Div1.InlineStyle:='left: 10px; top: 5px';
|
|
|
+
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.CSSClasses.Add('lvl3');
|
|
|
+ Div2.Parent:=Div1;
|
|
|
|
|
|
Doc.Style:=LinesToStr([
|
|
|
- 'div { left: 6px; }',
|
|
|
+ '.lvl1>.lvl2 { left: 10px; }', // set
|
|
|
+ '.lvl1>.lvl3 { top: 11px; }', // not set, not direct children
|
|
|
+ '.lvl2>.lvl3 { width: 12px; }', // set
|
|
|
'']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','10px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','5px',Div1.Top);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Div1.left','10px',Div1.Left);
|
|
|
+ AssertEquals('Div1.top','',Div1.Top);
|
|
|
+ AssertEquals('Div1.width','',Div1.Width);
|
|
|
+ AssertEquals('Div2.left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.top','',Div2.Top);
|
|
|
+ AssertEquals('Div2.width','12px',Div2.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Id_Class;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_TypePlusType;
|
|
|
var
|
|
|
+ Button1, Button2, Button3: TDemoButton;
|
|
|
Div1: TDemoDiv;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
+
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
Div1:=TDemoDiv.Create(nil);
|
|
|
Div1.Name:='Div1';
|
|
|
Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '.bird { left: 6px; }',
|
|
|
- '#Div1 { left: 7px; top: 8px; }', // id has higher specifity, no matter if before or after a .class
|
|
|
- '.bird { top: 9px; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','7px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','8px',Div1.Top);
|
|
|
+ Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.Name:='Button2';
|
|
|
+ Button2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Button3:=TDemoButton.Create(nil);
|
|
|
+ Button3.Name:='Button3';
|
|
|
+ Button3.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:='div+button { left: 10px; }'; // only Button2 has a prev sibling div
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','',Button1.Left);
|
|
|
+ AssertEquals('Div1.left','',Div1.Left);
|
|
|
+ AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
+ AssertEquals('Button3.left','',Button3.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Important;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_TypeTildeType;
|
|
|
var
|
|
|
+ Button1, Button2, Button3: TDemoButton;
|
|
|
Div1: TDemoDiv;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+
|
|
|
Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
|
|
|
- Doc.Style:=LinesToStr([
|
|
|
- '.bird { left: 6px !important; }',
|
|
|
- '#Div1 { left: 7px; top: 8px; }',
|
|
|
- '.bird { top: 9px ! important; }',
|
|
|
- '']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
- AssertEquals('Div1.Left','6px',Div1.Left);
|
|
|
- AssertEquals('Div1.Top','9px',Div1.Top);
|
|
|
+ Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Button3:=TDemoButton.Create(nil);
|
|
|
+ Button3.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:='div~button { left: 10px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Button1.left','',Button1.Left);
|
|
|
+ AssertEquals('Div1.left','',Div1.Left);
|
|
|
+ AssertEquals('Button2.left','10px',Button2.Left);
|
|
|
+ AssertEquals('Button3.left','10px',Button3.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Shorthand_OneRule;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_HasAttribute;
|
|
|
var
|
|
|
- Div1: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='100px';
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='2px';
|
|
|
+ Button1.ExplicitCaption:='Click Button1';
|
|
|
|
|
|
- Doc.Style:='.bird { border-color: blue; border: 6px red; border-width: 7px; }';
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Div1.BorderColor','red',Div1.BorderColor);
|
|
|
- AssertEquals('Div1.BorderWidth','7px',Div1.BorderWidth);
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '[left] { top: 3px; }',
|
|
|
+ '[caption] { width: 4px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','3px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Button1.Top','3px',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','4px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Shorthand_ClassClass;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeEquals;
|
|
|
var
|
|
|
- Div1: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='2px';
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
- Div1.CSSClasses.Add('eagle');
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='3px';
|
|
|
+ Button1.ExplicitAttributes[naColor]:='maybe black';
|
|
|
|
|
|
Doc.Style:=LinesToStr([
|
|
|
- '.bird.eagle { border-color: blue; }',
|
|
|
- '.bird { border-width: 6px; }',
|
|
|
- '.bird { border: 7px red; }',
|
|
|
+ '[left=2px] { top: 4px; }',
|
|
|
+ '[color="maybe black"] { width: 5px; }',
|
|
|
'']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
- AssertEquals('Div1.BorderWidth','7px',Div1.BorderWidth);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Button1.Top','',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Longhand_All_Longhand;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeEqualsI;
|
|
|
var
|
|
|
- Div1: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='2px';
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
- Div1.CSSClasses.Add('eagle');
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='3px';
|
|
|
+ Button1.ExplicitAttributes[naColor]:='maybe Black';
|
|
|
|
|
|
Doc.Style:=LinesToStr([
|
|
|
- '.bird.eagle { border-color: blue; }',
|
|
|
- '.bird { border-width: 7px; }',
|
|
|
- '.bird { all: initial; }',
|
|
|
- '.bird { background: red; }',
|
|
|
+ '[left="2Px" i] { top: 4px; }',
|
|
|
+ '[color="Maybe bLack" i] { width: 5px; }',
|
|
|
'']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
- AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
- AssertEquals('Div1.Background','red',Div1.Background);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Button1.Top','',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Specifity_Shorthand_All_Shorthand;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeBeginsWith;
|
|
|
var
|
|
|
- Div1, Div2: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
- Div1.CSSClasses.Add('bird');
|
|
|
-
|
|
|
- Div2:=TDemoDiv.Create(nil);
|
|
|
- Div2.Name:='Div2';
|
|
|
- Div2.Parent:=Doc.Root;
|
|
|
- Div2.CSSClasses.Add('eagle');
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
|
|
|
Doc.Style:=LinesToStr([
|
|
|
- '.bird { border: 7px blue; }',
|
|
|
- '.bird { all: initial; }',
|
|
|
- '.eagle { all: initial; }',
|
|
|
- '.eagle { border: 8px red; }',
|
|
|
+ '[left^=Fo] { top: 4px; }',
|
|
|
+ '[left^="Foo B"] { width: 5px; }',
|
|
|
'']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Div1.BorderColor','',Div1.BorderColor);
|
|
|
- AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
- AssertEquals('Div2.BorderColor','red',Div2.BorderColor);
|
|
|
- AssertEquals('Div2.BorderWidth','8px',Div2.BorderWidth);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TTestNewCSSResolver.Test_Origin_Id_Class;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeEndsWith;
|
|
|
var
|
|
|
- Div1: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
|
|
|
- Div1:=TDemoDiv.Create(nil);
|
|
|
- Div1.Name:='Div1';
|
|
|
- Div1.Parent:=Doc.Root;
|
|
|
-
|
|
|
- writeln('TTestNewCSSResolver.Test_Origin_Id_Class ',Doc.CSSResolver.ClassName);
|
|
|
- Doc.CSSResolver.AddStyleSheet(cssoUserAgent,'testagent',
|
|
|
- '#Div1 { border-width: 2px;'
|
|
|
- +' border-color: blue !important;'
|
|
|
- +' background: green; }'
|
|
|
- );
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
|
|
|
Doc.Style:=LinesToStr([
|
|
|
- 'div { border-width: 3px; ', // although class has lower spec than id, author origin wins
|
|
|
- ' border-color: orange;', // former important always wins
|
|
|
- '}']);
|
|
|
- Doc.ApplyStyle;
|
|
|
- AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
- AssertEquals('Div1.BorderWidth','3px',Div1.BorderWidth);
|
|
|
- AssertEquals('Div1.Background','green',Div1.Background);
|
|
|
+ '[left$=o] { top: 4px; }',
|
|
|
+ '[left$="o Bar"] { width: 5px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Button1.Top','',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-{ TDemoDiv }
|
|
|
-
|
|
|
-class function TDemoDiv.CSSTypeName: TCSSString;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeBeginsWithHyphen;
|
|
|
+var
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
- Result:=DemoElementTypeNames[detDiv];
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
|
|
|
-class function TDemoDiv.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
-begin
|
|
|
- Result:=FDemoDivTypeID;
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='Foo-Bar';
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '[left|=Foo] { top: 4px; }',
|
|
|
+ '[left|="Fo"] { width: 5px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-class procedure TDemoDiv.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeContainsWord;
|
|
|
+var
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
- FDemoDivTypeID:=aID;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='One Two Three';
|
|
|
+
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='Four Five';
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '[left~=One] { top: 4px; }',
|
|
|
+ '[left~=Two] { width: 5px; }',
|
|
|
+ '[left~=Three] { height: 6px; }',
|
|
|
+ '[left~="Four Five"] { color: #123; }', // not one word, so does not match!
|
|
|
+ '[left~=our] { display: none; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','5px',Doc.Root.Width);
|
|
|
+ AssertEquals('Root.Height','6px',Doc.Root.Height);
|
|
|
+ AssertEquals('Root.Color','',Doc.Root.Color);
|
|
|
+ AssertEquals('Root.Display','',Doc.Root.Display);
|
|
|
+ AssertEquals('Button1.Top','',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','',Button1.Width);
|
|
|
+ AssertEquals('Button1.Height','',Button1.Height);
|
|
|
+ AssertEquals('Button1.Color','',Button1.Color);
|
|
|
+ AssertEquals('Button1.Display','inline-block',Button1.Display);
|
|
|
end;
|
|
|
|
|
|
-class function TDemoDiv.GetCSSTypeStyle: TCSSString;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_AttributeContainsSubstring;
|
|
|
+var
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
- Result:='div{ display: block }';
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
|
|
|
-{ TDemoSpan }
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+ Button1.ExplicitAttributes[naLeft]:='Foo Bar';
|
|
|
|
|
|
-class function TDemoSpan.CSSTypeName: TCSSString;
|
|
|
-begin
|
|
|
- Result:=DemoElementTypeNames[detSpan];
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '[left*=oo] { top: 4px; }',
|
|
|
+ '[left*="o B"] { width: 5px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Button1.Top','4px',Button1.Top);
|
|
|
+ AssertEquals('Button1.Width','5px',Button1.Width);
|
|
|
end;
|
|
|
|
|
|
-class function TDemoSpan.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Root;
|
|
|
+var
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
- Result:=FDemoSpanTypeID;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.ExplicitAttributes[naLeft]:='Foo';
|
|
|
|
|
|
-class procedure TDemoSpan.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
-begin
|
|
|
- FDemoSpanTypeID:=aID;
|
|
|
-end;
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
-class function TDemoSpan.GetCSSTypeStyle: TCSSString;
|
|
|
-begin
|
|
|
- Result:='span{display: inline-block }';
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':roOt { top: 4px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Top','4px',Doc.Root.Top);
|
|
|
+ AssertEquals('Button1.Top','',Button1.Top);
|
|
|
end;
|
|
|
|
|
|
-{ TDemoButton }
|
|
|
-
|
|
|
-procedure TDemoButton.SetCaption(const AValue: TCSSString);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Empty;
|
|
|
+var
|
|
|
+ Div1, Div11, Div2: TDemoDiv;
|
|
|
begin
|
|
|
- if FCaption=AValue then Exit;
|
|
|
- FCaption:=AValue;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-class function TDemoButton.CSSTypeName: TCSSString;
|
|
|
-begin
|
|
|
- Result:=DemoElementTypeNames[detButton];
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-class function TDemoButton.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
-begin
|
|
|
- Result:=FDemoButtonTypeID;
|
|
|
-end;
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
-class procedure TDemoButton.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
-begin
|
|
|
- FDemoButtonTypeID:=aID;
|
|
|
-end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
-class function TDemoButton.GetCSSTypeStyle: TCSSString;
|
|
|
-begin
|
|
|
- Result:='button{display: inline-block }';
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':eMpty { left: 1px; }',
|
|
|
+ 'div:emPty { top: 2px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','1px',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','2px',Div11.Top);
|
|
|
+ AssertEquals('Div2.Left','1px',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','2px',Div2.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoButton.HasCSSExplicitAttribute(const AttrID: TCSSNumericalID
|
|
|
- ): boolean;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_FirstChild;
|
|
|
+var
|
|
|
+ Div1, Div11, Div12, Div2: TDemoDiv;
|
|
|
begin
|
|
|
- //writeln('TDemoButton.HasCSSExplicitAttribute ',AttrID,' CSSCaptionID=',CSSCaptionID);
|
|
|
- if AttrID=CSSCaptionID then
|
|
|
- Result:=ExplicitCaption<>''
|
|
|
- else
|
|
|
- Result:=inherited HasCSSExplicitAttribute(AttrID);
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoButton.GetCSSExplicitAttribute(const AttrID: TCSSNumericalID
|
|
|
- ): TCSSString;
|
|
|
-begin
|
|
|
- if AttrID=CSSCaptionID then
|
|
|
- Result:=ExplicitCaption
|
|
|
- else
|
|
|
- Result:=inherited GetCSSExplicitAttribute(AttrID);
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-{ TDemoDocument }
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
-procedure TDemoDocument.SetStyle(const AValue: TCSSString);
|
|
|
-begin
|
|
|
- if FStyle=AValue then Exit;
|
|
|
- FStyle:=AValue;
|
|
|
-end;
|
|
|
+ Div12:=TDemoDiv.Create(nil);
|
|
|
+ Div12.Parent:=Div1;
|
|
|
|
|
|
-constructor TDemoDocument.Create(AOwner: TComponent);
|
|
|
-begin
|
|
|
- inherited Create(AOwner);
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
- // create the css resolver
|
|
|
- FCSSResolver:=TCSSResolver.Create(nil);
|
|
|
- FCSSResolver.CSSRegistry:=TDemoNode.CSSRegistry;
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':first-child { left: 1px; }',
|
|
|
+ 'div:first-child { top: 2px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','1px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','2px',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','1px',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','2px',Div11.Top);
|
|
|
+ AssertEquals('Div12.Left','',Div12.Left);
|
|
|
+ AssertEquals('Div12.Top','',Div12.Top);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','',Div2.Top);
|
|
|
end;
|
|
|
|
|
|
-destructor TDemoDocument.Destroy;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_LastChild;
|
|
|
+var
|
|
|
+ Div1, Div11, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
begin
|
|
|
- FreeAndNil(Root);
|
|
|
- FreeAndNil(FCSSResolver);
|
|
|
- inherited Destroy;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-procedure TDemoDocument.ApplyStyle;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- procedure Traverse(Node: TDemoNode);
|
|
|
- var
|
|
|
- i: Integer;
|
|
|
- begin
|
|
|
- Node.ApplyCSS(CSSResolver);
|
|
|
- for i:=0 to Node.NodeCount-1 do
|
|
|
- Traverse(Node[i]);
|
|
|
- end;
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
-begin
|
|
|
- ApplyTypeStyles;
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Parent:=Div1;
|
|
|
|
|
|
- CSSResolver.AddStyleSheet(cssoAuthor,'test.css',Style);
|
|
|
- CSSResolver.Init;
|
|
|
- Traverse(Root);
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':last-child { left: 6px; }',
|
|
|
+ 'div:last-child { top: 7px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','',Div11.Top);
|
|
|
+ AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','',Button12.Top);
|
|
|
+ AssertEquals('Div2.Left','6px',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','7px',Div2.Top);
|
|
|
end;
|
|
|
|
|
|
-procedure TDemoDocument.ApplyTypeStyles;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_OnlyChild;
|
|
|
var
|
|
|
- FoundStyles: array of TDemoNodeClass;
|
|
|
+ Div1, Div11, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
- procedure AddTypeStyle(NodeClass: TDemoNodeClass);
|
|
|
- var
|
|
|
- i: Integer;
|
|
|
- Src, ParentSrc: TCSSString;
|
|
|
- ParentNodeClass: TDemoNodeClass;
|
|
|
- begin
|
|
|
- for i:=0 to length(FoundStyles)-1 do
|
|
|
- if FoundStyles[i]=NodeClass then exit;
|
|
|
- Insert(NodeClass,FoundStyles,length(FoundStyles));
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- Src:=NodeClass.GetCSSTypeStyle;
|
|
|
- //writeln('AddTypeStyle ',NodeClass.ClassName,' Src="',Src,'"');
|
|
|
- if Src='' then exit;
|
|
|
- if NodeClass.ClassType<>TDemoNode then
|
|
|
- begin
|
|
|
- ParentNodeClass:=TDemoNodeClass(NodeClass.ClassParent);
|
|
|
- AddTypeStyle(ParentNodeClass);
|
|
|
- ParentSrc:=ParentNodeClass.GetCSSTypeStyle;
|
|
|
- if Src=ParentSrc then exit;
|
|
|
- end;
|
|
|
- //writeln('AddTypeStyle ',NodeClass.ClassName,' [',Src,']');
|
|
|
- FCSSResolver.AddStyleSheet(cssoUserAgent,NodeClass.ClassName,Src);
|
|
|
- end;
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Name:='Div11';
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
- procedure CollectTypeStyles(Node: TDemoNode);
|
|
|
- var
|
|
|
- NodeClass: TDemoNodeClass;
|
|
|
- i: Integer;
|
|
|
- begin
|
|
|
- NodeClass:=TDemoNodeClass(Node.ClassType);
|
|
|
- AddTypeStyle(NodeClass);
|
|
|
- for i:=0 to Node.NodeCount-1 do
|
|
|
- CollectTypeStyles(Node[i]);
|
|
|
- end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
-begin
|
|
|
- FoundStyles:=[];
|
|
|
- CollectTypeStyles(Root);
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Name:='Button12';
|
|
|
+ Button12.Parent:=Div2;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':only-child { left: 8px; }',
|
|
|
+ 'div:only-child { top: 9px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','8px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','8px',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','9px',Div11.Top);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','',Div2.Top);
|
|
|
+ AssertEquals('Button12.Left','8px',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','',Button12.Top);
|
|
|
end;
|
|
|
|
|
|
-{ TDemoCSSRegistry }
|
|
|
-
|
|
|
-function TDemoCSSRegistry.OnCheck_Border(Resolver: TCSSBaseResolver): boolean;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Not;
|
|
|
var
|
|
|
- HasWidth, HasColor: Boolean;
|
|
|
+ Div1, Div11, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
begin
|
|
|
- HasWidth:=false;
|
|
|
- HasColor:=false;
|
|
|
- repeat
|
|
|
- case Resolver.CurComp.Kind of
|
|
|
- rvkFloat:
|
|
|
- if not HasWidth then
|
|
|
- HasWidth:=Resolver.CurComp.FloatUnit in ([cuNONE,cuPERCENT]+cuAllLengths);
|
|
|
- rvkKeyword:
|
|
|
- if not HasColor then
|
|
|
- HasColor:=(Resolver.CurComp.KeywordID>=kwFirstColor) and (Resolver.CurComp.KeywordID<=kwLastColor);
|
|
|
- end;
|
|
|
- until not Resolver.ReadNext;
|
|
|
- Result:=HasWidth or HasColor;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_BorderColor(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Color([]);
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_BorderWidth(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Dimension(Chk_BorderWidth);
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Name:='Div11';
|
|
|
+ Div11.Parent:=Div1;
|
|
|
+
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Name:='Button12';
|
|
|
+ Button12.Parent:=Div2;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':not(:only-child) { left: 8px; }',
|
|
|
+ ':not(div:only-child) { top: 9px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','9px',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','9px',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','',Div11.Top);
|
|
|
+ AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','9px',Div2.Top);
|
|
|
+ AssertEquals('Button12.Left','',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','9px',Button12.Top);
|
|
|
end;
|
|
|
|
|
|
-procedure TDemoCSSRegistry.OnSplit_Border(Resolver: TCSSBaseResolver;
|
|
|
- var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_NthChild;
|
|
|
var
|
|
|
- aWidth, aColor: TCSSString;
|
|
|
+ Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
begin
|
|
|
- aWidth:='';
|
|
|
- aColor:='';
|
|
|
- repeat
|
|
|
- case Resolver.CurComp.Kind of
|
|
|
- rvkFloat:
|
|
|
- if aWidth='' then begin
|
|
|
- if Resolver.CurComp.FloatUnit in ([cuNONE,cuPERCENT]+cuAllLengths) then
|
|
|
- aWidth:=Resolver.CurComp.FloatAsString;
|
|
|
- end;
|
|
|
- rvkKeyword:
|
|
|
- if aColor='' then
|
|
|
- begin
|
|
|
- if (Resolver.CurComp.KeywordID>=kwFirstColor) and (Resolver.CurComp.KeywordID<=kwLastColor) then
|
|
|
- aColor:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
- end;
|
|
|
- end;
|
|
|
- until not Resolver.ReadNext;
|
|
|
- SetLength(AttrIDs,2);
|
|
|
- SetLength(Values,2);
|
|
|
- AttrIDs[0]:=DemoAttrs[naBorderWidth].Index;
|
|
|
- Values[0]:=aWidth;
|
|
|
- AttrIDs[1]:=DemoAttrs[naBorderColor].Index;
|
|
|
- Values[1]:=aColor;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_Direction(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Keyword(Chk_DirectionAllowedKeywordIDs);
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_Display(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Keyword(Chk_DisplayAllowedKeywordIDs);
|
|
|
-end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_LeftTop(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Dimension(Chk_LeftTop);
|
|
|
-end;
|
|
|
+ Div3:=TDemoDiv.Create(nil);
|
|
|
+ Div3.Parent:=Doc.Root;
|
|
|
|
|
|
-function TDemoCSSRegistry.OnCheck_WidthHeight(Resolver: TCSSBaseResolver): boolean;
|
|
|
-begin
|
|
|
- Result:=Resolver.CheckAttribute_Dimension(Chk_WidthHeight);
|
|
|
-end;
|
|
|
+ Div4:=TDemoDiv.Create(nil);
|
|
|
+ Div4.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoCSSRegistry.OnCompute_Direction(Resolver: TCSSResolver;
|
|
|
- Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
-var
|
|
|
- Invalid: boolean;
|
|
|
-begin
|
|
|
- if Resolver.ReadAttribute_Keyword(Invalid,Chk_DirectionAllowedKeywordIDs) then
|
|
|
- begin
|
|
|
- Value.Value:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
- Value.State:=cavsComputed;
|
|
|
- end
|
|
|
- else begin
|
|
|
- Value.Value:='invalid';
|
|
|
- Value.State:=cavsInvalid;
|
|
|
- end;
|
|
|
- if Node=nil then ;
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ 'div:nth-child(2n+1) { left: 8px; }',
|
|
|
+ 'div:nth-child(n+3) { border-width: 6px; }',
|
|
|
+ 'div:nth-child(-n+2) { height: 7em; }',
|
|
|
+ 'div:nth-child(even) { top: 3px; }',
|
|
|
+ 'div:nth-child(odd) { width: 4px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.BorderWidth','',Doc.Root.BorderWidth);
|
|
|
+ AssertEquals('Root.Height','',Doc.Root.Height);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Root.Width','',Doc.Root.Width);
|
|
|
+ AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
+ AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
+ AssertEquals('Div1.Height','7em',Div1.Height);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div1.Width','4px',Div1.Width);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.BorderWidth','',Div2.BorderWidth);
|
|
|
+ AssertEquals('Div2.Height','7em',Div2.Height);
|
|
|
+ AssertEquals('Div2.Top','3px',Div2.Top);
|
|
|
+ AssertEquals('Div2.Width','',Div2.Width);
|
|
|
+ AssertEquals('Div3.Left','8px',Div3.Left);
|
|
|
+ AssertEquals('Div3.BorderWidth','6px',Div3.BorderWidth);
|
|
|
+ AssertEquals('Div3.Height','',Div3.Height);
|
|
|
+ AssertEquals('Div3.Top','',Div3.Top);
|
|
|
+ AssertEquals('Div3.Width','4px',Div3.Width);
|
|
|
+ AssertEquals('Div4.Left','',Div4.Left);
|
|
|
+ AssertEquals('Div4.BorderWidth','6px',Div4.BorderWidth);
|
|
|
+ AssertEquals('Div4.Height','',Div4.Height);
|
|
|
+ AssertEquals('Div4.Top','3px',Div4.Top);
|
|
|
+ AssertEquals('Div4.Width','',Div4.Width);
|
|
|
end;
|
|
|
|
|
|
-procedure TDemoCSSRegistry.OnCompute_LeftTop(Resolver: TCSSResolver;
|
|
|
- Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_NthLastChild;
|
|
|
var
|
|
|
- Invalid: boolean;
|
|
|
+ Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
begin
|
|
|
- if Resolver.ReadAttribute_Dimension(Invalid,Chk_LeftTop) then
|
|
|
- begin
|
|
|
- case Resolver.CurComp.Kind of
|
|
|
- rvkFloat:
|
|
|
- Value.Value:=Resolver.CurComp.FloatAsString;
|
|
|
- rvkKeyword:
|
|
|
- Value.Value:=Keywords[Resolver.CurComp.KeywordID];
|
|
|
- end;
|
|
|
- Value.State:=cavsComputed;
|
|
|
- end
|
|
|
- else begin
|
|
|
- Value.Value:='invalid';
|
|
|
- Value.State:=cavsInvalid;
|
|
|
- end;
|
|
|
- if Node=nil then ;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div3:=TDemoDiv.Create(nil);
|
|
|
+ Div3.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div4:=TDemoDiv.Create(nil);
|
|
|
+ Div4.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':nth-last-child(2n+1) { left: 8px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
+ AssertEquals('Div3.Left','',Div3.Left);
|
|
|
+ AssertEquals('Div4.Left','8px',Div4.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TDemoCSSRegistry.OnCompute_WidthHeight(Resolver: TCSSResolver;
|
|
|
- Node: TDemoNode; Value: TCSSAttributeValue);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_NthChildOf;
|
|
|
var
|
|
|
- Invalid: boolean;
|
|
|
+ Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
begin
|
|
|
- if Resolver.ReadAttribute_Dimension(Invalid,Chk_WidthHeight) then
|
|
|
- begin
|
|
|
- Value.Value:=Resolver.CurComp.FloatAsString;
|
|
|
- Value.State:=cavsComputed;
|
|
|
- end
|
|
|
- else begin
|
|
|
- Value.Value:='invalid';
|
|
|
- Value.State:=cavsInvalid;
|
|
|
- end;
|
|
|
- if Node=nil then ;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
-constructor TDemoCSSRegistry.Create;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- procedure SetDemoElementTypeID(aClass: TDemoNodeClass);
|
|
|
- var
|
|
|
- Desc: TCSSTypeDesc;
|
|
|
- begin
|
|
|
- Desc:=FindType(aClass.CSSTypeName);
|
|
|
- if Desc=nil then
|
|
|
- raise Exception.Create('20240625190912');
|
|
|
- aClass.SetClassCSSTypeID(Desc.Index);
|
|
|
- end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+ Div2.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
- procedure SetCompProps(ShorthandID: TDemoNodeAttribute; Longhands: array of TDemoNodeAttribute);
|
|
|
- var
|
|
|
- i: Integer;
|
|
|
- begin
|
|
|
- SetLength(DemoAttrs[ShorthandID].CompProps,length(Longhands));
|
|
|
- for i:=0 to length(Longhands)-1 do
|
|
|
- DemoAttrs[ShorthandID].CompProps[i]:=DemoAttrs[Longhands[i]];
|
|
|
- end;
|
|
|
+ Div3:=TDemoDiv.Create(nil);
|
|
|
+ Div3.Name:='Div3';
|
|
|
+ Div3.Parent:=Doc.Root;
|
|
|
+ Div3.ExplicitAttributes[naTop]:='3px';
|
|
|
+
|
|
|
+ Div4:=TDemoDiv.Create(nil);
|
|
|
+ Div4.Name:='Div4';
|
|
|
+ Div4.Parent:=Doc.Root;
|
|
|
+ Div4.ExplicitAttributes[naTop]:='3px';
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':nth-child(2n+1 of [top=3px]) { left: 5px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div2.Left','5px',Div2.Left);
|
|
|
+ AssertEquals('Div3.Left','',Div3.Left);
|
|
|
+ AssertEquals('Div4.Left','5px',Div4.Left);
|
|
|
+end;
|
|
|
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_FirstOfType;
|
|
|
var
|
|
|
- Attr: TDemoNodeAttribute;
|
|
|
- PseudoClass: TDemoPseudoClass;
|
|
|
- aType: TDemoElementType;
|
|
|
+ Div1, Div11, Div13, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
begin
|
|
|
- inherited Create;
|
|
|
- Init;
|
|
|
-
|
|
|
- // register demo attributes
|
|
|
- for Attr in TDemoNodeAttribute do
|
|
|
- AddDemoAttr(Attr);
|
|
|
- DemoAttrIDBase:=DemoAttrs[low(TDemoNodeAttribute)].Index;
|
|
|
- if FindAttribute(DemoAttributeNames[naBackground]).Index<>DemoAttrIDBase+ord(naBackground) then
|
|
|
- raise Exception.Create('20240617200337');
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
- // register demo pseudo classes
|
|
|
- for PseudoClass in TDemoPseudoClass do
|
|
|
- AddDemoPseudoClass(PseudoClass);
|
|
|
- DemoPseudoClassIDBase:=DemoPseudoClasses[low(TDemoPseudoClass)].Index;
|
|
|
- if FindPseudoClass(DemoPseudoClassNames[pcHover]).Index<>DemoPseudoClassIDBase+ord(pcHover) then
|
|
|
- raise Exception.Create('20231008232201');
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- // register demo element types
|
|
|
- for aType in TDemoElementType do
|
|
|
- AddDemoType(aType);
|
|
|
- DemoElementTypeIDBase:=DemoTypes[low(TDemoElementType)].Index;
|
|
|
- if FindType(DemoElementTypeNames[detButton]).Index<>DemoElementTypeIDBase+ord(detButton) then
|
|
|
- raise Exception.Create('20240625181725');
|
|
|
- SetDemoElementTypeID(TDemoNode);
|
|
|
- SetDemoElementTypeID(TDemoDiv);
|
|
|
- SetDemoElementTypeID(TDemoSpan);
|
|
|
- SetDemoElementTypeID(TDemoButton);
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
- kwRed:=AddKeyword('red');
|
|
|
- kwFirstColor:=kwRed;
|
|
|
- kwGreen:=AddKeyword('green');
|
|
|
- kwBlue:=AddKeyword('blue');
|
|
|
- kwWhite:=AddKeyword('white');
|
|
|
- kwBlack:=AddKeyword('black');
|
|
|
- kwLastColor:=kwBlack;
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Parent:=Div1;
|
|
|
|
|
|
- kwBlock:=AddKeyword('block');
|
|
|
- kwInline_Block:=AddKeyword('inline-block');
|
|
|
+ Div13:=TDemoDiv.Create(nil);
|
|
|
+ Div13.Parent:=Div1;
|
|
|
|
|
|
- kwLTR:=AddKeyword('ltr');
|
|
|
- kwRTL:=AddKeyword('rtl');
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
- // check parameters - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':first-of-type { left: 6px; }',
|
|
|
+ 'div:first-of-type { top: 7px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','6px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','7px',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','6px',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','7px',Div11.Top);
|
|
|
+ AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','',Button12.Top);
|
|
|
+ AssertEquals('Div13.Left','',Div13.Left);
|
|
|
+ AssertEquals('Div13.Top','',Div13.Top);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','',Div2.Top);
|
|
|
+end;
|
|
|
|
|
|
- // border-color
|
|
|
- DemoAttrs[naBorderColor].OnCheck:=@OnCheck_BorderColor;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_LastOfType;
|
|
|
+var
|
|
|
+ Div1, Div11, Div13, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
+begin
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
- // border-width
|
|
|
- DemoAttrs[naBorderWidth].OnCheck:=@OnCheck_BorderWidth;
|
|
|
- Chk_BorderWidth.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
- Chk_BorderWidth.AllowFrac:=true;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
- // border shorthand
|
|
|
- SetCompProps(naBorder,[naBorderColor,naBorderWidth]);
|
|
|
- DemoAttrs[naBorder].OnCheck:=@OnCheck_Border;
|
|
|
- DemoAttrs[naBorder].OnSplitShorthand:=@OnSplit_Border;
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
- // direction
|
|
|
- DemoAttrs[naDirection].OnCheck:=@OnCheck_Direction;
|
|
|
- Chk_DirectionAllowedKeywordIDs:=[kwLTR,kwRTL];
|
|
|
- DemoAttrs[naDirection].OnCompute:=@OnCompute_Direction;
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Parent:=Div1;
|
|
|
|
|
|
- // display
|
|
|
- DemoAttrs[naDisplay].OnCheck:=@OnCheck_Display;
|
|
|
- Chk_DisplayAllowedKeywordIDs:=[kwBlock,kwInline_Block];
|
|
|
+ Div13:=TDemoDiv.Create(nil);
|
|
|
+ Div13.Parent:=Div1;
|
|
|
|
|
|
- // left, top
|
|
|
- DemoAttrs[naLeft].OnCheck:=@OnCheck_LeftTop;
|
|
|
- DemoAttrs[naLeft].OnCompute:=@OnCompute_LeftTop;
|
|
|
- DemoAttrs[naTop].OnCheck:=@OnCheck_LeftTop;
|
|
|
- DemoAttrs[naTop].OnCompute:=@OnCompute_LeftTop;
|
|
|
- Chk_LeftTop.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
- Chk_LeftTop.AllowNegative:=true;
|
|
|
- Chk_LeftTop.AllowFrac:=true;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
- // width, height
|
|
|
- DemoAttrs[naWidth].OnCheck:=@OnCheck_WidthHeight;
|
|
|
- DemoAttrs[naWidth].OnCompute:=@OnCompute_WidthHeight;
|
|
|
- DemoAttrs[naHeight].OnCheck:=@OnCheck_WidthHeight;
|
|
|
- DemoAttrs[naHeight].OnCompute:=@OnCompute_WidthHeight;
|
|
|
- Chk_WidthHeight.AllowedUnits:=[cuNONE,cuPERCENT]+cuAllLengths;
|
|
|
- Chk_WidthHeight.AllowFrac:=true;
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':last-of-type { left: 6px; }',
|
|
|
+ 'div:last-of-type { top: 7px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','',Div11.Top);
|
|
|
+ AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','',Button12.Top);
|
|
|
+ AssertEquals('Div13.Left','6px',Div13.Left);
|
|
|
+ AssertEquals('Div13.Top','7px',Div13.Top);
|
|
|
+ AssertEquals('Div2.Left','6px',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','7px',Div2.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoCSSRegistry.AddDemoAttr(Attr: TDemoNodeAttribute
|
|
|
- ): TDemoCSSAttributeDesc;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_OnlyOfType;
|
|
|
+var
|
|
|
+ Div1, Div11, Div2: TDemoDiv;
|
|
|
+ Button12: TDemoButton;
|
|
|
begin
|
|
|
- Result:=TDemoCSSAttributeDesc(AddAttribute(DemoAttributeNames[Attr],
|
|
|
- DemoAttributeInitialValues[Attr],
|
|
|
- Attr in DemoAttributesInherited,
|
|
|
- not (Attr in DemoAttributesNotAll),
|
|
|
- TDemoCSSAttributeDesc));
|
|
|
- Result.DemoID:=Attr;
|
|
|
- DemoAttrs[Attr]:=Result;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoCSSRegistry.AddDemoPseudoClass(PC: TDemoPseudoClass
|
|
|
- ): TDemoCSSPseudoClassDesc;
|
|
|
-begin
|
|
|
- Result:=TDemoCSSPseudoClassDesc(AddPseudoClass(DemoPseudoClassNames[PC],
|
|
|
- TDemoCSSPseudoClassDesc));
|
|
|
- Result.DemoID:=PC;
|
|
|
- DemoPseudoClasses[PC]:=Result;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-function TDemoCSSRegistry.AddDemoType(aType: TDemoElementType
|
|
|
- ): TDemoCSSTypeDesc;
|
|
|
-begin
|
|
|
- Result:=TDemoCSSTypeDesc(AddType(DemoElementTypeNames[aType],
|
|
|
- TDemoCSSTypeDesc));
|
|
|
- Result.DemoID:=aType;
|
|
|
- DemoTypes[aType]:=Result;
|
|
|
-end;
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Parent:=Div1;
|
|
|
|
|
|
-{ TDemoNode }
|
|
|
+ Button12:=TDemoButton.Create(nil);
|
|
|
+ Button12.Parent:=Div1;
|
|
|
|
|
|
-function TDemoNode.GetAttribute(DemoAttr: TDemoNodeAttribute): TCSSString;
|
|
|
-var
|
|
|
- AttrDesc: TDemoCSSAttributeDesc;
|
|
|
- i: Integer;
|
|
|
-begin
|
|
|
- AttrDesc:=CSSRegistry.DemoAttrs[DemoAttr];
|
|
|
- i:=Values.IndexOf(AttrDesc.Index);
|
|
|
- if i>=0 then
|
|
|
- Result:=Values.Values[i].Value
|
|
|
- else
|
|
|
- Result:='';
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':only-of-type { left: 6px; }',
|
|
|
+ 'div:only-of-type { top: 7px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','6px',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Div11.Left','6px',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','7px',Div11.Top);
|
|
|
+ AssertEquals('Button12.Left','6px',Button12.Left);
|
|
|
+ AssertEquals('Button12.Top','',Button12.Top);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div2.Top','',Div2.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetNodeCount: integer;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_NthOfType;
|
|
|
+var
|
|
|
+ Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
+ Button1, Button2: TDemoButton;
|
|
|
begin
|
|
|
- Result:=FNodes.Count;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div3:=TDemoDiv.Create(nil);
|
|
|
+ Div3.Name:='Div3';
|
|
|
+ Div3.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.Name:='Button2';
|
|
|
+ Button2.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Div4:=TDemoDiv.Create(nil);
|
|
|
+ Div4.Name:='Div4';
|
|
|
+ Div4.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':nth-of-type(2n+1) { left: 8px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','8px',Div1.Left);
|
|
|
+ AssertEquals('Button1.Left','8px',Button1.Left);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Div3.Left','8px',Div3.Left);
|
|
|
+ AssertEquals('Button2.Left','',Button2.Left);
|
|
|
+ AssertEquals('Div4.Left','',Div4.Left);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetNodes(Index: integer): TDemoNode;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_NthLastOfType;
|
|
|
+var
|
|
|
+ Div1, Div2, Div3, Div4: TDemoDiv;
|
|
|
+ Button1, Button2: TDemoButton;
|
|
|
begin
|
|
|
- Result:=TDemoNode(FNodes[Index]);
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoNode.GetPseudoClasses(PseudoClass: TDemoPseudoClass): boolean;
|
|
|
-begin
|
|
|
- Result:=FPseudoClasses[PseudoClass];
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoNode.SetParent(const AValue: TDemoNode);
|
|
|
-begin
|
|
|
- if FParent=AValue then Exit;
|
|
|
- if AValue=Self then
|
|
|
- raise Exception.Create('cycle');
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- if FParent<>nil then
|
|
|
- begin
|
|
|
- FParent.FNodes.Remove(Self);
|
|
|
- end;
|
|
|
- FParent:=AValue;
|
|
|
- if FParent<>nil then
|
|
|
- begin
|
|
|
- FParent.FNodes.Add(Self);
|
|
|
- FreeNotification(FParent);
|
|
|
- end;
|
|
|
-end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoNode.SetInlineStyleElements(const AValue: TCSSRuleElement);
|
|
|
-begin
|
|
|
- if FInlineStyleElements=AValue then Exit;
|
|
|
- FreeAndNil(FInlineStyleElements);
|
|
|
- FInlineStyleElements:=AValue;
|
|
|
-end;
|
|
|
+ Div3:=TDemoDiv.Create(nil);
|
|
|
+ Div3.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoNode.SetInlineStyle(const AValue: TCSSString);
|
|
|
-begin
|
|
|
- if FInlineStyle=AValue then Exit;
|
|
|
- FInlineStyle:=AValue;
|
|
|
- FreeAndNil(FInlineStyleElements);
|
|
|
-end;
|
|
|
+ Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoNode.SetPseudoClasses(PseudoClass: TDemoPseudoClass;
|
|
|
- const AValue: boolean);
|
|
|
-begin
|
|
|
- FPseudoClasses[PseudoClass]:=AValue;
|
|
|
-end;
|
|
|
+ Div4:=TDemoDiv.Create(nil);
|
|
|
+ Div4.Parent:=Doc.Root;
|
|
|
|
|
|
-procedure TDemoNode.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
-begin
|
|
|
- inherited Notification(AComponent, Operation);
|
|
|
- if AComponent=Self then exit;
|
|
|
- if Operation=opRemove then
|
|
|
- begin
|
|
|
- if FNodes<>nil then
|
|
|
- FNodes.Remove(AComponent);
|
|
|
- end;
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':nth-last-of-type(2n+1) { left: 8px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','',Div1.Left);
|
|
|
+ AssertEquals('Button1.Left','',Button1.Left);
|
|
|
+ AssertEquals('Div2.Left','8px',Div2.Left);
|
|
|
+ AssertEquals('Div3.Left','',Div3.Left);
|
|
|
+ AssertEquals('Button2.Left','8px',Button2.Left);
|
|
|
+ AssertEquals('Div4.Left','8px',Div4.Left);
|
|
|
end;
|
|
|
|
|
|
-constructor TDemoNode.Create(AOwner: TComponent);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Is;
|
|
|
+var
|
|
|
+ Div1, Div2: TDemoDiv;
|
|
|
+ Button1, Button2: TDemoButton;
|
|
|
+ Span1: TDemoSpan;
|
|
|
begin
|
|
|
- inherited Create(AOwner);
|
|
|
- FNodes:=TFPObjectList.Create(false);
|
|
|
- FCSSClasses:=TStringList.Create;
|
|
|
- FCSSClasses.Delimiter:=' ';
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
-destructor TDemoNode.Destroy;
|
|
|
-begin
|
|
|
- Clear;
|
|
|
- FreeAndNil(FNodes);
|
|
|
- FreeAndNil(FCSSClasses);
|
|
|
- inherited Destroy;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
-procedure TDemoNode.Clear;
|
|
|
-var
|
|
|
- i: Integer;
|
|
|
-begin
|
|
|
- Rules:=nil;
|
|
|
- FreeAndNil(Values);
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Doc.Root;
|
|
|
|
|
|
- FCSSClasses.Clear;
|
|
|
- FreeAndNil(FInlineStyleElements);
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
|
|
|
- for i:=NodeCount-1 downto 0 do
|
|
|
- Nodes[i].Free;
|
|
|
- if FNodes.Count>0 then
|
|
|
- raise Exception.Create('20240710174459');
|
|
|
+ Span1:=TDemoSpan.Create(nil);
|
|
|
+ Span1.Parent:=Doc.Root;
|
|
|
+ Span1.ExplicitAttributes[naTop]:='3px';
|
|
|
+
|
|
|
+ Button2:=TDemoButton.Create(nil);
|
|
|
+ Button2.Parent:=Doc.Root;
|
|
|
+ Button2.ExplicitAttributes[naTop]:='3px';
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':is(div, button)[top=3px] { left: 7px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','7px',Div1.Left);
|
|
|
+ AssertEquals('Button1.Left','',Button1.Left);
|
|
|
+ AssertEquals('Div2.Left','',Div2.Left);
|
|
|
+ AssertEquals('Span1.Left','',Div2.Left);
|
|
|
+ AssertEquals('Button2.Left','7px',Button2.Left);
|
|
|
end;
|
|
|
|
|
|
-procedure TDemoNode.ApplyCSS(Resolver: TCSSResolver);
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Where;
|
|
|
var
|
|
|
- AttrDesc: TDemoCSSAttributeDesc;
|
|
|
- i: Integer;
|
|
|
- AttrID: TCSSNumericalID;
|
|
|
- CurValue: TCSSAttributeValue;
|
|
|
+ Div1, Div2: TDemoDiv;
|
|
|
begin
|
|
|
- if (InlineStyleElement=nil) and (InlineStyle<>'') then
|
|
|
- InlineStyleElement:=Resolver.ParseInlineStyle(InlineStyle) as TCSSRuleElement;
|
|
|
-
|
|
|
- Resolver.Compute(Self,InlineStyleElement,Rules,Values);
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
- {$IFDEF VerboseCSSResolver}
|
|
|
- writeln('TDemoNode.ApplyCSS ',Name,' length(Values)=',length(Values.Values),' All="',CSSRegistry.Keywords[Values.AllValue],'"');
|
|
|
- for i:=0 to length(Values.Values)-1 do begin
|
|
|
- AttrID:=Values.Values[i].AttrID;
|
|
|
- writeln('TDemoNode.ApplyCSS ',Name,' resolved ',CSSRegistry.Attributes[AttrID].Name,'/',AttrID,':="',Values.Values[i].Value,'"');
|
|
|
- end;
|
|
|
- {$ENDIF}
|
|
|
- // compute values
|
|
|
- for i:=0 to length(Values.Values)-1 do
|
|
|
- begin
|
|
|
- CurValue:=Values.Values[i];
|
|
|
- case CurValue.State of
|
|
|
- cavsSource, cavsBaseKeywords:
|
|
|
- begin
|
|
|
- AttrID:=CurValue.AttrID;
|
|
|
- AttrDesc:=CSSRegistry.Attributes[AttrID] as TDemoCSSAttributeDesc;
|
|
|
- if AttrDesc.OnCompute<>nil then
|
|
|
- begin
|
|
|
- Resolver.CurComp.EndP:=PChar(CurValue.Value);
|
|
|
- Resolver.ReadNext;
|
|
|
- AttrDesc.OnCompute(Resolver,Self,CurValue);
|
|
|
- {$IFDEF VerboseCSSResolver}
|
|
|
- writeln('TDemoNode.ApplyCSS ',Name,' computed ',CSSRegistry.Attributes[AttrID].Name,'/',AttrID,':="',CurValue.Value,'"');
|
|
|
- {$ENDIF}
|
|
|
- end else
|
|
|
- CurValue.State:=cavsComputed;
|
|
|
- end;
|
|
|
- cavsComputed: ;
|
|
|
- cavsInvalid: ;
|
|
|
- end;
|
|
|
- end;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
-function TDemoNode.GetCSSID: TCSSString;
|
|
|
-begin
|
|
|
- Result:=Name;
|
|
|
-end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Div1;
|
|
|
+ Div2.ExplicitAttributes[naTop]:='3px';
|
|
|
|
|
|
-class function TDemoNode.CSSTypeName: TCSSString;
|
|
|
-begin
|
|
|
- Result:=DemoElementTypeNames[detNode];
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':where(div[top=3px]) { left: 1px; }',
|
|
|
+ 'div div { left: 2px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
+ AssertEquals('Div2.Left','2px',Div2.Left);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.HasCSSClass(const aClassName: TCSSString): boolean;
|
|
|
+procedure TTestNewCSSResolver.Test_Selector_Hover;
|
|
|
var
|
|
|
- i: Integer;
|
|
|
+ Div1, Div11: TDemoDiv;
|
|
|
+ Button1: TDemoButton;
|
|
|
begin
|
|
|
- for i:=0 to CSSClasses.Count-1 do
|
|
|
- if aClassName=CSSClasses[i] then
|
|
|
- exit(true);
|
|
|
- Result:=false;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+ Doc.Root.Name:='root';
|
|
|
|
|
|
-function TDemoNode.GetCSSParent: ICSSNode;
|
|
|
-begin
|
|
|
- Result:=Parent;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.Hover:=true;
|
|
|
|
|
|
-function TDemoNode.GetCSSIndex: integer;
|
|
|
-begin
|
|
|
- if Parent=nil then
|
|
|
- Result:=-1
|
|
|
- else
|
|
|
- Result:=Parent.FNodes.IndexOf(Self);
|
|
|
-end;
|
|
|
+ Button1:=TDemoButton.Create(nil);
|
|
|
+ Button1.Name:='Button1';
|
|
|
+ Button1.Parent:=Div1;
|
|
|
+ Button1.Hover:=true;
|
|
|
|
|
|
-function TDemoNode.GetCSSNextSibling: ICSSNode;
|
|
|
-var
|
|
|
- i: Integer;
|
|
|
-begin
|
|
|
- i:=GetCSSIndex;
|
|
|
- if (i<0) or (i+1>=Parent.NodeCount) then
|
|
|
- Result:=nil
|
|
|
- else
|
|
|
- Result:=Parent.Nodes[i+1];
|
|
|
+ Div11:=TDemoDiv.Create(nil);
|
|
|
+ Div11.Name:='Div11';
|
|
|
+ Div11.Parent:=Div1;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ ':hover { left: 1px; }',
|
|
|
+ 'button:hover { top: 2px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Root.Top','',Doc.Root.Top);
|
|
|
+ AssertEquals('Div1.Left','1px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','',Div1.Top);
|
|
|
+ AssertEquals('Button1.Left','1px',Button1.Left);
|
|
|
+ AssertEquals('Button1.Top','2px',Button1.Top);
|
|
|
+ AssertEquals('Div11.Left','',Div11.Left);
|
|
|
+ AssertEquals('Div11.Top','',Div11.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSPreviousSibling: ICSSNode;
|
|
|
+procedure TTestNewCSSResolver.Test_InlineStyle;
|
|
|
var
|
|
|
- i: Integer;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- i:=GetCSSIndex;
|
|
|
- if i<1 then
|
|
|
- Result:=nil
|
|
|
- else
|
|
|
- Result:=Parent.Nodes[i-1];
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoNode.GetCSSChildCount: integer;
|
|
|
-begin
|
|
|
- Result:=NodeCount;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.InlineStyle:='left: 10px; top: 5px';
|
|
|
|
|
|
-function TDemoNode.GetCSSChild(const anIndex: integer): ICSSNode;
|
|
|
-begin
|
|
|
- Result:=Nodes[anIndex];
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ 'div { left: 6px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','10px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','5px',Div1.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSNextOfType: ICSSNode;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Id_Class;
|
|
|
var
|
|
|
- i, Cnt: Integer;
|
|
|
- MyID: TCSSNumericalID;
|
|
|
- aNode: TDemoNode;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- Result:=nil;
|
|
|
- i:=GetCSSIndex;
|
|
|
- if i<0 then exit;
|
|
|
- inc(i);
|
|
|
- MyID:=GetClassCSSTypeID;
|
|
|
- Cnt:=Parent.NodeCount;
|
|
|
- while i<Cnt do
|
|
|
- begin
|
|
|
- aNode:=Parent.Nodes[i];
|
|
|
- if aNode.GetClassCSSTypeID=MyID then
|
|
|
- exit(aNode);
|
|
|
- inc(i);
|
|
|
- end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '.bird { left: 6px; }',
|
|
|
+ '#Div1 { left: 7px; top: 8px; }', // id has higher specifity, no matter if before or after a .class
|
|
|
+ '.bird { top: 9px; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','7px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','8px',Div1.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSPreviousOfType: ICSSNode;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Important;
|
|
|
var
|
|
|
- i: Integer;
|
|
|
- MyID: TCSSNumericalID;
|
|
|
- aNode: TDemoNode;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- Result:=nil;
|
|
|
- i:=GetCSSIndex;
|
|
|
- if i<0 then exit;
|
|
|
- dec(i);
|
|
|
- MyID:=GetClassCSSTypeID;
|
|
|
- while i>=0 do
|
|
|
- begin
|
|
|
- aNode:=Parent.Nodes[i];
|
|
|
- if aNode.GetClassCSSTypeID=MyID then
|
|
|
- exit(aNode);
|
|
|
- dec(i);
|
|
|
- end;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoNode.GetCSSAttributeClass: TCSSString;
|
|
|
-begin
|
|
|
- FCSSClasses.Delimiter:=' ';
|
|
|
- Result:=FCSSClasses.DelimitedText;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '.bird { left: 6px !important; }',
|
|
|
+ '#Div1 { left: 7px; top: 8px; }',
|
|
|
+ '.bird { top: 9px ! important; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Root.Left','',Doc.Root.Left);
|
|
|
+ AssertEquals('Div1.Left','6px',Div1.Left);
|
|
|
+ AssertEquals('Div1.Top','9px',Div1.Top);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.HasCSSExplicitAttribute(const AttrID: TCSSNumericalID): boolean;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Shorthand_OneRule;
|
|
|
var
|
|
|
- b: TCSSNumericalID;
|
|
|
- Attr: TDemoNodeAttribute;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- b:=CSSRegistry.DemoAttrIDBase;
|
|
|
- if (AttrID<b) or (AttrID>b+ord(High(TDemoNodeAttribute))) then
|
|
|
- exit(false);
|
|
|
- Attr:=TDemoNodeAttribute(AttrID-b);
|
|
|
- Result:=ExplicitAttributes[Attr]<>'';
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
+
|
|
|
+ Doc.Style:='.bird { border-color: blue; border: 6px red; border-width: 7px; }';
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','red',Div1.BorderColor);
|
|
|
+ AssertEquals('Div1.BorderWidth','7px',Div1.BorderWidth);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSExplicitAttribute(const AttrID: TCSSNumericalID): TCSSString;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Shorthand_ClassClass;
|
|
|
var
|
|
|
- Attr: TDemoNodeAttribute;
|
|
|
- b: TCSSNumericalID;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- b:=CSSRegistry.DemoAttrIDBase;
|
|
|
- if (AttrID<b) or (AttrID>b+ord(High(TDemoNodeAttribute))) then
|
|
|
- exit('');
|
|
|
- Attr:=TDemoNodeAttribute(AttrID-b);
|
|
|
- Result:=ExplicitAttributes[Attr];
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
+ Div1.CSSClasses.Add('eagle');
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '.bird.eagle { border-color: blue; }',
|
|
|
+ '.bird { border-width: 6px; }',
|
|
|
+ '.bird { border: 7px red; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
+ AssertEquals('Div1.BorderWidth','7px',Div1.BorderWidth);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.HasCSSPseudoClass(const AttrID: TCSSNumericalID): boolean;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Longhand_All_Longhand;
|
|
|
var
|
|
|
- b: TCSSNumericalID;
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- b:=CSSRegistry.DemoPseudoClassIDBase;
|
|
|
- if (AttrID>=b) and (AttrID<=b+ord(High(TDemoPseudoClass))) then
|
|
|
- Result:=HasPseudoClass[TDemoPseudoClass(AttrID-b)]
|
|
|
- else
|
|
|
- Result:=false;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoNode.GetCSSEmpty: boolean;
|
|
|
-begin
|
|
|
- Result:=NodeCount=0;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
+ Div1.CSSClasses.Add('eagle');
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '.bird.eagle { border-color: blue; }',
|
|
|
+ '.bird { border-width: 7px; }',
|
|
|
+ '.bird { all: initial; }',
|
|
|
+ '.bird { background: red; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
+ AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
+ AssertEquals('Div1.Background','red',Div1.Background);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSDepth: integer;
|
|
|
+procedure TTestNewCSSResolver.Test_Specifity_Shorthand_All_Shorthand;
|
|
|
var
|
|
|
- Node: TDemoNode;
|
|
|
+ Div1, Div2: TDemoDiv;
|
|
|
begin
|
|
|
- Result:=0;
|
|
|
- Node:=Parent;
|
|
|
- while Node<>nil do
|
|
|
- begin
|
|
|
- inc(Result);
|
|
|
- Node:=Node.Parent;
|
|
|
- end;
|
|
|
-end;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
|
|
|
-function TDemoNode.GetCSSTypeName: TCSSString;
|
|
|
-begin
|
|
|
- Result:=CSSTypeName;
|
|
|
-end;
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+ Div1.CSSClasses.Add('bird');
|
|
|
|
|
|
-class function TDemoNode.GetClassCSSTypeID: TCSSNumericalID;
|
|
|
-begin
|
|
|
- Result:=FDemoNodeTypeID;
|
|
|
-end;
|
|
|
+ Div2:=TDemoDiv.Create(nil);
|
|
|
+ Div2.Name:='Div2';
|
|
|
+ Div2.Parent:=Doc.Root;
|
|
|
+ Div2.CSSClasses.Add('eagle');
|
|
|
|
|
|
-class procedure TDemoNode.SetClassCSSTypeID(aID: TCSSNumericalID);
|
|
|
-begin
|
|
|
- FDemoNodeTypeID:=aID;
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ '.bird { border: 7px blue; }',
|
|
|
+ '.bird { all: initial; }',
|
|
|
+ '.eagle { all: initial; }',
|
|
|
+ '.eagle { border: 8px red; }',
|
|
|
+ '']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','',Div1.BorderColor);
|
|
|
+ AssertEquals('Div1.BorderWidth','',Div1.BorderWidth);
|
|
|
+ AssertEquals('Div2.BorderColor','red',Div2.BorderColor);
|
|
|
+ AssertEquals('Div2.BorderWidth','8px',Div2.BorderWidth);
|
|
|
end;
|
|
|
|
|
|
-function TDemoNode.GetCSSTypeID: TCSSNumericalID;
|
|
|
+procedure TTestNewCSSResolver.Test_Origin_Id_Class;
|
|
|
+var
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- Result:=GetClassCSSTypeID;
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.CSSResolver.AddStyleSheet(cssoUserAgent,'testagent',
|
|
|
+ '#Div1 { border-width: 2px;'
|
|
|
+ +' border-color: blue !important;'
|
|
|
+ +' background: green; }'
|
|
|
+ );
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ 'div { border-width: 3px; ', // although class has lower spec than id, author origin wins
|
|
|
+ ' border-color: orange;', // former important always wins
|
|
|
+ '}']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','blue',Div1.BorderColor);
|
|
|
+ AssertEquals('Div1.BorderWidth','3px',Div1.BorderWidth);
|
|
|
+ AssertEquals('Div1.Background','green',Div1.Background);
|
|
|
end;
|
|
|
|
|
|
-class function TDemoNode.GetCSSTypeStyle: TCSSString;
|
|
|
+procedure TTestNewCSSResolver.Test_Var;
|
|
|
+var
|
|
|
+ Div1: TDemoDiv;
|
|
|
begin
|
|
|
- Result:='';
|
|
|
+ exit;
|
|
|
+
|
|
|
+ Doc.Root:=TDemoNode.Create(nil);
|
|
|
+
|
|
|
+ Div1:=TDemoDiv.Create(nil);
|
|
|
+ Div1.Name:='Div1';
|
|
|
+ Div1.Parent:=Doc.Root;
|
|
|
+
|
|
|
+ Doc.Style:=LinesToStr([
|
|
|
+ 'div {',
|
|
|
+ ' --bird-color: red;',
|
|
|
+ '}',
|
|
|
+ 'div {',
|
|
|
+ ' border-color: var(--bird-color);',
|
|
|
+ ' border-width: var(--bird-width);',
|
|
|
+ '}',
|
|
|
+ 'div {',
|
|
|
+ ' --bird-width: 3px;',
|
|
|
+ '}']);
|
|
|
+ ApplyStyle;
|
|
|
+ AssertEquals('Div1.BorderColor','red',Div1.BorderColor);
|
|
|
end;
|
|
|
|
|
|
initialization
|