Prechádzať zdrojové kódy

fcl-css: empty and class

mattias 2 rokov pred
rodič
commit
7ce609e721

+ 24 - 12
packages/fcl-css/src/fpcssresolver.pas

@@ -47,7 +47,8 @@ const
   CSSIDNone = 0;
   CSSTypeID_Universal = 1; // id of type '*'
   CSSAttributeID_ID = 1; // id of attribute key 'id'
-  CSSAttributeID_All = 2; // id of attribute key 'all'
+  CSSAttributeID_Class = 2; // id of attribute key 'class'
+  CSSAttributeID_All = 3; // id of attribute key 'all'
   // pseudo attribute IDs
   CSSPseudoID_Root = 1; // :root
   CSSPseudoID_Empty = 2; // :empty
@@ -82,6 +83,7 @@ type
     function GetCSSTypeName: TCSSString;
     function GetCSSTypeID: TCSSNumericalID;
     function HasCSSClass(const aClassName: TCSSString): boolean;
+    function GetCSSAttributeClass: TCSSString;
     function GetCSSParent: TCSSNode;
     function GetCSSIndex: integer; // node index in parent's children
     function GetCSSNextSibling: TCSSNode;
@@ -94,6 +96,7 @@ type
     function GetCSSAttribute(const AttrID: TCSSNumericalID): TCSSString;
     function HasCSSPseudoAttribute(const AttrID: TCSSNumericalID): boolean;
     function GetCSSPseudoAttribute(const AttrID: TCSSNumericalID): TCSSString;
+    function GetCSSEmpty: boolean;
     procedure SetCSSValue(AttrID: TCSSNumericalID; Value: TCSSElement);
   end;
 
@@ -418,7 +421,7 @@ begin
     if TestNode.GetCSSParent=nil then
       Result:=CSSSpecifityClass;
   CSSPseudoID_Empty:
-    if TestNode.GetCSSChildCount=0 then
+    if TestNode.GetCSSEmpty then
       Result:=CSSSpecifityClass;
   CSSPseudoID_FirstChild:
     if TestNode.GetCSSPreviousSibling=nil then
@@ -564,10 +567,15 @@ begin
     // [name]  ->  has attribute name
     AttrID:=ResolveIdentifier(TCSSIdentifierElement(El),nikAttribute);
     case AttrID of
-    CSSIDNone,
-    CSSAttributeID_All: Result:=CSSSpecifityNoMatch;
-    CSSAttributeID_ID:
+    CSSIDNone:
+      Result:=CSSSpecifityNoMatch;
+    CSSAttributeID_ID,
+    CSSAttributeID_Class:
+      // basic CSS attributes are always defined
       Result:=CSSSpecifityClass;
+    CSSAttributeID_All:
+      // special CSS attributes without a value
+      Result:=CSSSpecifityNoMatch;
     else
       if TestNode.HasCSSAttribute(AttrID) then
         Result:=CSSSpecifityClass
@@ -597,10 +605,12 @@ begin
   writeln('TCSSResolver.SelectorArrayBinaryMatches AttrID=',AttrID,' Value=',TCSSIdentifierElement(Left).Value);
   {$ENDIF}
   case AttrID of
-  CSSIDNone,
-  CSSAttributeID_All: exit(CSSSpecifityNoMatch);
+  CSSIDNone: exit(CSSSpecifityNoMatch);
   CSSAttributeID_ID:
     LeftValue:=TestNode.GetCSSID;
+  CSSAttributeID_Class:
+    LeftValue:=TestNode.GetCSSAttributeClass;
+  CSSAttributeID_All: exit(CSSSpecifityNoMatch);
   else
     LeftValue:=TestNode.GetCSSAttribute(AttrID);
   end;
@@ -623,20 +633,21 @@ begin
       Result:=CSSSpecifityClass;
   boSquaredEqual:
     // begins with
-    if LeftStr(LeftValue,length(RightValue))=RightValue then
+    if (RightValue<>'') and (LeftStr(LeftValue,length(RightValue))=RightValue) then
       Result:=CSSSpecifityClass;
   boDollarEqual:
     // ends with
-    if RightStr(LeftValue,length(RightValue))=RightValue then
+    if (RightValue<>'') and (RightStr(LeftValue,length(RightValue))=RightValue) then
       Result:=CSSSpecifityClass;
   boPipeEqual:
     // equal to or starts with name-hyphen
-    if (LeftValue=RightValue)
-        or (LeftStr(LeftValue,length(RightValue)+1)=RightValue+'-') then
+    if (RightValue<>'')
+        and ((LeftValue=RightValue)
+          or (LeftStr(LeftValue,length(RightValue)+1)=RightValue+'-')) then
       Result:=CSSSpecifityClass;
   boStarEqual:
     // contains substring
-    if Pos(RightValue,LeftValue)>0 then
+    if (RightValue<>'') and (Pos(RightValue,LeftValue)>0) then
       Result:=CSSSpecifityClass;
   boTileEqual:
     // contains word
@@ -799,6 +810,7 @@ begin
     nikAttribute:
       case aName of
       'id': Result:=CSSAttributeID_ID;
+      'class': Result:=CSSAttributeID_Class;
       'all': Result:=CSSAttributeID_All;
       end;
     nikPseudoAttribute:

+ 16 - 0
packages/fcl-css/tests/tccssresolver.pp

@@ -99,10 +99,12 @@ type
     function GetCSSChild(const anIndex: integer): TCSSNode; virtual;
     function GetCSSNextOfType: TCSSNode; virtual;
     function GetCSSPreviousOfType: TCSSNode; virtual;
+    function GetCSSAttributeClass: TCSSString; virtual;
     function HasCSSAttribute(const AttrID: TCSSNumericalID): boolean; virtual;
     function GetCSSAttribute(const AttrID: TCSSNumericalID): TCSSString; virtual;
     function HasCSSPseudoAttribute(const AttrID: TCSSNumericalID): boolean; virtual;
     function GetCSSPseudoAttribute(const AttrID: TCSSNumericalID): TCSSString; virtual;
+    function GetCSSEmpty: boolean; virtual;
     property Parent: TDemoNode read FParent write SetParent;
     property NodeCount: integer read GetNodeCount;
     property Nodes[Index: integer]: TDemoNode read GetNodes; default;
@@ -516,13 +518,16 @@ begin
   Button1:=TDemoButton.Create(Doc);
   Button1.Parent:=Doc.Root;
   Button1.Left:='3px';
+  Button1.Color:='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);
 end;
 
 procedure TTestCSSResolver.Test_Selector_AttributeBeginsWith;
@@ -1322,6 +1327,12 @@ begin
   end;
 end;
 
+function TDemoNode.GetCSSAttributeClass: TCSSString;
+begin
+  FCSSClasses.Delimiter:=' ';
+  Result:=FCSSClasses.DelimitedText;
+end;
+
 function TDemoNode.HasCSSAttribute(const AttrID: TCSSNumericalID): boolean;
 begin
   Result:=(AttrID>=DemoAttrIDBase) and (AttrID<=DemoAttrIDBase+ord(High(TDemoNodeAttribute)));
@@ -1349,6 +1360,11 @@ begin
   Result:='';
 end;
 
+function TDemoNode.GetCSSEmpty: boolean;
+begin
+  Result:=NodeCount=0;
+end;
+
 function TDemoNode.GetCSSTypeName: TCSSString;
 begin
   Result:=CSSTypeName;