diff --git a/.formatter.exs b/.formatter.exs index 5c5372f..82396f2 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -18,6 +18,15 @@ locals_without_parens = ~w[ area br col embed hr img input keygen param source track wbr text partial + animate animateMotion animateTransform circle clipPath + color-profile defs desc discard ellipse feBlend + feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feDropShadow + feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset + fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter foreignObject g hatch hatchpath image line linearGradient + marker mask mesh meshgradient meshpatch meshrow metadata mpath path pattern polygon + polyline radialGradient rect set solidcolor stop svg switch symbol text_ + textPath tspan unknown use view + form_for inputs_for checkbox color_input checkbox color_input date_input date_select datetime_local_input datetime_select email_input file_input hidden_input number_input password_input range_input diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cd232a..e3bcc30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## Master +- `Temple.Svg` module +- `mix temple.convert` Mix task +- (dev) rename `mix update_mdn_docs` to `mix temple.update_mdn_docs` and don't ship it to hex + +### Breaking + +- Rename Temple.Tags to Temple.Html + ## v0.3.1 - `Temple.Form.phx_label`, `Temple.Form.submit`, `Temple.Link.phx_button`, `Temple.Link.phx_link` now correctly parse blocks. Before this, they would escape anything passed to the block instead of accepting it as raw HTML. diff --git a/README.md b/README.md index 246caee..376025f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ end Using Temple is a as simple as using the DSL inside of an `temple/1` block. This returns a safe result of the form `{:safe, html_string}`. -See the [documentation](https://hexdocs.pm/temple/Temple.Tags.html) for more details. +See the [documentation](https://hexdocs.pm/temple/Temple.Html.html) for more details. ```elixir use Temple @@ -153,6 +153,14 @@ html lang: "en" do end ``` +### Tasks + +#### temple.convert + +This task can be used to convert plain HTML and SVG into Temple syntax. Input is taken from stdin or from a file and the output is sent to stdout. + +`cat index.html | mix temple.convert > index.html.exs` + ### Formatter To include Temple's formatter configuration, add `:temple` to your `.formatter.exs`. diff --git a/lib/mix/tasks/temple.convert.ex b/lib/mix/tasks/temple.convert.ex new file mode 100644 index 0000000..0ff870d --- /dev/null +++ b/lib/mix/tasks/temple.convert.ex @@ -0,0 +1,22 @@ +defmodule Mix.Tasks.Temple.Convert do + use Mix.Task + @shortdoc "Converts HTML to Temple syntax" + @moduledoc """ + Converts HTML to Temple syntax + + Takes HTML from a file or from stdin and outputs temple syntax to stdout. + """ + + def run(args) do + html = + if Enum.count(args) > 0 do + args |> List.first() |> File.read!() + else + IO.read(:stdio, :all) + end + + {:ok, result} = Temple.HtmlToTemple.parse(html) + + IO.write(result) + end +end diff --git a/lib/mix/tasks/temple.update_mdn_docs.ex b/lib/mix/tasks/temple.update_mdn_docs.ex new file mode 100644 index 0000000..2859e9f --- /dev/null +++ b/lib/mix/tasks/temple.update_mdn_docs.ex @@ -0,0 +1,48 @@ +defmodule Mix.Tasks.Temple.UpdateMdnDocs do + use Mix.Task + + @html_base_url "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/" + @svg_base_url "https://developer.mozilla.org/en-US/docs/Web/SVG/Element/" + @params "?summary&raw" + + @shortdoc "Update the MDN documentation" + def run(_) do + IO.puts("Downloading HTML documentation") + + (Temple.Html.nonvoid_elements() ++ Temple.Html.void_elements() ++ ["html"]) + |> Enum.map( + &to_doc(to_string(&1), "./tmp/docs/html/", fn el -> base_url(:html, html_page(el)) end) + ) + |> Enum.each(&Task.await/1) + + IO.puts("Downloading SVG documentation") + + Temple.Svg.elements() + |> Enum.map(&Temple.Utils.to_valid_tag(&1)) + |> Enum.map(&to_doc(&1, "./tmp/docs/svg/", fn el -> base_url(:svg, el) end)) + |> Enum.each(&Task.await/1) + end + + defp to_doc(el, dir_path, url_getter) do + Task.async(fn -> + url = url_getter.(el) + + {doc, 0} = System.cmd("curl", ["--silent", url]) + + File.mkdir_p!(dir_path) + + doc = HtmlSanitizeEx.strip_tags(doc) + + File.write!(dir_path <> el <> ".txt", doc) + end) + end + + defp html_page(el) when el in ["h1", "h2", "h3", "h4", "h5", "h6"] do + "Heading_Elements" + end + + defp html_page(el), do: el + + defp base_url(:html, page), do: @html_base_url <> page <> @params + defp base_url(:svg, page), do: @svg_base_url <> page <> @params +end diff --git a/lib/mix/tasks/update_mdn_docs.ex b/lib/mix/tasks/update_mdn_docs.ex deleted file mode 100644 index 0947327..0000000 --- a/lib/mix/tasks/update_mdn_docs.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule Mix.Tasks.UpdateMdnDocs do - use Mix.Task - - @baseurl "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/" - @params "?summary&raw" - - @shortdoc "Update the MDN documentation" - def run(_) do - IO.puts("Downloading MDN documentation") - - (Temple.Tags.nonvoid_elements() ++ Temple.Tags.void_elements() ++ ["html"]) - |> Enum.map(fn el -> - Task.async(fn -> - el = to_string(el) - - page = - if Enum.any?(["h1", "h2", "h3", "h4", "h5", "h6"], &(&1 == el)) do - "Heading_Elements" - else - el - end - - {doc, 0} = System.cmd("curl", ["--silent", @baseurl <> page <> @params]) - File.mkdir_p!("./tmp/docs/") - - path = "./tmp/docs/" <> el <> ".txt" - doc = HtmlSanitizeEx.strip_tags(doc) - - File.write!(path, doc) - end) - end) - |> Enum.each(&Task.await/1) - end -end diff --git a/lib/temple.ex b/lib/temple.ex index f555319..2d6968a 100644 --- a/lib/temple.ex +++ b/lib/temple.ex @@ -2,9 +2,6 @@ defmodule Temple do defmacro __using__(_) do quote location: :keep do import Temple - import Temple.Tags - import Temple.Form - import Temple.Link end end @@ -33,14 +30,18 @@ defmodule Temple do """ defmacro temple([do: block] = _block) do quote location: :keep do - import Kernel, except: [div: 2] + import Kernel, except: [div: 2, use: 1, use: 2] + import Temple.Html + import Temple.Svg + import Temple.Form + import Temple.Link - with {:ok, var!(buff, Temple.Tags)} <- Temple.Utils.start_buffer([]) do + with {:ok, var!(buff, Temple.Html)} <- Temple.Utils.start_buffer([]) do unquote(block) - markup = Temple.Utils.get_buffer(var!(buff, Temple.Tags)) + markup = Temple.Utils.get_buffer(var!(buff, Temple.Html)) - :ok = Temple.Utils.stop_buffer(var!(buff, Temple.Tags)) + :ok = Temple.Utils.stop_buffer(var!(buff, Temple.Html)) Temple.Utils.join_and_escape(markup) end @@ -63,7 +64,7 @@ defmodule Temple do defmacro text(text) do quote location: :keep do Temple.Utils.put_buffer( - var!(buff, Temple.Tags), + var!(buff, Temple.Html), unquote(text) |> Temple.Utils.escape_content() ) end @@ -98,7 +99,7 @@ defmodule Temple do defmacro partial(partial) do quote location: :keep do Temple.Utils.put_buffer( - var!(buff, Temple.Tags), + var!(buff, Temple.Html), unquote(partial) |> Temple.Utils.from_safe() ) end diff --git a/lib/temple/elements.ex b/lib/temple/elements.ex index 54d53c8..65e80c6 100644 --- a/lib/temple/elements.ex +++ b/lib/temple/elements.ex @@ -1,12 +1,12 @@ defmodule Temple.Elements do @moduledoc """ - This module contains the primitives used to generate the macros in the `Temple.Tags` module. + This module contains the primitives used to generate the macros in the `Temple.Html` and `Temple.Svg` modules. """ @doc """ Defines an element. - *Note*: Underscores are converted to hypens. + *Note*: Underscores are converted to dashes. ```elixir defmodule MyElements do @@ -26,6 +26,7 @@ defmodule Temple.Elements do Temple.Elements.nonvoid_element(unquote(name)) end + @doc false defmacro unquote(name)(attrs_or_content_or_block) defmacro unquote(name)([{:do, _inner}] = block) do @@ -36,6 +37,7 @@ defmodule Temple.Elements do Temple.Elements.nonvoid_element(unquote(name), attrs_or_content) end + @doc false defmacro unquote(name)(attrs_or_content, block_or_attrs) defmacro unquote(name)(attrs, [{:do, _inner}] = block) do @@ -59,8 +61,8 @@ defmodule Temple.Elements do @doc false def nonvoid_element(el) do quote location: :keep do - Temple.Utils.put_open_tag(var!(buff, Temple.Tags), unquote(el), []) - Temple.Utils.put_close_tag(var!(buff, Temple.Tags), unquote(el)) + Temple.Utils.put_open_tag(var!(buff, Temple.Html), unquote(el), []) + Temple.Utils.put_close_tag(var!(buff, Temple.Html), unquote(el)) end end @@ -69,16 +71,16 @@ defmodule Temple.Elements do def nonvoid_element(el, [{:do, inner}]) do quote location: :keep do - Temple.Utils.put_open_tag(var!(buff, Temple.Tags), unquote(el), []) + Temple.Utils.put_open_tag(var!(buff, Temple.Html), unquote(el), []) _ = unquote(inner) - Temple.Utils.put_close_tag(var!(buff, Temple.Tags), unquote(el)) + Temple.Utils.put_close_tag(var!(buff, Temple.Html), unquote(el)) end end def nonvoid_element(el, attrs_or_content) do quote location: :keep do - Temple.Utils.put_open_tag(var!(buff, Temple.Tags), unquote(el), unquote(attrs_or_content)) - Temple.Utils.put_close_tag(var!(buff, Temple.Tags), unquote(el)) + Temple.Utils.put_open_tag(var!(buff, Temple.Html), unquote(el), unquote(attrs_or_content)) + Temple.Utils.put_close_tag(var!(buff, Temple.Html), unquote(el)) end end @@ -87,24 +89,24 @@ defmodule Temple.Elements do def nonvoid_element(el, attrs, [{:do, inner}] = _block) do quote location: :keep do - Temple.Utils.put_open_tag(var!(buff, Temple.Tags), unquote_splicing([el, attrs])) + Temple.Utils.put_open_tag(var!(buff, Temple.Html), unquote_splicing([el, attrs])) _ = unquote(inner) - Temple.Utils.put_close_tag(var!(buff, Temple.Tags), unquote(el)) + Temple.Utils.put_close_tag(var!(buff, Temple.Html), unquote(el)) end end def nonvoid_element(el, content, attrs) do quote location: :keep do - Temple.Utils.put_open_tag(var!(buff, Temple.Tags), unquote_splicing([el, attrs])) + Temple.Utils.put_open_tag(var!(buff, Temple.Html), unquote_splicing([el, attrs])) text unquote(content) - Temple.Utils.put_close_tag(var!(buff, Temple.Tags), unquote(el)) + Temple.Utils.put_close_tag(var!(buff, Temple.Html), unquote(el)) end end @doc false def void_element(el, attrs \\ []) do quote location: :keep do - Temple.Utils.put_void_tag(var!(buff, Temple.Tags), unquote_splicing([el, attrs])) + Temple.Utils.put_void_tag(var!(buff, Temple.Html), unquote_splicing([el, attrs])) end end end diff --git a/lib/temple/form.ex b/lib/temple/form.ex index c31553a..8b51507 100644 --- a/lib/temple/form.ex +++ b/lib/temple/form.ex @@ -45,9 +45,9 @@ defmodule Temple.Form do quote location: :keep do var!(form) = HTML.Form.form_for(unquote_splicing([form_data, action, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), var!(form) |> HTML.Safe.to_iodata()) + Utils.put_buffer(var!(buff, Temple.Html), var!(form) |> HTML.Safe.to_iodata()) _ = unquote(block) - Utils.put_buffer(var!(buff, Temple.Tags), "") + Utils.put_buffer(var!(buff, Temple.Html), "") end end @@ -83,7 +83,7 @@ defmodule Temple.Form do {:safe, input} = apply(Phoenix.HTML.Form, unquote(helper), [unquote_splicing([form, field, opts])]) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end end @@ -97,7 +97,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.textarea(unquote_splicing([form, field, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -108,7 +108,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.reset(unquote_splicing([value, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -119,7 +119,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.submit(do: temple(do: unquote(block))) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -127,7 +127,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.submit(unquote(value)) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -138,7 +138,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.submit(unquote(opts), do: temple(do: unquote(block))) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -146,7 +146,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.submit(unquote_splicing([value, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -157,7 +157,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.label(unquote_splicing([form, field])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -169,7 +169,7 @@ defmodule Temple.Form do {:safe, input} = Phoenix.HTML.Form.label(unquote_splicing([form, field]), do: temple(do: unquote(block))) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -177,7 +177,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.label(unquote_splicing([form, field, text_or_opts])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -191,7 +191,7 @@ defmodule Temple.Form do do: temple(do: unquote(block)) ) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -199,7 +199,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.label(unquote_splicing([form, field, text, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -211,7 +211,7 @@ defmodule Temple.Form do {:safe, input} = Phoenix.HTML.Form.radio_button(unquote_splicing([form, field, value, attrs])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -223,7 +223,7 @@ defmodule Temple.Form do {:safe, input} = Phoenix.HTML.Form.multiple_select(unquote_splicing([form, field, options, attrs])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -234,7 +234,7 @@ defmodule Temple.Form do quote location: :keep do {:safe, input} = Phoenix.HTML.Form.select(unquote_splicing([form, field, options, attrs])) - Utils.put_buffer(var!(buff, Temple.Tags), input) + Utils.put_buffer(var!(buff, Temple.Html), input) end end @@ -293,7 +293,7 @@ defmodule Temple.Form do hidden_input end) - |> Enum.each(&Utils.put_buffer(var!(buff, Temple.Tags), &1)) + |> Enum.each(&Utils.put_buffer(var!(buff, Temple.Html), &1)) var!(inner_form) = form diff --git a/lib/temple/tags.ex b/lib/temple/html.ex similarity index 78% rename from lib/temple/tags.ex rename to lib/temple/html.ex index 248a7e2..3e65290 100644 --- a/lib/temple/tags.ex +++ b/lib/temple/html.ex @@ -1,14 +1,16 @@ -defmodule Temple.Tags do +defmodule Temple.Html do require Temple.Elements @moduledoc """ - The `Temple.Tags` module defines macros for all HTML5 compliant elements. + The `Temple.Html` module defines macros for all HTML5 compliant elements. - `Temple.Tags` macros must be called inside of a `Temple.temple/1` block. + `Temple.Html` macros must be called inside of a `Temple.temple/1` block. + + *Note*: Only the lowest arity macros are documented. Void elements are defined as a 1-arity macro and non-void elements are defined as 0, 1, and 2-arity macros. ## Attributes - Tags accept a keyword list or a map of attributes to be emitted into the element's opening tag. Multi-word attribute keys written in snake_case (`data_url`) will be transformed into kebab-case (`data-url`). + Html accept a keyword list or a map of attributes to be emitted into the element's opening tag. Multi-word attribute keys written in snake_case (`data_url`) will be transformed into kebab-case (`data-url`). ## Children @@ -88,20 +90,20 @@ defmodule Temple.Tags do def void_elements, do: @void_elements for el <- @nonvoid_elements do - @doc if File.exists?("./tmp/docs/#{el}.txt"), do: File.read!("./tmp/docs/#{el}.txt") + @doc if File.exists?("./tmp/docs/html/#{el}.txt"), do: File.read!("./tmp/docs/html/#{el}.txt") Temple.Elements.defelement(unquote(el), :nonvoid) end for el <- @void_elements do - @doc if File.exists?("./tmp/docs/#{el}.txt"), do: File.read!("./tmp/docs/#{el}.txt") + @doc if File.exists?("./tmp/docs/html/#{el}.txt"), do: File.read!("./tmp/docs/html/#{el}.txt") Temple.Elements.defelement(unquote(el), :void) end - @doc if File.exists?("./tmp/docs/html.txt"), do: File.read!("./tmp/docs/html.txt") + @doc if File.exists?("./tmp/docs/html/html.txt"), do: File.read!("./tmp/docs/html/html.txt") defmacro html(attrs \\ [], [{:do, _inner}] = block) do doc_type = quote location: :keep do - Temple.Utils.put_buffer(var!(buff, Temple.Tags), "") + Temple.Utils.put_buffer(var!(buff, Temple.Html), "") end [doc_type, Temple.Elements.nonvoid_element(:html, attrs, block)] diff --git a/lib/temple/html_to_temple.ex b/lib/temple/html_to_temple.ex new file mode 100644 index 0000000..e8d6de7 --- /dev/null +++ b/lib/temple/html_to_temple.ex @@ -0,0 +1,74 @@ +defmodule Temple.HtmlToTemple do + @moduledoc false + + @tags Temple.Html.void_elements() ++ + Temple.Html.nonvoid_elements() ++ Temple.Svg.elements() ++ [:html] + + def parse(doc) do + result = + doc + |> Floki.parse() + |> do_parse(0) + + {:ok, result} + end + + def do_parse({tag, [], []}, indent) do + tag = tag |> find_tag + (Temple.Utils.kebab_to_snake(tag) <> "()\n") |> pad_indent(indent) + end + + def do_parse({tag, attrs, []}, indent) do + tag = tag |> find_tag + (Temple.Utils.kebab_to_snake(tag) <> build_attrs(attrs) <> "\n") |> pad_indent(indent) + end + + def do_parse({tag, attrs, [""]}, indent), do: do_parse({tag, attrs, []}, indent) + + def do_parse({tag, attrs, children}, indent) do + tag = tag |> find_tag + + head = + (Temple.Utils.kebab_to_snake(tag) <> build_attrs(attrs) <> " do\n") + |> pad_indent(indent) + + parsed_childs = + for child <- children do + do_parse(child, indent + 1) + end + |> Enum.join("\n") + + head <> parsed_childs <> pad_indent("end\n", indent) + end + + def do_parse(text, indent) when is_binary(text) do + (~s|text "| <> text <> ~s|"\n|) |> pad_indent(indent) + end + + defp build_attrs([]), do: "" + + defp build_attrs(attrs) do + attrs = + for {key, value} <- attrs do + wrap_in_quotes(key) <> ~s|: "| <> value <> ~s|"| + end + |> Enum.join(", ") + + " " <> attrs + end + + defp wrap_in_quotes(key) do + if Regex.match?(~r/[^a-zA-Z_]/, key) do + ~s|"| <> key <> ~s|"| + else + key + end + end + + defp pad_indent(paddable, indent) do + String.pad_leading(paddable, 2 * indent + String.length(paddable)) + end + + defp find_tag(tag), + do: @tags |> Enum.find(fn x -> String.downcase(to_string(x)) == tag end) +end diff --git a/lib/temple/link.ex b/lib/temple/link.ex index be964fa..fe3e4bb 100644 --- a/lib/temple/link.ex +++ b/lib/temple/link.ex @@ -15,7 +15,7 @@ defmodule Temple.Link do temple(do: unquote(block)) |> HTML.Link.link(unquote(opts)) - Utils.put_buffer(var!(buff, Temple.Tags), link) + Utils.put_buffer(var!(buff, Temple.Html), link) end end @@ -23,7 +23,7 @@ defmodule Temple.Link do quote location: :keep do {:safe, link} = HTML.Link.link(unquote_splicing([content, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), link) + Utils.put_buffer(var!(buff, Temple.Html), link) end end @@ -36,7 +36,7 @@ defmodule Temple.Link do temple(do: unquote(block)) |> HTML.Link.button(unquote(opts)) - Utils.put_buffer(var!(buff, Temple.Tags), link) + Utils.put_buffer(var!(buff, Temple.Html), link) end end @@ -44,7 +44,7 @@ defmodule Temple.Link do quote location: :keep do {:safe, link} = HTML.Link.button(unquote_splicing([content, opts])) - Utils.put_buffer(var!(buff, Temple.Tags), link) + Utils.put_buffer(var!(buff, Temple.Html), link) end end end diff --git a/lib/temple/svg.ex b/lib/temple/svg.ex new file mode 100644 index 0000000..7d5fbd6 --- /dev/null +++ b/lib/temple/svg.ex @@ -0,0 +1,29 @@ +defmodule Temple.Svg do + require Temple.Elements + + @moduledoc """ + The `Temple.Svg` module defines macros for all SVG elements. + + Usage is the same as `Temple.Html`. + """ + + @elements ~w[ + animate animateMotion animateTransform circle clipPath + color_profile defs desc discard ellipse feBlend + feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feDropShadow + feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset + fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter foreignObject g hatch hatchpath image line linearGradient + marker mask metadata mpath path pattern polygon + polyline radialGradient rect set solidcolor stop svg switch symbol text_ + textPath tspan use view + ]a + + @doc false + def elements(), do: @elements + + for el <- @elements do + @doc if File.exists?("./tmp/docs/svg/#{Temple.Utils.to_valid_tag(el)}.txt"), + do: File.read!("./tmp/docs/svg/#{Temple.Utils.to_valid_tag(el)}.txt") + Temple.Elements.defelement(unquote(el), :nonvoid) + end +end diff --git a/lib/temple/utils.ex b/lib/temple/utils.ex index 6f791f5..a3a120d 100644 --- a/lib/temple/utils.ex +++ b/lib/temple/utils.ex @@ -74,7 +74,10 @@ defmodule Temple.Utils do end defp snake_to_kebab(stringable), - do: stringable |> to_string() |> String.replace("_", "-") + do: stringable |> to_string() |> String.replace_trailing("_", "") |> String.replace("_", "-") + + def kebab_to_snake(stringable), + do: stringable |> to_string() |> String.replace("-", "_") def __quote__(outer) do quote [location: :keep], do: unquote(outer) @@ -84,4 +87,10 @@ defmodule Temple.Utils do block |> Macro.prewalk(&Temple.Utils.insert_props(&1, props, inner)) end + + def doc_path(:html, el), do: "./tmp/docs/html/#{el}.txt" + def doc_path(:svg, el), do: "./tmp/docs/svg/#{el}.txt" + + def to_valid_tag(tag), + do: tag |> to_string |> String.replace_trailing("_", "") |> String.replace("_", "-") end diff --git a/mix.exs b/mix.exs index ffc36ef..5a7a4e7 100644 --- a/mix.exs +++ b/mix.exs @@ -40,13 +40,14 @@ defmodule Temple.MixProject do maintainers: ["Mitchell Hanberg"], licenses: ["MIT"], links: %{github: "https://github.com/mhanberg/temple"}, + exclude_patterns: ["temple.update_mdn_docs.ex"], files: ~w(lib priv CHANGELOG.md LICENSE mix.exs README.md .formatter.exs) ] end defp aliases do [ - docs: ["update_mdn_docs", "docs"] + docs: ["temple.update_mdn_docs", "docs"] ] end @@ -58,7 +59,8 @@ defmodule Temple.MixProject do {:ex_doc, "~> 0.0", only: [:dev], runtime: false}, {:html_sanitize_ex, "~> 1.3", only: [:dev, :test], runtime: false}, {:phoenix, "~> 1.4", optional: true}, - {:plug, "~> 1.8", optional: true} + {:plug, "~> 1.8", optional: true}, + {:floki, "~> 0.23.0"} ] end end diff --git a/mix.lock b/mix.lock index 8a64b51..39322f0 100644 --- a/mix.lock +++ b/mix.lock @@ -3,6 +3,8 @@ "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm"}, "ecto": {:hex, :ecto, "3.2.0", "940e2598813f205223d60c78d66e514afe1db5167ed8075510a59e496619cfb5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, + "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"}, + "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/mix/tasks/html_to_temple_test.exs b/test/mix/tasks/html_to_temple_test.exs new file mode 100644 index 0000000..00809c5 --- /dev/null +++ b/test/mix/tasks/html_to_temple_test.exs @@ -0,0 +1,89 @@ +defmodule Mix.Tasks.HtmlToTempleTest do + use ExUnit.Case, async: true + + test "converts html to temple syntax" do + html = """ + +
+ + + + + +