From 23410cf4edeeeadb3295e2d371b3f97f2fe29a86 Mon Sep 17 00:00:00 2001 From: Amar Raja Date: Fri, 14 Sep 2018 16:09:51 +0100 Subject: [PATCH] Start on rendering blocks --- .gitignore | 2 + lib/fragment/image.ex | 6 +- .../structured_text/block/text/paragraph.ex | 39 ++++++- lib/fragment/structured_text/span.ex | 2 + lib/fragment/structured_text/span/em.ex | 2 + .../structured_text/span/hyperlink.ex | 9 +- lib/fragment/structured_text/span/label.ex | 2 + lib/fragment/structured_text/span/strong.ex | 2 + test/frag_test.exs | 107 ++++++++++++++++++ 9 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 test/frag_test.exs diff --git a/.gitignore b/.gitignore index 12179ea..46123ac 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ erl_crash.dump # Also ignore archive artifacts (built via "mix archive.build"). *.ez + +.elixir_ls diff --git a/lib/fragment/image.ex b/lib/fragment/image.ex index d024f6b..633c45d 100644 --- a/lib/fragment/image.ex +++ b/lib/fragment/image.ex @@ -9,5 +9,9 @@ end defimpl Prismic.Fragment, for: Prismic.Fragment.Image do # TODO - def as_html(_, _, _), do: "" + def as_html(img, _link_resolver, _html_serializer) do + main = img.main + %{url: url, height: h, width: w} = main + ~s[] + end end diff --git a/lib/fragment/structured_text/block/text/paragraph.ex b/lib/fragment/structured_text/block/text/paragraph.ex index caf67b7..3230393 100644 --- a/lib/fragment/structured_text/block/text/paragraph.ex +++ b/lib/fragment/structured_text/block/text/paragraph.ex @@ -7,5 +7,42 @@ defmodule Block.Text.Paragraph do end defimpl Block, for: Block.Text.Paragraph do - def as_html(_, _link_resolver, _html_serializer), do: "" + alias Prismic.Fragment.StructuredText.Span + + def as_html(para, _link_resolver, _html_serializer) do + ~s(

#{process_spans(para)}

) + end + + # TODO: All this should move out (unless paragraph is the only one with spans?) + defp process_spans(%{text: text, spans: []}), do: text + + defp process_spans(%{text: text, spans: spans}) do + text_stream = String.codepoints(text) + do_process_spans(text_stream, 0, spans, [], []) + end + + defp do_process_spans([], _pos, _spans, applied_spans, acc) do + [acc | Enum.map(applied_spans, &Span.close_tag/1)] + end + + # TODO: Not sure how efficient this is, since it is one character at a time + # Could do something smarter by checking the next opening and chunk characters + # from there. Uses an IO list so we aren't creating too many intermediate strings + defp do_process_spans([h | t], pos, spans, applied_spans, acc) do + {ending_here, still_to_end} = Enum.split_with(applied_spans, &match?(%{end: ^pos}, &1)) + starting_here = Enum.filter(spans, &match?(%{start: ^pos}, &1)) + + ending_tags = Enum.map(ending_here, &Span.close_tag/1) + starting_tags = Enum.map(starting_here, &Span.open_tag/1) + + # TODO: h should be html encoded + acc = [acc | [ending_tags, starting_tags, h]] + + applied_spans = + starting_here + |> Enum.reverse() + |> Enum.concat(still_to_end) + + do_process_spans(t, pos + 1, spans, applied_spans, acc) + end end diff --git a/lib/fragment/structured_text/span.ex b/lib/fragment/structured_text/span.ex index 663aa2d..4d3447e 100644 --- a/lib/fragment/structured_text/span.ex +++ b/lib/fragment/structured_text/span.ex @@ -1,3 +1,5 @@ defprotocol Prismic.Fragment.StructuredText.Span do def serialize(span, link_resolver) + def open_tag(span) + def close_tag(span) end diff --git a/lib/fragment/structured_text/span/em.ex b/lib/fragment/structured_text/span/em.ex index 028285c..56991e3 100644 --- a/lib/fragment/structured_text/span/em.ex +++ b/lib/fragment/structured_text/span/em.ex @@ -9,4 +9,6 @@ end defimpl Span, for: Span.Em do # TODO def serialize(_, _link_resolver), do: "" + def open_tag(_span), do: "" + def close_tag(_span), do: "" end diff --git a/lib/fragment/structured_text/span/hyperlink.ex b/lib/fragment/structured_text/span/hyperlink.ex index b9262e2..1dc1d32 100644 --- a/lib/fragment/structured_text/span/hyperlink.ex +++ b/lib/fragment/structured_text/span/hyperlink.ex @@ -5,12 +5,15 @@ defmodule Span.Hyperlink do defstruct [:start, :end, :link] @type t :: %__MODULE__{ - start: Integer.t(), - end: Integer.t(), - link: WebLink.t() | DocumentLink.t() | ImageLink.t()} + start: Integer.t(), + end: Integer.t(), + link: WebLink.t() | DocumentLink.t() | ImageLink.t() + } end defimpl Span, for: Span.Hyperlink do # TODO def serialize(_, _link_resolver), do: "" + def open_tag(%Span.Hyperlink{link: link}), do: ~s() + def close_tag(_span), do: "" end diff --git a/lib/fragment/structured_text/span/label.ex b/lib/fragment/structured_text/span/label.ex index 9960c5b..8b2e319 100644 --- a/lib/fragment/structured_text/span/label.ex +++ b/lib/fragment/structured_text/span/label.ex @@ -9,4 +9,6 @@ end defimpl Span, for: Span.Label do # TODO def serialize(_, _link_resolver), do: "" + def open_tag(_span), do: "" end diff --git a/lib/fragment/structured_text/span/strong.ex b/lib/fragment/structured_text/span/strong.ex index 8558e74..4f9283a 100644 --- a/lib/fragment/structured_text/span/strong.ex +++ b/lib/fragment/structured_text/span/strong.ex @@ -9,4 +9,6 @@ end defimpl Span, for: Span.Strong do # TODO def serialize(_, _link_resolver), do: "" + def open_tag(_span), do: "" + def close_tag(_span), do: "" end diff --git a/test/frag_test.exs b/test/frag_test.exs new file mode 100644 index 0000000..7bbf454 --- /dev/null +++ b/test/frag_test.exs @@ -0,0 +1,107 @@ +defmodule Prismic.FragText do + use ExUnit.Case + alias Prismic.Fragment.StructuredText.Block.Text.Paragraph + alias Prismic.Fragment.StructuredText.Span.{Em, Strong, Hyperlink} + + describe "structured text render" do + defp render_para(spans, text \\ "abc") do + st = %Prismic.Fragment.StructuredText{ + blocks: [ + %Paragraph{ + label: nil, + spans: spans, + text: text + } + ] + } + + Prismic.Fragment.as_html(st, nil) + end + + test "renders em" do + spans = [ + %Em{end: 3, start: 0} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "renders strong" do + spans = [ + %Strong{end: 3, start: 0} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "renders link" do + spans = [ + %Hyperlink{end: 3, start: 0, link: "somelink"} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "renders multiple" do + spans = [ + %Em{end: 3, start: 0}, + %Em{end: 6, start: 4} + ] + + text = "abcdef" + assert ~s(

abcdef

) == render_para(spans, text) + end + + test "handles nesting" do + spans = [ + %Em{end: 6, start: 0}, + %Strong{end: 5, start: 3} + ] + + text = "abcdef" + assert ~s(

abcdef

) == render_para(spans, text) + end + + test "ignores starts longer than input" do + spans = [ + %Em{end: 6, start: 999} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "closes tag if end greater than input" do + spans = [ + %Em{end: 999, start: 0} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "can do single characters" do + spans = [ + %Em{end: 2, start: 1} + ] + + assert ~s(

abc

) == render_para(spans) + end + + test "can do middle" do + spans = [ + %Em{end: 4, start: 2} + ] + + text = "abcdef" + assert ~s(

abcdef

) == render_para(spans, text) + end + + test "leaves tags balanced" do + spans = [ + %Em{end: 3, start: 0}, + %Strong{end: 3, start: 0} + ] + + assert ~s(

abc

) == render_para(spans) + end + end +end