From 77d8e6584bd91a98ed2dbfb7a4e326830c471670 Mon Sep 17 00:00:00 2001 From: Nuno Brito Date: Tue, 28 Jun 2022 14:12:37 +0100 Subject: [PATCH 1/3] added insensitive case fl-icontains --- README.md | 7 ++++--- lib/floki/selector.ex | 5 +++++ lib/floki/selector/pseudo_class.ex | 12 ++++++++++++ test/floki_test.exs | 8 ++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b6d3d36..38aecc8f 100644 --- a/README.md +++ b/README.md @@ -259,9 +259,10 @@ Here you find all the [CSS selectors](https://www.w3.org/TR/selectors/#selectors There are also some selectors based on non-standard specifications. They are: -| Pattern | Description | -|----------------------|-----------------------------------------------------| -| E:fl-contains('foo') | an E element that contains "foo" inside a text node | +| Pattern | Description | +|-----------------------|-----------------------------------------------------| +| E:fl-contains('foo') | an E element that contains "foo" inside a text node | +| E:fl-icontains('foo') | an E element that contains "foo" inside a text node (case insensitive) | ## Special thanks diff --git a/lib/floki/selector.ex b/lib/floki/selector.ex index 4e9a671c..426adf9b 100644 --- a/lib/floki/selector.ex +++ b/lib/floki/selector.ex @@ -210,6 +210,11 @@ defmodule Floki.Selector do PseudoClass.match_contains?(tree, html_node, pseudo_class) end + #Case insensitive contains + defp pseudo_class_match?(html_node, pseudo_class = %{name: "fl-icontains"}, tree) do + PseudoClass.match_icontains?(tree, html_node, pseudo_class) + end + defp pseudo_class_match?(html_node, %{name: "root"}, tree) do PseudoClass.match_root?(html_node, tree) end diff --git a/lib/floki/selector/pseudo_class.ex b/lib/floki/selector/pseudo_class.ex index 9ceab407..9b7fb33a 100644 --- a/lib/floki/selector/pseudo_class.ex +++ b/lib/floki/selector/pseudo_class.ex @@ -71,6 +71,18 @@ defmodule Floki.Selector.PseudoClass do res != nil end + #Case insensitive contains + def match_icontains?(tree, html_node, %__MODULE__{value: value}) do + res = + Enum.find(html_node.children_nodes_ids, fn id -> + case Map.get(tree.nodes, id) do + %Text{content: content} -> String.downcase(content) =~ String.downcase(value) + _ -> false + end + end) + + res != nil + end defp match_position?(relative_position, value, name) do case value do diff --git a/test/floki_test.exs b/test/floki_test.exs index f16f61dc..c0c1c5a2 100644 --- a/test/floki_test.exs +++ b/test/floki_test.exs @@ -1160,6 +1160,14 @@ defmodule FlokiTest do ] end + test "icontains pseudo-class" do + doc = document!(html_body(~s(

One

Two

nothing42
))) + + assert Floki.find(doc, "p:fl-icontains('two')") == [ + {"p", [], ["Two"]} + ] + end + test "contains psuedo-class with substring" do html = document!( From 562679c75a8d953acdde4247c3fe9d31ceb207bf Mon Sep 17 00:00:00 2001 From: Nuno Brito Date: Tue, 28 Jun 2022 14:32:36 +0100 Subject: [PATCH 2/3] only one downcase on value --- README.md | 6 +++--- lib/floki/selector/pseudo_class.ex | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38aecc8f..223c72ca 100644 --- a/README.md +++ b/README.md @@ -259,9 +259,9 @@ Here you find all the [CSS selectors](https://www.w3.org/TR/selectors/#selectors There are also some selectors based on non-standard specifications. They are: -| Pattern | Description | -|-----------------------|-----------------------------------------------------| -| E:fl-contains('foo') | an E element that contains "foo" inside a text node | +| Pattern | Description | +|-----------------------|------------------------------------------------------------------------| +| E:fl-contains('foo') | an E element that contains "foo" inside a text node | | E:fl-icontains('foo') | an E element that contains "foo" inside a text node (case insensitive) | ## Special thanks diff --git a/lib/floki/selector/pseudo_class.ex b/lib/floki/selector/pseudo_class.ex index 9b7fb33a..b38a0a1b 100644 --- a/lib/floki/selector/pseudo_class.ex +++ b/lib/floki/selector/pseudo_class.ex @@ -73,10 +73,11 @@ defmodule Floki.Selector.PseudoClass do end #Case insensitive contains def match_icontains?(tree, html_node, %__MODULE__{value: value}) do + downcase_value = String.downcase(value) res = Enum.find(html_node.children_nodes_ids, fn id -> case Map.get(tree.nodes, id) do - %Text{content: content} -> String.downcase(content) =~ String.downcase(value) + %Text{content: content} -> String.downcase(content) =~ downcase_value _ -> false end end) From d7dd2403e971dfc47be6bdaba3c61d685ee03016 Mon Sep 17 00:00:00 2001 From: Nuno Brito Date: Tue, 28 Jun 2022 15:31:24 +0100 Subject: [PATCH 3/3] mix format applied --- lib/floki/selector.ex | 2 +- lib/floki/selector/pseudo_class.ex | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/floki/selector.ex b/lib/floki/selector.ex index 426adf9b..f1a1cca8 100644 --- a/lib/floki/selector.ex +++ b/lib/floki/selector.ex @@ -210,7 +210,7 @@ defmodule Floki.Selector do PseudoClass.match_contains?(tree, html_node, pseudo_class) end - #Case insensitive contains + # Case insensitive contains defp pseudo_class_match?(html_node, pseudo_class = %{name: "fl-icontains"}, tree) do PseudoClass.match_icontains?(tree, html_node, pseudo_class) end diff --git a/lib/floki/selector/pseudo_class.ex b/lib/floki/selector/pseudo_class.ex index b38a0a1b..34f488d6 100644 --- a/lib/floki/selector/pseudo_class.ex +++ b/lib/floki/selector/pseudo_class.ex @@ -71,9 +71,11 @@ defmodule Floki.Selector.PseudoClass do res != nil end - #Case insensitive contains + + # Case insensitive contains def match_icontains?(tree, html_node, %__MODULE__{value: value}) do downcase_value = String.downcase(value) + res = Enum.find(html_node.children_nodes_ids, fn id -> case Map.get(tree.nodes, id) do