Packages
surface
0.11.5
0.12.3
0.12.2
0.12.1
0.12.0
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.1
0.1.0
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha.0
A component based library for Phoenix LiveView
Current section
Files
Jump to
Current section
Files
lib/surface/view.ex
defmodule Surface.View do
@moduledoc """
Use this module on regular Phoenix views to enable .sface templates
## Examples
To make sface templates available on all your views, add to the `view` function on `lib/your_app_web.ex`:
defmodule YourAppWeb do
# ...
def view do
use Phoenix.View,
root: "lib/your_app_web/templates",
namespace: YourAppWeb
# ...
use Surface.View, root: "lib/your_app_web/templates"
end
end
If you want to make it available only on specific views, you can add a new function on the `lib/your_app_web.ex`:
defmodule YourAppWeb do
# ...
def surface_view(options \\ []) do
[
view(options),
quote do
use Surface.View, root: "lib/your_app_web/templates"
end
]
end
end
Then, replace `use YourAppWeb, :view` with `use YourAppWeb, :surface_view` on the views you want to enable sface
templates.
"""
defmacro __using__(opts \\ []) do
%{module: module} = __CALLER__
root = opts[:root] || raise(ArgumentError, "expected :root to be given as an option")
renders =
for {name, _} <- templates(module, root) do
quote do
def render("#{unquote(name)}.html", assigns) do
__render_surface__(unquote(name), assigns)
end
end
end
before_compile =
quote do
@surface_view_root unquote(root)
@before_compile unquote(__MODULE__)
end
[before_compile | renders]
end
defmacro __before_compile__(env) do
root = Module.get_attribute(env.module, :surface_view_root)
render_funs =
for {name, path} <- templates(env.module, root) do
ast =
path
|> File.read!()
|> Surface.Compiler.compile(1, env, path)
|> Surface.Compiler.to_live_struct()
quote do
@file unquote(path)
@external_resource unquote(path)
defp __render_surface__(unquote(name), var!(assigns)) do
unquote(ast)
end
end
end
mix_recompile =
quote do
# Override definition injected by Phoenix.Template
defoverridable __mix_recompile__?: 0
@doc false
def __mix_recompile__? do
super() || __surface_recompile__?()
end
@doc false
def __surface_recompile__? do
unquote(hash(env.module, root)) != Surface.View.hash(unquote(env.module), unquote(root))
end
end
[mix_recompile | render_funs]
end
defp templates(module, root) do
module
|> templates_wildcard(root)
|> Path.wildcard()
|> Enum.map(&{template_name(&1), &1})
end
defp templates_wildcard(module, root) do
view_name =
module
|> Module.split()
|> Enum.drop(1)
|> Enum.map(&Macro.underscore/1)
|> Enum.join("/")
|> String.replace_trailing("_view", "")
"#{root}/#{view_name}/*.sface"
end
defp template_name(path) do
path
|> Path.basename()
|> String.replace_trailing(".sface", "")
end
@doc """
Returns the hash of all template paths for the given view.
Used by Surface to check if a given view requires recompilation when a new template is added.
"""
def hash(module, root) do
module
|> templates_wildcard(root)
|> Path.wildcard()
|> Enum.sort()
|> :erlang.md5()
end
end