From 48b1e4bf5323d4737823e99f5f782c8fdc4a2281 Mon Sep 17 00:00:00 2001 From: Darren Siegel Date: Fri, 20 Oct 2023 14:51:41 -0400 Subject: [PATCH 1/5] download and import of full course with condensed format --- lib/oli_web/controllers/ingest_controller.ex | 78 ++++++++++++++++++- lib/oli_web/live/import/csv_import_view.ex | 53 +++++++------ lib/oli_web/router.ex | 1 + .../templates/ingest/index_csv.html.eex | 7 +- 4 files changed, 114 insertions(+), 25 deletions(-) diff --git a/lib/oli_web/controllers/ingest_controller.ex b/lib/oli_web/controllers/ingest_controller.ex index 1c28ae80d04..bc59e5c7c54 100644 --- a/lib/oli_web/controllers/ingest_controller.ex +++ b/lib/oli_web/controllers/ingest_controller.ex @@ -33,10 +33,84 @@ defmodule OliWeb.IngestController do render(conn, page, Keyword.put_new(keywords, :active, :ingest)) end - def index_csv(conn, _params) do - render_ingest_page_csv(conn, :index_csv, title: "Import") + def index_csv(conn, %{"project_slug" => project_slug}) do + render_ingest_page_csv(conn, :index_csv, title: "Import", project_slug: project_slug) end + def download_current(conn, %{"project_slug" => project_slug}) do + + container_type_id = Oli.Resources.ResourceType.get_id_by_type("container") + page_type_id = Oli.Resources.ResourceType.get_id_by_type("page") + + content = Oli.Publishing.AuthoringResolver.full_hierarchy(project_slug) + |> Oli.Delivery.Hierarchy.flatten_hierarchy() + |> Enum.map(fn %{ + numbering: %{ + index: index, + level: level + }, + revision: %{ + resource_type_id: type_id, + title: title, + slug: slug, + poster_image: poster_image, + intro_content: intro_content, + intro_video: intro_video, + duration_minutes: duration_minutes, + purpose: purpose + } + } -> + + case type_id do + ^container_type_id -> + + c = case level do + 0 -> "Root Resource" + 1 -> "Unit #{index}" + _ -> "Module #{index}" + end + + [c, title, slug, duration_minutes |> v, poster_image |> v, intro_video |> v, intro_content |> m] + + ^page_type_id -> + + page_type = case purpose do + :foundation -> "foundation" + _ -> "exploration" + end + + [page_type, title, slug, duration_minutes |> v, poster_image |> v, intro_video |> v, intro_content |> m] + + end + end) + |> CSV.encode() + |> Enum.to_list() + + conn + |> send_download({:binary, content}, + filename: "current_attrs_#{project_slug}.csv" + ) + end + + defp m(%{"children" => children}) do + Enum.map(children, fn c -> + Enum.map(c["children"], fn t -> + if t["bold"] do + "**#{t["text"]}**" + else + t["text"] + end + end) + end) + |> Enum.join("|") + end + defp m(_), do: "" + + defp v(nil), do: "" + defp v(v) when is_binary(v), do: v + defp v(v) when is_map(v), do: v + defp v(v), do: Integer.to_string(v) + def upload_csv(conn, %{"project_slug" => project_slug} = params) do author = conn.assigns[:current_author] diff --git a/lib/oli_web/live/import/csv_import_view.ex b/lib/oli_web/live/import/csv_import_view.ex index 45fbfe0bd46..b646f74124c 100644 --- a/lib/oli_web/live/import/csv_import_view.ex +++ b/lib/oli_web/live/import/csv_import_view.ex @@ -76,37 +76,46 @@ defmodule OliWeb.Import.CSVImportView do defp process_rows(pid, project_slug, ingest_file) do + to_content = fn content -> + children = String.split(content, "|") + |> Enum.map(fn p -> to_paragraph(p) end) + + %{ + children: children + } + end + File.stream!(ingest_file) |> CSV.decode() |> Enum.to_list() |> Enum.with_index(1) - |> Enum.map(fn {{:ok, [_title, slug, attr, content]}, row_num} -> + |> Enum.map(fn {{:ok, [_type, _title, slug, duration_minutes, poster_image, intro_video, intro_content]}, row_num} -> revision = Oli.Publishing.AuthoringResolver.from_revision_slug(project_slug, slug) - value = case attr do - "duration_minutes" -> String.to_integer(content) - "poster_image" -> content - "intro_video" -> content - "intro_content" -> - - children = String.split(content, "\n") - |> Enum.map(fn p -> to_paragraph(p) end) - - %{ - children: children - } - end - - change = Map.put(%{}, String.to_existing_atom(attr), value) + has_change? = duration_minutes != "" or poster_image != "" or intro_video != "" or intro_content != "" + + if has_change? do + change = %{ + duration_minutes: if duration_minutes != "" do String.to_integer(duration_minutes) else nil end, + poster_image: if poster_image != "" do poster_image else nil end, + intro_video: if intro_video != "" do intro_video else nil end, + intro_content: if intro_content != "" do to_content.(intro_content) else nil end + } + + needs_change? = revision.duration_minutes != change.duration_minutes or revision.poster_image != change.poster_image or revision.intro_video != change.intro_video or revision.intro_content != change.intro_content + + if needs_change? do + case Oli.Resources.update_revision(revision, change) do + {:ok, _} -> + IO.inspect change + send(pid, {:update, row_num, :success}) + {:error, _} -> + send(pid, {:update, row_num, :failure}) + end + end - case Oli.Resources.update_revision(revision, change) do - {:ok, _} -> - send(pid, {:update, row_num, :success}) - {:error, _} -> - send(pid, {:update, row_num, :failure}) end - end) end diff --git a/lib/oli_web/router.ex b/lib/oli_web/router.ex index 77bcf604236..4cd7060083b 100644 --- a/lib/oli_web/router.ex +++ b/lib/oli_web/router.ex @@ -1302,6 +1302,7 @@ defmodule OliWeb.Router do get("/:project_slug/import/index", IngestController, :index_csv) post("/:project_slug/import/upload_csv", IngestController, :upload_csv) + get("/:project_slug/import/download", IngestController, :download_current) live("/:project_slug/import/csv", Import.CSVImportView) live("/ingest", Admin.Ingest) diff --git a/lib/oli_web/templates/ingest/index_csv.html.eex b/lib/oli_web/templates/ingest/index_csv.html.eex index b2d4cf88a99..eb5d21b9060 100644 --- a/lib/oli_web/templates/ingest/index_csv.html.eex +++ b/lib/oli_web/templates/ingest/index_csv.html.eex @@ -1,6 +1,6 @@

CSV Import

-

Upload a CSV file to inject data into existing project.

+

Upload a .csv file to inject data into existing project.


<%= form_for @conn, "upload_csv", [as: :upload_csv, multipart: true], fn f -> %> @@ -16,4 +16,9 @@ <% end %> +
+ +

Download a .csv + file for this project with all pages and containers and current values for nextgen attrs

+
From 88a1e5616def1e37ff730bcd6cfb0e51acafc3f5 Mon Sep 17 00:00:00 2001 From: Darren Siegel Date: Fri, 20 Oct 2023 15:04:44 -0400 Subject: [PATCH 2/5] headers --- lib/oli_web/controllers/ingest_controller.ex | 6 ++- lib/oli_web/live/import/csv_import_view.ex | 40 +++++++++++--------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/oli_web/controllers/ingest_controller.ex b/lib/oli_web/controllers/ingest_controller.ex index bc59e5c7c54..f89a4b608fb 100644 --- a/lib/oli_web/controllers/ingest_controller.ex +++ b/lib/oli_web/controllers/ingest_controller.ex @@ -42,7 +42,7 @@ defmodule OliWeb.IngestController do container_type_id = Oli.Resources.ResourceType.get_id_by_type("container") page_type_id = Oli.Resources.ResourceType.get_id_by_type("page") - content = Oli.Publishing.AuthoringResolver.full_hierarchy(project_slug) + rows = Oli.Publishing.AuthoringResolver.full_hierarchy(project_slug) |> Oli.Delivery.Hierarchy.flatten_hierarchy() |> Enum.map(fn %{ numbering: %{ @@ -83,6 +83,10 @@ defmodule OliWeb.IngestController do end end) + + headers = ["type", "title", "slug", "duration_minutes", "poster_image", "intro_video", "intro_content"] + + content = [headers | rows] |> CSV.encode() |> Enum.to_list() diff --git a/lib/oli_web/live/import/csv_import_view.ex b/lib/oli_web/live/import/csv_import_view.ex index b646f74124c..c31eb3558de 100644 --- a/lib/oli_web/live/import/csv_import_view.ex +++ b/lib/oli_web/live/import/csv_import_view.ex @@ -88,31 +88,35 @@ defmodule OliWeb.Import.CSVImportView do File.stream!(ingest_file) |> CSV.decode() |> Enum.to_list() - |> Enum.with_index(1) + |> Enum.with_index(0) |> Enum.map(fn {{:ok, [_type, _title, slug, duration_minutes, poster_image, intro_video, intro_content]}, row_num} -> - revision = Oli.Publishing.AuthoringResolver.from_revision_slug(project_slug, slug) + if row_num > 0 do - has_change? = duration_minutes != "" or poster_image != "" or intro_video != "" or intro_content != "" + revision = Oli.Publishing.AuthoringResolver.from_revision_slug(project_slug, slug) - if has_change? do - change = %{ - duration_minutes: if duration_minutes != "" do String.to_integer(duration_minutes) else nil end, - poster_image: if poster_image != "" do poster_image else nil end, - intro_video: if intro_video != "" do intro_video else nil end, - intro_content: if intro_content != "" do to_content.(intro_content) else nil end - } + has_change? = duration_minutes != "" or poster_image != "" or intro_video != "" or intro_content != "" - needs_change? = revision.duration_minutes != change.duration_minutes or revision.poster_image != change.poster_image or revision.intro_video != change.intro_video or revision.intro_content != change.intro_content + if has_change? do + change = %{ + duration_minutes: if duration_minutes != "" do String.to_integer(duration_minutes) else nil end, + poster_image: if poster_image != "" do poster_image else nil end, + intro_video: if intro_video != "" do intro_video else nil end, + intro_content: if intro_content != "" do to_content.(intro_content) else nil end + } - if needs_change? do - case Oli.Resources.update_revision(revision, change) do - {:ok, _} -> - IO.inspect change - send(pid, {:update, row_num, :success}) - {:error, _} -> - send(pid, {:update, row_num, :failure}) + needs_change? = revision.duration_minutes != change.duration_minutes or revision.poster_image != change.poster_image or revision.intro_video != change.intro_video or revision.intro_content != change.intro_content + + if needs_change? do + case Oli.Resources.update_revision(revision, change) do + {:ok, _} -> + IO.inspect change + send(pid, {:update, row_num, :success}) + {:error, _} -> + send(pid, {:update, row_num, :failure}) + end end + end end From 67ec2063d9f9ff985fa1e610888f28c005986eb5 Mon Sep 17 00:00:00 2001 From: darrensiegel Date: Sat, 21 Oct 2023 03:56:25 +0000 Subject: [PATCH 3/5] Auto format --- lib/oli_web/controllers/ingest_controller.ex | 118 +++++++++++-------- lib/oli_web/live/import/csv_import_view.ex | 62 +++++++--- 2 files changed, 117 insertions(+), 63 deletions(-) diff --git a/lib/oli_web/controllers/ingest_controller.ex b/lib/oli_web/controllers/ingest_controller.ex index d4726629ba1..8de27e56184 100644 --- a/lib/oli_web/controllers/ingest_controller.ex +++ b/lib/oli_web/controllers/ingest_controller.ex @@ -38,57 +38,80 @@ defmodule OliWeb.IngestController do end def download_current(conn, %{"project_slug" => project_slug}) do - container_type_id = Oli.Resources.ResourceType.get_id_by_type("container") page_type_id = Oli.Resources.ResourceType.get_id_by_type("page") - rows = Oli.Publishing.AuthoringResolver.full_hierarchy(project_slug) - |> Oli.Delivery.Hierarchy.flatten_hierarchy() - |> Enum.map(fn %{ - numbering: %{ - index: index, - level: level - }, - revision: %{ - resource_type_id: type_id, - title: title, - slug: slug, - poster_image: poster_image, - intro_content: intro_content, - intro_video: intro_video, - duration_minutes: duration_minutes, - purpose: purpose - } - } -> - - case type_id do - ^container_type_id -> - - c = case level do - 0 -> "Root Resource" - 1 -> "Unit #{index}" - _ -> "Module #{index}" - end - - [c, title, slug, duration_minutes |> v, poster_image |> v, intro_video |> v, intro_content |> m] - - ^page_type_id -> - - page_type = case purpose do - :foundation -> "foundation" - _ -> "exploration" - end - - [page_type, title, slug, duration_minutes |> v, poster_image |> v, intro_video |> v, intro_content |> m] - - end - end) - - headers = ["type", "title", "slug", "duration_minutes", "poster_image", "intro_video", "intro_content"] + rows = + Oli.Publishing.AuthoringResolver.full_hierarchy(project_slug) + |> Oli.Delivery.Hierarchy.flatten_hierarchy() + |> Enum.map(fn %{ + numbering: %{ + index: index, + level: level + }, + revision: %{ + resource_type_id: type_id, + title: title, + slug: slug, + poster_image: poster_image, + intro_content: intro_content, + intro_video: intro_video, + duration_minutes: duration_minutes, + purpose: purpose + } + } -> + case type_id do + ^container_type_id -> + c = + case level do + 0 -> "Root Resource" + 1 -> "Unit #{index}" + _ -> "Module #{index}" + end + + [ + c, + title, + slug, + duration_minutes |> v, + poster_image |> v, + intro_video |> v, + intro_content |> m + ] + + ^page_type_id -> + page_type = + case purpose do + :foundation -> "foundation" + _ -> "exploration" + end + + [ + page_type, + title, + slug, + duration_minutes |> v, + poster_image |> v, + intro_video |> v, + intro_content |> m + ] + end + end) - content = [headers | rows] - |> CSV.encode() - |> Enum.to_list() + headers = [ + "type", + "title", + "slug", + "duration_minutes", + "poster_image", + "intro_video", + "intro_content" + ] + + content = + [headers | rows] + |> CSV.encode() + |> Enum.to_list() conn |> send_download({:binary, content}, @@ -108,6 +131,7 @@ defmodule OliWeb.IngestController do end) |> Enum.join("|") end + defp m(_), do: "" defp v(nil), do: "" diff --git a/lib/oli_web/live/import/csv_import_view.ex b/lib/oli_web/live/import/csv_import_view.ex index 354ad978de0..19caaf65c49 100644 --- a/lib/oli_web/live/import/csv_import_view.ex +++ b/lib/oli_web/live/import/csv_import_view.ex @@ -74,10 +74,10 @@ defmodule OliWeb.Import.CSVImportView do end defp process_rows(pid, project_slug, ingest_file) do - to_content = fn content -> - children = String.split(content, "|") - |> Enum.map(fn p -> to_paragraph(p) end) + children = + String.split(content, "|") + |> Enum.map(fn p -> to_paragraph(p) end) %{ children: children @@ -88,37 +88,67 @@ defmodule OliWeb.Import.CSVImportView do |> CSV.decode() |> Enum.to_list() |> Enum.with_index(0) - |> Enum.map(fn {{:ok, [_type, _title, slug, duration_minutes, poster_image, intro_video, intro_content]}, row_num} -> - + |> Enum.map(fn {{:ok, + [ + _type, + _title, + slug, + duration_minutes, + poster_image, + intro_video, + intro_content + ]}, row_num} -> if row_num > 0 do - revision = Oli.Publishing.AuthoringResolver.from_revision_slug(project_slug, slug) - has_change? = duration_minutes != "" or poster_image != "" or intro_video != "" or intro_content != "" + has_change? = + duration_minutes != "" or poster_image != "" or intro_video != "" or intro_content != "" if has_change? do change = %{ - duration_minutes: if duration_minutes != "" do String.to_integer(duration_minutes) else nil end, - poster_image: if poster_image != "" do poster_image else nil end, - intro_video: if intro_video != "" do intro_video else nil end, - intro_content: if intro_content != "" do to_content.(intro_content) else nil end + duration_minutes: + if duration_minutes != "" do + String.to_integer(duration_minutes) + else + nil + end, + poster_image: + if poster_image != "" do + poster_image + else + nil + end, + intro_video: + if intro_video != "" do + intro_video + else + nil + end, + intro_content: + if intro_content != "" do + to_content.(intro_content) + else + nil + end } - - needs_change? = revision.duration_minutes != change.duration_minutes or revision.poster_image != change.poster_image or revision.intro_video != change.intro_video or revision.intro_content != change.intro_content + needs_change? = + revision.duration_minutes != change.duration_minutes or + revision.poster_image != change.poster_image or + revision.intro_video != change.intro_video or + revision.intro_content != change.intro_content if needs_change? do case Oli.Resources.update_revision(revision, change) do {:ok, _} -> - IO.inspect change + IO.inspect(change) send(pid, {:update, row_num, :success}) + {:error, _} -> send(pid, {:update, row_num, :failure}) end end - end - end end) end From 5e19f2e5651d06ad19249c3056b43279e1a9cfe6 Mon Sep 17 00:00:00 2001 From: Darren Siegel Date: Mon, 23 Oct 2023 09:33:53 -0400 Subject: [PATCH 4/5] remaining markdown rendering --- lib/oli/rendering/content/markdown.ex | 517 ++++++-------------------- 1 file changed, 115 insertions(+), 402 deletions(-) diff --git a/lib/oli/rendering/content/markdown.ex b/lib/oli/rendering/content/markdown.ex index 5ad51fba294..2ebe750cbdf 100644 --- a/lib/oli/rendering/content/markdown.ex +++ b/lib/oli/rendering/content/markdown.ex @@ -11,7 +11,6 @@ defmodule Oli.Rendering.Content.Markdown do alias Phoenix.HTML alias Oli.Rendering.Content.MathMLSanitizer alias HtmlSanitizeEx.Scrubber - alias Oli.Utils.Purposes alias Oli.Rendering.Content.ResourceSummary @behaviour Oli.Rendering.Content @@ -134,139 +133,63 @@ defmodule Oli.Rendering.Content.Markdown do missing_media_src(context, e) end - defp tableBorderClass(%{"border" => "hidden"}), do: "table-borderless" - defp tableBorderClass(_), do: "table-bordered" - - defp tableRowClass(%{"rowstyle" => "alternating"}), do: "table-striped" - defp tableRowClass(_), do: "" - - def table(%Context{} = context, next, attrs) do - - # We want to ensure that tables are always wrapped - # in a figure element, even if there is no caption. When - # a caption attr is present but "empty" we still want the figure, - # but not an empty
. The
element with its - # responsive-embed class is needed in all cases to acheive correct - # table display. - - wrapping_fn = - case attrs do - %{"caption" => ""} -> &figure_only/3 - %{"caption" => nil} -> &figure_only/3 - %{"caption" => [%{"children" => [%{"text" => ""}], "type" => "p"}]} -> &figure_only/3 - %{"caption" => _an_actual_caption} -> &captioned_content/3 - _ -> &figure_only/3 - end - - wrapping_fn.(context, attrs, [ - "", + def table(%Context{} = _context, next, _attrs) do + [ + "\n", next.(), - "
\n" - ]) + "\n\n" + ] end def tr(%Context{} = _context, next, _) do - ["", next.(), "\n"] - end - - defp maybeColSpan(%{"colspan" => colspan}) do - " colspan='#{colspan}'" - end - - defp maybeColSpan(_) do - "" - end - - defp maybeRowSpan(%{"rowspan" => rowspan}) do - " rowspan='#{rowspan}'" - end - - defp maybeRowSpan(_) do - "" + ["\n|", next.()] end - defp maybeTextAlign(%{"align" => alignment}) do - " class='text-#{alignment}'" - end - - defp maybeTextAlign(_) do - "" + def th(%Context{} = _context, next, _attrs) do + [next.(), "|"] end - defp maybeAlign(attrs) do - maybeColSpan(attrs) <> maybeRowSpan(attrs) <> maybeTextAlign(attrs) + def td(%Context{} = _context, next, _attrs) do + [next.(), "|"] end - def th(%Context{} = _context, next, attrs) do - ["", next.(), "\n"] + def tc(%Context{} = _context, next, _attrs) do + [next.(), "|"] end - def td(%Context{} = _context, next, attrs) do - ["", next.(), "\n"] - end - - def tc(%Context{} = _context, next, attrs) do - [click_class, audio_element, play_code, _] = - case attrs["audioSrc"] do - nil -> ["", "", "", ""] - src -> ["clickable" | audio_player(src)] - end - - pronouns = - case attrs["pronouns"] do - nil -> [] - pronouns -> ["", pronouns, " "] - end - - [ - "", - pronouns, - next.(), - audio_element, - "\n" - ] - end - - def ol(%Context{} = _context, next, %{"style" => style}) do - ["
    ", next.(), "
\n"] + def ol(%Context{} = _context, next, %{"style" => _style}) do + ["\n", next.(), "\n\n"] end def ol(%Context{} = _context, next, _) do - ["
    ", next.(), "
\n"] + ["\n", next.(), "\n\n"] end def dl(%Context{}, next, title, %{}) do - [ - "

", - title.(), - "

\n", - "
", - next.(), - "
\n" - ] + ["\n", title, "\n", next.(), "\n\n"] end def dt(%Context{}, next, %{}) do - ["
", next.(), "
\n"] + [next.(), "\n"] end def dd(%Context{}, next, %{}) do - ["
", next.(), "
\n"] + [": ", next.(), "\n"] end - def ul(%Context{} = _context, next, %{"style" => style}) do - ["
    ", next.(), "
\n"] + def ul(%Context{} = _context, next, %{"style" => _style}) do + ["\n", next.(), "\n\n"] end def ul(%Context{} = _context, next, _) do - ["
    ", next.(), "
\n"] + ["\n", next.(), "\n\n"] end def li(%Context{} = _context, next, _) do - ["
  • ", next.(), "
  • \n"] + ["1. ", next.(), "\n"] end - def conjugation(%Oli.Rendering.Context{}, render_table, render_pronunciation, attrs) do + def conjugation(%Oli.Rendering.Context{}, render_table, _render_pronunciation, attrs) do title = case attrs["title"] do nil -> "" @@ -279,51 +202,40 @@ defmodule Oli.Rendering.Content.Markdown do verb -> verb end - [ - "
    ", - "
    ", - title, - "
    ", - "
    ", - verb, - render_pronunciation.(), - "
    ", - render_table.(), - "
    " - ] + adhoc_group("Conjugation", [title, "\n", "verb: #{verb}\n", render_table.()]) end def dialog(%Context{}, next, %{"title" => title}) do - ["

    ", title, "

    ", next.(), "
    "] + adhoc_group("Dialog", [title, "\n", next.()]) end def dialog(%Context{}, next, _) do - ["
    ", next.(), "
    "] + adhoc_group("Dialog", next.()) end def dialog_speaker_portrait(image) do - "" + [ + "![dialog speaker portrait](#{escape_xml!(image)})\n\n", + ] end def dialog_speaker_portrait() do - ~s|| + "" end def dialog_speaker(speaker_id, %{"speakers" => speakers}) do speaker = Enum.find(speakers, fn speaker -> speaker["id"] == speaker_id end) + case speaker do + %{"name" => name, "image" => image} -> + [dialog_speaker_portrait(image), "Speaker: ", name, "\n"] - ["
    "] ++ - case speaker do - %{"name" => name, "image" => image} -> - [dialog_speaker_portrait(image), "
    ", name, "
    "] + %{"name" => name} -> + [dialog_speaker_portrait(), "Speaker: ", name, "\n"] - %{"name" => name} -> - [dialog_speaker_portrait(), "
    ", name, "
    "] - - _ -> - ["
    ", "Unknown Speaker", "
    "] - end ++ - ["
    "] + _ -> + ["Speaker: Unknown Speaker \n"] + end ++ + [""] end def dialog_line_class(speaker_id, %{"speakers" => speakers}) do @@ -339,67 +251,22 @@ defmodule Oli.Rendering.Content.Markdown do def dialog_line(%Context{}, next, %{"speaker" => speaker_id}, dialog) do [ - "
    ", dialog_speaker(speaker_id, dialog), - "
    ", next.(), - "
    " + "\n" ] end def definition_meaning(%Context{} = _context, next, _) do - ["
  • ", next.(), "
  • \n"] + ["Meaning: ", next.(), "\n"] end def definition_translation(%Context{} = _context, next, _) do - ["", next.(), " \n"] - end - - defp audio_player(nil), do: ["", "", ""] - - defp audio_player(src) do - audio_id = UUID.uuid4() - # See app.ts for toggleAudio() - play_code = "window.toggleAudio(document.getElementById(\"#{audio_id}\"));" - audio_element = "" - [audio_element, play_code, audio_id] - end - - def pronunciation(%Context{} = _context, next, element) do - case element["src"] do - nil -> - ["", next.(), "\n"] - - src -> - [audio_element, play_code, _] = audio_player(src) - - [ - "", - ~s||, - "", - audio_element, - next.(), - "\n" - ] - end + ["Translation: ", next.(), "\n"] end - defp maybePronunciationHeader(%{"pronunciation" => pronunciation}) do - if Oli.Activities.ParseUtils.has_content?(pronunciation) do - "Pronunciation: " - else - "" - end - end - - defp maybePronunciationHeader(_), do: "" - - defp meaningClass(meanings) do - case Enum.count(meanings) do - 0 -> "meanings-empty" - 1 -> "meanings-single" - _ -> "meanings" - end + def pronunciation(%Context{} = _context, next, _element) do + ["Pronunciation: ", next.()] end def definition( @@ -407,32 +274,24 @@ defmodule Oli.Rendering.Content.Markdown do render_translation, render_pronunciation, render_meaning, - %{"term" => term, "meanings" => meanings} = element + %{"term" => term} = _element ) do - [ - "
    ", + + adhoc_group("Definition", [ term, - "
    (definition) ", - maybePronunciationHeader(element), + "\n", render_pronunciation.(), - "", render_translation.(), - "
      ", - render_meaning.(), - "
    \n" - ] + render_meaning.() + ]) end def foreign( - %Oli.Rendering.Context{learning_language: learning_language}, + %Oli.Rendering.Context{learning_language: _learning_language}, next, - attrs + _attrs ) do - [ - "", - next.(), - "" - ] + next.() end def formula_class(false), do: "formula" @@ -446,7 +305,7 @@ defmodule Oli.Rendering.Content.Markdown do %{"subtype" => "latex", "src" => src, "legacyBlockRendered" => true}, true ) do - ["\\(", escape_xml!(src), "\\)\n"] + ["$$ ", escape_xml!(src), " $$\n"] end def formula( @@ -455,7 +314,7 @@ defmodule Oli.Rendering.Content.Markdown do %{"subtype" => "latex", "src" => src}, true ) do - ["\\(", escape_xml!(src), "\\)\n"] + ["$$ ", escape_xml!(src), " $$\n"] end def formula( @@ -464,29 +323,27 @@ defmodule Oli.Rendering.Content.Markdown do %{"subtype" => "latex", "src" => src}, false ) do - ["\\[", escape_xml!(src), "\\]\n"] + ["$$ ", escape_xml!(src), " $$\n"] end def formula( %Oli.Rendering.Context{} = _context, _next, %{"subtype" => "mathml", "src" => src}, - inline + _inline ) do [ - "", Scrubber.scrub(src, MathMLSanitizer), - "\n" + "\n" ] end def figure(%Context{} = _context, render_children, render_title, _) do [ - "
    ", render_title.(), - "
    ", + "\n", render_children.(), - "
    \n" + "\n" ] end @@ -495,7 +352,7 @@ defmodule Oli.Rendering.Content.Markdown do end def math(%Context{} = _context, next, _) do - ["
    \\[", next.(), "\\]
    \n"] + ["$$ ", next.(), " $$\n"] end def math_line(%Context{} = _context, next, _) do @@ -504,12 +361,12 @@ defmodule Oli.Rendering.Content.Markdown do # V2 - presence of "code" attr def code( - %Context{} = context, + %Context{} = _context, _next, %{ "language" => language, "code" => code - } = attrs + } = _attrs ) do safe_language = escape_xml!(language) @@ -520,18 +377,20 @@ defmodule Oli.Rendering.Content.Markdown do "text" end - captioned_content(context, attrs, [ - ~s|
    #{escape_xml!(code)}
    \n| - ]) + [ + "```#{language}\n", + escape_xml!(code), + "\n```\n" + ] end # V1 - content as children def code( - %Context{} = context, + %Context{} = _context, next, %{ "language" => language - } = attrs + } = _attrs ) do safe_language = escape_xml!(language) @@ -542,67 +401,38 @@ defmodule Oli.Rendering.Content.Markdown do "text" end - captioned_content(context, attrs, [ - ~s|
    |,
    +    [
    +      "```#{language}\n",
           next.(),
    -      "
    \n" - ]) + "\n```\n" + ] end def code( - %Context{} = context, + %Context{} = _dcontext, next, attrs ) do {_error_id, _error_msg} = log_error("Malformed content element. Missing language attribute", attrs) - captioned_content(context, attrs, [ - ~s|
    |,
    -      next.(),
    -      "
    \n" - ]) - end - - def code_line(%Context{} = _context, next, _) do - [next.(), "\n"] - end - - def command_button(%Context{} = _context, next, %{ - "style" => style, - "target" => target, - "message" => message - }) do - css_class = - case style do - "link" -> "btn btn-link command-button" - _ -> "btn btn-primary command-button" - end - [ - "", + "```\n", next.(), - "" + "\n```\n" ] end - def command_button(%Context{} = _context, next, %{ - "target" => target, - "message" => message - }) do - [ - "", - next.(), - "" - ] + def code_line(%Context{} = _context, next, _) do + [next.(), "\n"] end - def command_button(%Context{} = _context, next, _attrs) do - [next.()] + def command_button(%Context{} = _context, _next, _) do + "" end def blockquote(%Context{} = _context, next, _) do - ["
    ", next.(), "
    \n"] + ["> ", next.(), "\n\n"] end def a(%Context{} = context, next, %{"href" => href}) do @@ -613,18 +443,15 @@ defmodule Oli.Rendering.Content.Markdown do end end - def a(%Context{} = context, next, attrs) do - {_error_id, _error_msg} = - log_error("Malformed content element. Missing href attribute", attrs) - - external_link(context, next, "#") + def a(%Context{} = _context, next, _attrs) do + next.() end defp internal_link( %Context{section_slug: section_slug, mode: mode, project_slug: project_slug}, next, href, - opts \\ [] + _opts \\ [] ) do href = case section_slug do @@ -648,80 +475,32 @@ defmodule Oli.Rendering.Content.Markdown do end end - target_rel = - case Keyword.get(opts, :target) do - nil -> "" - target -> ~s| target="#{target}" rel="noreferrer"| - end - - [~s||, next.(), "\n"] + ["[", next.(), "](#{href})"] end defp external_link(%Context{} = _context, next, href) do - [ - ~s||, - next.(), - "\n" - ] + ["[", next.(), "](#{href})"] end - def page_link(%Context{resource_summary_fn: resource_summary_fn} = context, _next, %{ - "idref" => idref, - "purpose" => purpose + def page_link(%Context{resource_summary_fn: resource_summary_fn} = _context, _next, %{ + "idref" => idref }) do %ResourceSummary{title: title, slug: slug} = resource_summary_fn.(idref) href = "/course/link/#{slug}" - [ - ~s|" - ] + ["[", escape_xml!(title), "](#{href})"] end - def cite(%Context{} = context, next, a) do - bib_references = Map.get(context, :bib_app_params, []) - bib_entry = Enum.find(bib_references, fn x -> x.id == Map.get(a, "bibref") end) - - if bib_entry != nil do - [~s| - [#{bib_entry.ordinal}] - \n|] - else - ["", next.(), "\n"] - end + def cite(%Context{} = _context, next, _a) do + next.() end - def popup(%Context{} = context, _next, element) do - {:safe, rendered} = - OliWeb.Common.React.component( - context, - "Components.DeliveryElementRenderer", - %{ - "element" => element - }, - html_element: "span" - ) - - rendered + def popup(%Context{} = _context, _next, _element) do + [] end - def selection(%Context{} = context, _, selection) do - Oli.Rendering.Content.Selection.render(context, selection, true) + def selection(%Context{} = _context, _, _selection) do + [] end defp revision_slug_from_course_link(href) do @@ -733,47 +512,20 @@ defmodule Oli.Rendering.Content.Markdown do escape_xml!(text) |> wrap_with_marks(text_entity) end - def error(%Context{} = _context, element, error) do - case error do - {:unsupported, error_id, _error_msg} -> - [ - ~s|
    Content element type '#{element["type"]}' is not supported. Please contact support with issue ##{error_id}
    \n| - ] - - {:invalid, error_id, _error_msg} -> - [ - ~s|
    Content element is invalid. Please contact support with issue ##{error_id}
    \n| - ] - - {_, error_id, _error_msg} -> - [ - ~s|
    An error occurred while rendering content. Please contact support with issue ##{error_id}
    \n| - ] - end + def error(%Context{} = _context, _element, _error) do + "rendering error\n\n" end def example(%Context{} = _context, next, _) do - [ - ~s|
    Example
    |, - next.(), - "
    \n" - ] + adhoc_group("Example", next.()) end def learn_more(%Context{} = _context, next, _) do - [ - ~s|
    Learn more
    |, - next.(), - "
    \n" - ] + adhoc_group("Learn More", next.()) end def manystudentswonder(%Context{} = _context, next, _) do - [ - ~s|
    Many Students Wonder
    |, - next.(), - "
    \n" - ] + adhoc_group("Many Students Wonder", next.()) end def escape_xml!(text) do @@ -784,19 +536,19 @@ defmodule Oli.Rendering.Content.Markdown do defp wrap_with_marks(text, text_entity) do supported_mark_tags = %{ - "em" => "em", - "strong" => "strong", - "mark" => "mark", - "del" => "del", - "var" => "var", - "term" => "term", - "code" => "code", - "sub" => "sub", - "doublesub" => "doublesub", - "deemphasis" => "deemphasis", - "sup" => "sup", - "underline" => "underline", - "strikethrough" => "strikethrough" + "em" => "*", + "strong" => "**", + "mark" => "==", + "del" => "", + "var" => "", + "term" => "", + "code" => "`", + "sub" => "~", + "doublesub" => "", + "deemphasis" => "", + "sup" => "^", + "underline" => "", + "strikethrough" => "~~" } marks = @@ -813,51 +565,12 @@ defmodule Oli.Rendering.Content.Markdown do text, fn mark, acc -> case mark do - "term" -> ~s|#{acc}| - "underline" -> ~s|#{acc}| - "strikethrough" -> ~s|#{acc}| - "doublesub" -> ~s|#{acc}| - "deemphasis" -> ~s|#{acc}| - _ -> "<#{mark}>#{acc}" + _ -> "#{mark}#{acc}#{mark}" end end ) end - # Accessible captions are created using a combination of the
    and
    elements. - defp captioned_content(_context, %{"caption" => ""} = _attrs, content), do: content - - defp captioned_content(%Context{} = context, %{"caption" => caption_content} = _attrs, content) do - [~s|
    |] ++ - [~s|
    |] ++ - content ++ - [~s|
    |] ++ - [caption(context, caption_content)] ++ - ["
    "] ++ - ["
    "] ++ - ["
    "] - end - - defp captioned_content(_context, _attrs, content), do: content - - defp caption(_context, content) when is_binary(content) do - escape_xml!(content) - end - - defp caption(context, content) do - Oli.Rendering.Content.render(context, content, __MODULE__) - end - - defp figure_only(_context, _attrs, content) do - [ - ~s|
    |, - ~s|
    |, - content, - "
    ", - "
    " - ] - end - defp missing_media_src(%Context{render_opts: render_opts} = context, element) do {error_id, error_msg} = log_error("Malformed content element. Missing src attribute", element) From 04c67739ebb05b38b69d6164bcf8bc2ffeb3dcec Mon Sep 17 00:00:00 2001 From: darrensiegel Date: Mon, 23 Oct 2023 13:51:26 +0000 Subject: [PATCH 5/5] Auto format --- lib/oli/rendering/content/markdown.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/oli/rendering/content/markdown.ex b/lib/oli/rendering/content/markdown.ex index d5855cc9b90..11f565b113f 100644 --- a/lib/oli/rendering/content/markdown.ex +++ b/lib/oli/rendering/content/markdown.ex @@ -202,7 +202,7 @@ defmodule Oli.Rendering.Content.Markdown do verb -> verb end - adhoc_group("Conjugation", [title, "\n", "verb: #{verb}\n", render_table.()]) + adhoc_group("Conjugation", [title, "\n", "verb: #{verb}\n", render_table.()]) end def dialog(%Context{}, next, %{"title" => title}) do @@ -215,7 +215,7 @@ defmodule Oli.Rendering.Content.Markdown do def dialog_speaker_portrait(image) do [ - "![dialog speaker portrait](#{escape_xml!(image)})\n\n", + "![dialog speaker portrait](#{escape_xml!(image)})\n\n" ] end @@ -225,6 +225,7 @@ defmodule Oli.Rendering.Content.Markdown do def dialog_speaker(speaker_id, %{"speakers" => speakers}) do speaker = Enum.find(speakers, fn speaker -> speaker["id"] == speaker_id end) + case speaker do %{"name" => name, "image" => image} -> [dialog_speaker_portrait(image), "Speaker: ", name, "\n"] @@ -235,7 +236,7 @@ defmodule Oli.Rendering.Content.Markdown do _ -> ["Speaker: Unknown Speaker \n"] end ++ - [""] + [""] end def dialog_line_class(speaker_id, %{"speakers" => speakers}) do @@ -276,7 +277,6 @@ defmodule Oli.Rendering.Content.Markdown do render_meaning, %{"term" => term} = _element ) do - adhoc_group("Definition", [ term, "\n",