You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
2.7 KiB

  1. defmodule Microformats2.Helpers do
  2. @spec attr_list(String.t() | [any()] | tuple(), String.t()) :: [String.t()]
  3. def attr_list(node, attr \\ "class") do
  4. node
  5. |> Floki.attribute(attr)
  6. |> List.first()
  7. |> to_string
  8. |> String.split(" ", trim: true)
  9. end
  10. @spec blank?(any()) :: boolean()
  11. def blank?(nil), do: true
  12. def blank?(""), do: true
  13. def blank?([]), do: true
  14. def blank?(_), do: false
  15. @spec present?(any()) :: boolean()
  16. def present?(v), do: not blank?(v)
  17. @spec stripped_or_nil(nil | String.t()) :: nil | String.t()
  18. def stripped_or_nil(nil), do: nil
  19. def stripped_or_nil(val), do: String.trim(val)
  20. @spec is_rootlevel?(bitstring() | tuple()) :: boolean()
  21. def is_rootlevel?(node) when is_tuple(node) do
  22. node
  23. |> attr_list("class")
  24. |> Enum.any?(&is_a?(&1, "h"))
  25. end
  26. def is_rootlevel?(class_name) when is_bitstring(class_name) do
  27. is_a?(class_name, "h")
  28. end
  29. @spec is_a?(any(), any()) :: boolean()
  30. def is_a?("h-" <> _, wanted), do: wanted == "h"
  31. def is_a?("p-" <> _, wanted), do: wanted == "p"
  32. def is_a?("e-" <> _, wanted), do: wanted == "e"
  33. def is_a?("u-" <> _, wanted), do: wanted == "u"
  34. def is_a?("dt-" <> _, wanted), do: wanted == "dt"
  35. def is_a?(_, _), do: false
  36. @spec has_a?(String.t() | [any()] | tuple(), any()) :: boolean()
  37. def has_a?(node, wanted) do
  38. node
  39. |> attr_list()
  40. |> Enum.filter(&is_a?(&1, wanted))
  41. |> blank?
  42. end
  43. @spec abs_uri(String.t(), String.t(), any()) :: String.t()
  44. def abs_uri(url, base_url, doc) do
  45. parsed = URI.parse(url)
  46. parsed_base = URI.parse(base_url)
  47. cond do
  48. # absolute URI
  49. present?(parsed.scheme) ->
  50. url
  51. # protocol relative URI
  52. blank?(parsed.scheme) and present?(parsed.host) ->
  53. URI.to_string(%{parsed | scheme: parsed_base.scheme})
  54. true ->
  55. base_element = Floki.find(doc, "base")
  56. new_base =
  57. if blank?(base_element) or blank?(Floki.attribute(base_element, "href")) do
  58. base_url
  59. else
  60. abs_uri(Floki.attribute(base_element, "href") |> List.first(), base_url, [])
  61. end
  62. parsed_new_base = URI.parse(new_base)
  63. new_path = Path.expand(parsed.path || "/", Path.dirname(parsed_new_base.path || "/"))
  64. URI.to_string(%{parsed | scheme: parsed_new_base.scheme, host: parsed_new_base.host, path: new_path})
  65. end
  66. end
  67. @spec to_key(String.t()) :: String.t()
  68. def to_key(str) do
  69. String.replace(str, ~r/[-]/, "_")
  70. end
  71. @spec normalized_key(String.t()) :: String.t() | atom()
  72. def normalized_key(key) do
  73. if Application.get_env(:microformats2, :atomize_keys, true),
  74. do: String.to_atom(key),
  75. else: key
  76. end
  77. end