Add first step of creating an Article
This commit is contained in:
@ -6,7 +6,7 @@ defmodule Outlook.Articles do
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Articles.{Article,RawHtmlInput}
|
||||
|
||||
@doc """
|
||||
Returns the list of articles.
|
||||
@ -101,4 +101,8 @@ defmodule Outlook.Articles do
|
||||
def change_article(%Article{} = article, attrs \\ %{}) do
|
||||
Article.changeset(article, attrs)
|
||||
end
|
||||
|
||||
def change_raw_html_input(%RawHtmlInput{} = raw_html_input, attrs \\ %{}) do
|
||||
RawHtmlInput.changeset(raw_html_input, attrs)
|
||||
end
|
||||
end
|
||||
|
||||
16
lib/outlook/articles/raw_html_input.ex
Normal file
16
lib/outlook/articles/raw_html_input.ex
Normal file
@ -0,0 +1,16 @@
|
||||
defmodule Outlook.Articles.RawHtmlInput do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
embedded_schema do
|
||||
field :content, :string
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(html_input, attrs) do
|
||||
html_input
|
||||
|> cast(attrs, [:content])
|
||||
|> validate_required([:content])
|
||||
|> validate_length(:content, min: 200)
|
||||
end
|
||||
end
|
||||
14
lib/outlook/html_preparations.ex
Normal file
14
lib/outlook/html_preparations.ex
Normal file
@ -0,0 +1,14 @@
|
||||
defmodule Outlook.HtmlPreparations do
|
||||
@moduledoc """
|
||||
The HtmlPreparations context.
|
||||
"""
|
||||
|
||||
alias Outlook.HtmlPreparations.HtmlPreparation
|
||||
|
||||
def convert_raw_html_input(html) do
|
||||
html
|
||||
|> Floki.parse_fragment!
|
||||
|> HtmlPreparation.floki_to_internal
|
||||
|> HtmlPreparation.set_sibling_with
|
||||
end
|
||||
end
|
||||
65
lib/outlook/html_preparations/html_preparation.ex
Normal file
65
lib/outlook/html_preparations/html_preparation.ex
Normal file
@ -0,0 +1,65 @@
|
||||
defmodule Outlook.HtmlPreparations.HtmlPreparation do
|
||||
import Ecto.UUID, only: [generate: 0]
|
||||
|
||||
alias Outlook.InternalTree.InternalNode
|
||||
|
||||
@block_elements ["address","article","aside","blockquote","canvas","dd","div","dl","dt","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hr","li","main","nav","noscript","ol","p","pre","section","table","tfoot","ul","video"]
|
||||
# @inline_elements ["a","abbr","acronym","b","bdo","big","br","button","cite","code","dfn","em","i","img","input","kbd","label","map","object","output","q","samp","script","select","small","span","strong","sub","sup","textarea","time","tt","u","var"]
|
||||
|
||||
defp clean_atts_to_map(atts) do
|
||||
atts_to_keep = ~w(href src)
|
||||
atts_to_rename = ~w(class style src-set)
|
||||
atts
|
||||
|> Enum.reject(fn {k,_} -> k not in (atts_to_keep ++ atts_to_rename) end)
|
||||
|> Enum.reject(fn {_,v} -> v == "" end)
|
||||
|> Enum.map(fn {k,v} -> {k in atts_to_rename && "#{k}-old" || k, v} end)
|
||||
|> Enum.map(fn {k,v} -> {String.to_atom(k),v} end)
|
||||
|> Enum.into(%{})
|
||||
end
|
||||
|
||||
def floki_to_internal [ { tag, attributes, content } | rest ] do
|
||||
[ %InternalNode{
|
||||
name: tag,
|
||||
attributes: clean_atts_to_map(attributes),
|
||||
type: :element,
|
||||
uuid: generate(),
|
||||
content: floki_to_internal(content)
|
||||
} | floki_to_internal(rest) ]
|
||||
end
|
||||
|
||||
def floki_to_internal [ "" <> textnode | rest ] do
|
||||
[ %InternalNode{
|
||||
type: :text,
|
||||
uuid: generate(),
|
||||
content: textnode
|
||||
} | floki_to_internal(rest) ]
|
||||
end
|
||||
|
||||
def floki_to_internal [ {:comment, comment} | rest ] do
|
||||
[ %InternalNode{
|
||||
type: :comment,
|
||||
uuid: generate(),
|
||||
content: comment
|
||||
} | floki_to_internal(rest) ]
|
||||
end
|
||||
|
||||
def floki_to_internal([ ]), do: ( [ ] )
|
||||
|
||||
|
||||
def set_sibling_with([ %{type: :element} = node | rest ]) do
|
||||
[ %InternalNode{ node |
|
||||
sibling_with: node.name in @block_elements && :block || :inline,
|
||||
content: set_sibling_with(node.content)
|
||||
} | set_sibling_with(rest) ]
|
||||
end
|
||||
|
||||
def set_sibling_with([ node | rest ]) do
|
||||
sib_with = case node.type do
|
||||
:text -> Regex.match?(~r/^\s*$/, node.content) && :both || :inline
|
||||
:comment -> :both
|
||||
end
|
||||
[ %InternalNode{ node | sibling_with: sib_with } | set_sibling_with(rest) ]
|
||||
end
|
||||
|
||||
def set_sibling_with([ ]), do: ( [ ] )
|
||||
end
|
||||
4
lib/outlook/internal_tree/internal_node.ex
Normal file
4
lib/outlook/internal_tree/internal_node.ex
Normal file
@ -0,0 +1,4 @@
|
||||
defmodule Outlook.InternalTree.InternalNode do
|
||||
@derive Jason.Encoder
|
||||
defstruct name: "", attributes: %{}, type: :atom, uuid: "", content: [], sibling_with: nil
|
||||
end
|
||||
Reference in New Issue
Block a user