Ver Fonte

Dirty styles when attributes change

Michael Ragazzon há 3 anos atrás
pai
commit
a85be1e344
2 ficheiros alterados com 12 adições e 4 exclusões
  1. 4 2
      Source/Core/Element.cpp
  2. 8 2
      Tests/Source/UnitTests/Selectors.cpp

+ 4 - 2
Source/Core/Element.cpp

@@ -1671,12 +1671,10 @@ void Element::OnAttributeChange(const ElementAttributes& changed_attributes)
 		if (attribute == "id")
 		{
 			id = value.Get<String>();
-			DirtyDefinition(DirtyNodes::SelfAndSiblings);
 		}
 		else if (attribute == "class")
 		{
 			meta->style.SetClassNames(value.Get<String>());
-			DirtyDefinition(DirtyNodes::SelfAndSiblings);
 		}
 		else if (((attribute == "colspan" || attribute == "rowspan") && meta->computed_values.display() == Style::Display::TableCell)
 			|| (attribute == "span" && (meta->computed_values.display() == Style::Display::TableColumn || meta->computed_values.display() == Style::Display::TableColumnGroup)))
@@ -1727,6 +1725,10 @@ void Element::OnAttributeChange(const ElementAttributes& changed_attributes)
 				Log::Message(Log::LT_WARNING, "Invalid 'style' attribute, string type required. In element: %s", GetAddress().c_str());
 		}
 	}
+
+	// Any change to the attributes may affect which styles apply to the current element, in particular due to attribute selectors, ID selectors, and
+	// class selectors. This can further affect all siblings or descendants due to sibling or descendant combinators.
+	DirtyDefinition(DirtyNodes::SelfAndSiblings);
 }
 
 // Called when properties on the element are changed.

+ 8 - 2
Tests/Source/UnitTests/Selectors.cpp

@@ -72,7 +72,7 @@ static const String doc_end = R"(
 </rml>
 )";
 
-enum class SelectorOp { None, RemoveElementsByIds, InsertElementBefore, RemoveClasses, RemoveId, RemoveChecked, SetHover };
+enum class SelectorOp { None, RemoveElementsByIds, InsertElementBefore, RemoveClasses, RemoveId, RemoveChecked, RemoveAttributeUnit, SetHover };
 
 struct QuerySelector {
 	QuerySelector(String selector, String expected_ids, int expect_num_warnings = 0, int expect_num_query_warnings = 0) :
@@ -114,7 +114,6 @@ static const Vector<QuerySelector> query_selectors =
 	{ "*.hello",                     "X Z H" },
 	{ "*:checked",                   "I" },
 	
-	{ "p[unit=m]",                   "B" },
 	{ "p[unit='m']",                 "B" },
 	{ "p[unit=\"m\"]",               "B" },
 	{ "[class]",                     "X Y Z P F0 G H" },
@@ -216,6 +215,9 @@ static const Vector<QuerySelector> query_selectors =
 	{ ":not(:hover) + #P #D1",       "D1",              SelectorOp::SetHover,             "Z", ""  },
 	{ "#X + #Y",                     "Y",               SelectorOp::RemoveId,             "X", ""  },
 
+	{ "p[unit=m]",                   "B",               SelectorOp::RemoveAttributeUnit,  "B", ""  },
+	{ "p[unit=m] + *",               "C",               SelectorOp::RemoveAttributeUnit,  "B", ""  },
+
 	{ "body > * #D0",                "D0" },
 	{ "#E + * ~ *",                  "G H" },
 	{ "#B + * ~ #G",                 "G" },
@@ -352,6 +354,10 @@ TEST_CASE("Selectors")
 					document->GetElementById(selector.operation_argument)->SetId("");
 					operation_str = "RemoveId";
 					break;
+				case SelectorOp::RemoveAttributeUnit:
+					document->GetElementById(selector.operation_argument)->RemoveAttribute("unit");
+					operation_str = "RemoveAttributeUnit";
+					break;
 				case SelectorOp::SetHover:
 					document->GetElementById(selector.operation_argument)->SetPseudoClass("hover", true);
 					operation_str = "SetHover";