changed CHANGELOG.md
 
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
8
+ ## [0.3.0] - 2020-02-04
9
+
10
+ ### Added
11
+
12
+ - `view_module` option to `Adminable.Plug` to allow users to use their own views and templates
13
+ - `mix adminable.gen.view` to export Adminable's view and templates for modification
14
+
8
15
## [0.2.0] - 2019-12-23
9
16
10
17
### Updated
changed README.md
 
@@ -12,7 +12,7 @@ by adding `adminable` to your list of dependencies in `mix.exs`:
12
12
```elixir
13
13
def deps do
14
14
[
15
- {:adminable, "~> 0.1.0"}
15
+ {:adminable, "~> 0.3.0"}
16
16
]
17
17
end
18
18
```
 
@@ -46,8 +46,25 @@ scope "/admin" do
46
46
forward("/", Adminable.Plug, [
47
47
otp_app: :my_app,
48
48
repo: MyApp.Repo,
49
- schemas: [MyApp.User]
49
+ schemas: [MyApp.User],
50
+ view_module: MyAppWeb.Adminable.AdminView
50
51
layout: {MyAppWeb.LayoutView, "app.html"}
51
52
])
52
53
end
53
54
```
55
+
56
+ Arguments
57
+
58
+ - `otp_app` - Your app
59
+ - `repo` - Your app's Repo
60
+ - `schemas` - The schemas to make Admin sections for
61
+ - `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
62
+ - `layout` - (Optional) The layout to use
63
+
64
+ ## Exporting View and Templates
65
+
66
+ To export Adminable's AdminView and templates for modification, run:
67
+
68
+ ```bash
69
+ mix adminable.gen.view MyWebModule
70
+ ```
changed hex_metadata.config
 
@@ -4,11 +4,13 @@
4
4
<<"Create admin interfaces for Ecto schemas in Phoenix apps">>}.
5
5
{<<"elixir">>,<<"~> 1.8">>}.
6
6
{<<"files">>,
7
- [<<"lib">>,<<"lib/adminable.ex">>,<<"lib/adminable">>,
8
- <<"lib/adminable/router.ex">>,<<"lib/adminable/views">>,
9
- <<"lib/adminable/views/admin_view.ex">>,
10
- <<"lib/adminable/views/pagination_view.ex">>,
11
- <<"lib/adminable/views/field.ex">>,<<"lib/adminable/views/layout_view.ex">>,
7
+ [<<"lib">>,<<"lib/mix">>,<<"lib/mix/tasks">>,
8
+ <<"lib/mix/tasks/adminable.gen.view.ex">>,<<"lib/adminable.ex">>,
9
+ <<"lib/adminable">>,<<"lib/adminable/router.ex">>,
10
+ <<"lib/adminable/exporter.ex">>,<<"lib/adminable/views">>,
11
+ <<"lib/adminable/views/admin_view.ex">>,<<"lib/adminable/views/field.ex">>,
12
+ <<"lib/adminable/views/layout_view.ex">>,
13
+ <<"lib/adminable/views/view_helpers.ex">>,
12
14
<<"lib/adminable/error_helpers.ex">>,
13
15
<<"lib/adminable/admin_controller.ex">>,<<"lib/adminable/templates">>,
14
16
<<"lib/adminable/templates/layout">>,
 
@@ -60,4 +62,4 @@
60
62
{<<"optional">>,false},
61
63
{<<"repository">>,<<"hexpm">>},
62
64
{<<"requirement">>,<<"~> 1.0">>}]]}.
63
- {<<"version">>,<<"0.2.0">>}.
65
+ {<<"version">>,<<"0.3.0">>}.
changed lib/adminable.ex
 
@@ -27,11 +27,20 @@ defmodule Adminable do
27
27
forward("/", Adminable.Plug, [
28
28
otp_app: :my_app,
29
29
repo: MyApp.Repo,
30
- schemas: [MyApp.User]
30
+ schemas: [MyApp.User],
31
+ view_module: MyAppWeb.Adminable.AdminView
31
32
layout: {MyAppWeb.LayoutView, "app.html"}
32
33
])
33
34
end
34
35
```
36
+
37
+ Arguments
38
+
39
+ * `otp_app` - Your app
40
+ * `repo` - Your app's Repo
41
+ * `schemas` - The schemas to make Admin sections for
42
+ * `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
43
+ * `layout` - (Optional) The layout to use
35
44
"""
36
45
37
46
@doc """
changed lib/adminable/admin_controller.ex
 
@@ -3,7 +3,6 @@ defmodule Adminable.AdminController do
3
3
4
4
use Phoenix.Controller, namespace: Adminable
5
5
import Plug.Conn
6
- alias Adminable.Router.Helpers, as: Routes
7
6
8
7
def dashboard(conn, _params) do
9
8
schemas = Map.keys(conn.assigns.schemas)
 
@@ -14,6 +13,7 @@ defmodule Adminable.AdminController do
14
13
15
14
conn
16
15
|> put_layout(conn.assigns.layout)
16
+ |> put_view(conn.assigns.view_module)
17
17
|> render("dashboard.html", opts)
18
18
end
19
19
 
@@ -40,6 +40,7 @@ defmodule Adminable.AdminController do
40
40
41
41
conn
42
42
|> put_layout(conn.assigns.layout)
43
+ |> put_view(conn.assigns.view_module)
43
44
|> render("index.html", opts)
44
45
end
45
46
 
@@ -56,6 +57,7 @@ defmodule Adminable.AdminController do
56
57
57
58
conn
58
59
|> put_layout(conn.assigns.layout)
60
+ |> put_view(conn.assigns.view_module)
59
61
|> render("new.html", opts)
60
62
end
61
63
 
@@ -70,7 +72,7 @@ defmodule Adminable.AdminController do
70
72
{:ok, _created} ->
71
73
conn
72
74
|> put_flash(:info, "#{String.capitalize(schema)} created!")
73
- |> redirect(to: Routes.admin_path(conn, :index, schema))
75
+ |> redirect(to: Adminable.Router.Helpers.admin_path(conn, :index, schema))
74
76
75
77
{:error, changeset} ->
76
78
opts = [
 
@@ -83,6 +85,7 @@ defmodule Adminable.AdminController do
83
85
|> put_flash(:error, "#{String.capitalize(schema)} failed to create!")
84
86
|> put_status(:unprocessable_entity)
85
87
|> put_layout(conn.assigns.layout)
88
+ |> put_view(conn.assigns.view_module)
86
89
|> render("new.html", opts)
87
90
end
88
91
end
 
@@ -105,6 +108,7 @@ defmodule Adminable.AdminController do
105
108
106
109
conn
107
110
|> put_layout(conn.assigns.layout)
111
+ |> put_view(conn.assigns.view_module)
108
112
|> render("edit.html", opts)
109
113
end
110
114
 
@@ -119,7 +123,7 @@ defmodule Adminable.AdminController do
119
123
{:ok, _updated_model} ->
120
124
conn
121
125
|> put_flash(:info, "#{String.capitalize(schema)} ID #{pk} updated!")
122
- |> redirect(to: Routes.admin_path(conn, :index, schema))
126
+ |> redirect(to: Adminable.Router.Helpers.admin_path(conn, :index, schema))
123
127
124
128
{:error, changeset} ->
125
129
opts = [
 
@@ -133,6 +137,7 @@ defmodule Adminable.AdminController do
133
137
|> put_flash(:error, "#{String.capitalize(schema)} ID #{pk} failed to update!")
134
138
|> put_status(:unprocessable_entity)
135
139
|> put_layout(conn.assigns.layout)
140
+ |> put_view(conn.assigns.view_module)
136
141
|> render("edit.html", opts)
137
142
end
138
143
end
added lib/adminable/exporter.ex
 
@@ -0,0 +1,61 @@
1
+ defmodule Adminable.Exporter do
2
+ @moduledoc """
3
+ Exports templates and a view module.
4
+ This allows for apps that use Adminable to modify templates
5
+ to their liking.
6
+ """
7
+
8
+ template_paths = "lib/adminable/templates/admin/**/*.html.eex" |> Path.wildcard() |> Enum.sort()
9
+
10
+ templates =
11
+ for template_path <- template_paths do
12
+ @external_resource Path.relative_to_cwd(template_path)
13
+ {Path.basename(template_path), File.read!(template_path)}
14
+ end
15
+
16
+ @templates templates
17
+
18
+ def list_templates do
19
+ @templates
20
+ end
21
+
22
+ def view_module(web_module) do
23
+ """
24
+ defmodule #{inspect web_module}.Adminable.AdminView do
25
+ use #{inspect web_module}, :view
26
+ use Adminable.ViewHelpers
27
+ end
28
+ """
29
+ end
30
+
31
+ def templates_path(web_module) do
32
+ Path.join(web_module_path(web_module), "templates")
33
+ end
34
+
35
+ def views_path(web_module) do
36
+ Path.join(web_module_path(web_module), "views")
37
+ end
38
+
39
+ defp web_module_path(web_module) do
40
+ name = Phoenix.Naming.underscore(web_module)
41
+ Path.join(["lib", name])
42
+ end
43
+
44
+ def export(web_module) do
45
+ templates_path = templates_path(web_module)
46
+ views_path = views_path(web_module)
47
+
48
+ view_module = view_module(web_module)
49
+ templates = list_templates()
50
+
51
+ exported_view_module_path = Path.join([views_path, "adminable", "admin_view.ex"])
52
+ File.mkdir_p!(Path.dirname(exported_view_module_path))
53
+ File.write!(exported_view_module_path, view_module)
54
+
55
+ exported_templates_path = Path.join([templates_path, "adminable", "admin"])
56
+ File.mkdir_p!(exported_templates_path)
57
+ Enum.each(templates, fn({name, data}) ->
58
+ File.write!(Path.join(exported_templates_path, name), data)
59
+ end)
60
+ end
61
+ end
changed lib/adminable/plug.ex
 
@@ -10,10 +10,20 @@ defmodule Adminable.Plug do
10
10
otp_app: :my_app,
11
11
repo: MyApp.Repo,
12
12
schemas: [MyApp.User],
13
+ view_module: MyAppWeb.Adminable.AdminView
13
14
layout: {MyAppWeb.LayoutView, "app.html"}
14
15
])
15
16
end
16
17
```
18
+
19
+ Arguments
20
+
21
+ * `otp_app` - Your app
22
+ * `repo` - Your app's Repo
23
+ * `schemas` - The schemas to make Admin sections for
24
+ * `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
25
+ * `layout` - (Optional) The layout to use
26
+
17
27
"""
18
28
19
29
def init(opts) do
 
@@ -24,6 +34,7 @@ defmodule Adminable.Plug do
24
34
repo = Keyword.fetch!(opts, :repo)
25
35
otp_app = Keyword.fetch!(opts, :otp_app)
26
36
schemas = Keyword.get(opts, :schemas, [])
37
+ view_module = Keyword.get(opts, :view_module, Adminable.AdminView)
27
38
layout = Keyword.get(opts, :layout, {Adminable.LayoutView, "app.html"})
28
39
29
40
schemas =
 
@@ -40,6 +51,7 @@ defmodule Adminable.Plug do
40
51
|> Plug.Conn.assign(:repo, repo)
41
52
|> Plug.Conn.assign(:schemas, schemas)
42
53
|> Plug.Conn.assign(:layout, layout)
54
+ |> Plug.Conn.assign(:view_module, view_module)
43
55
|> Adminable.Router.call(opts)
44
56
end
45
57
end
changed lib/adminable/templates/admin/_pagination.html.eex
 
@@ -1,48 +1,48 @@
1
- <%= if Adminable.PaginationView.show_pagination?(@total_pages) do %>
1
+ <%= if Adminable.AdminView.show_pagination?(@total_pages) do %>
2
2
<div class="rev-PaginationWrapper text-center">
3
3
<ul class="rev-Pagination" role="navigation" aria-label="Pagination">
4
- <%= unless Adminable.PaginationView.first_page?(@page_number) do %>
4
+ <%= unless Adminable.AdminView.first_page?(@page_number) do %>
5
5
<li class="rev-Pagination-arrow">
6
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, 1, @url) %>">
6
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, 1, @url) %>">
7
7
<span><i class="icon-angle-double-left"></i>First<span class="ShowForSR"> page</span></span>
8
8
</a>
9
9
</li>
10
10
<li class="rev-Pagination-arrow">
11
- <a href="<%= Adminable.PaginationView.make_previous_page_link(@conn, @page_number, @url) %>">
11
+ <a href="<%= Adminable.AdminView.make_previous_page_link(@conn, @page_number, @url) %>">
12
12
<span><i class="icon-angle-left"></i>Previous<span class="ShowForSR"> page</span></span>
13
13
</a>
14
14
</li>
15
15
<% end %>
16
16
17
17
<%= for page <- 1..@total_pages do %>
18
- <%= if Adminable.PaginationView.show_previous_ellipsis?(page, @page_number) do %>
18
+ <%= if Adminable.AdminView.show_previous_ellipsis?(page, @page_number) do %>
19
19
<li class="rev-Pagination-dots">
20
20
...
21
21
</li>
22
22
<% end %>
23
- <%= if Adminable.PaginationView.show_page_link?(page, @page_number) do %>
24
- <li class="rev-Pagination-number <%= Adminable.PaginationView.selected_page_class(page, @page_number)%>">
23
+ <%= if Adminable.AdminView.show_page_link?(page, @page_number) do %>
24
+ <li class="rev-Pagination-number <%= Adminable.AdminView.selected_page_class(page, @page_number)%>">
25
25
<%= if page == @page_number do %>
26
26
<span class="ShowForSR">You're on page </span><a><%= @page_number %></a>
27
27
<% else %>
28
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, page, @url) %>" aria-label="Page <%= page %>"><%= page %></a>
28
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, page, @url) %>" aria-label="Page <%= page %>"><%= page %></a>
29
29
<% end %>
30
30
</li>
31
31
<% end %>
32
- <%= if Adminable.PaginationView.show_next_ellipsis?(page, @page_number, @total_pages) do %>
32
+ <%= if Adminable.AdminView.show_next_ellipsis?(page, @page_number, @total_pages) do %>
33
33
<li class="rev-Pagination-dots">
34
34
...
35
35
</li>
36
36
<% end %>
37
37
<% end %>
38
- <%= unless Adminable.PaginationView.last_page?(@page_number, @total_pages) do %>
38
+ <%= unless Adminable.AdminView.last_page?(@page_number, @total_pages) do %>
39
39
<li class="rev-Pagination-arrow">
40
- <a href="<%= Adminable.PaginationView.make_next_page_link(@conn, @page_number, @url) %>">
40
+ <a href="<%= Adminable.AdminView.make_next_page_link(@conn, @page_number, @url) %>">
41
41
<span>Next<span class="ShowForSR"> page</span><i class="icon-angle-right"></i></span>
42
42
</a>
43
43
</li>
44
44
<li class="rev-Pagination-arrow">
45
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, @total_pages, @url) %>">
45
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, @total_pages, @url) %>">
46
46
<span>Last<span class="ShowForSR"> page</span><i class="icon-angle-double-right"></i></span>
47
47
</a>
48
48
</li>
changed lib/adminable/templates/admin/dashboard.html.eex
 
@@ -1,11 +1,11 @@
1
- <%= row do %>
2
- <%= col do %>
1
+ <div class="rev-Row">
2
+ <div class="rev-Col">
3
3
<h1>Admin Dashboard</h1>
4
- <% end %>
5
- <% end %>
4
+ </div>
5
+ </div>
6
6
7
- <%= row do %>
8
- <%= col do %>
7
+ <div class="rev-Row">
8
+ <div class="rev-Col">
9
9
<div class="rev-TableContainer">
10
10
<table class="rev-Table">
11
11
<thead class="rev-Table-head">
 
@@ -24,5 +24,5 @@
24
24
</tbody>
25
25
</table>
26
26
</div>
27
- <% end %>
28
- <% end %>
27
+ </div>
28
+ </div>
changed lib/adminable/templates/admin/edit.html.eex
 
@@ -1,25 +1,25 @@
1
- <%= row do %>
2
- <%= col class: "rev-Col--medium7 rev-Col--smallCentered" do %>
3
- <%= row do %>
4
- <%= col do %>
1
+ <div class="rev-Row">
2
+ <div class="rev-Col rev-Col--medium7 rev-Col--smallCentered" do %>
3
+ <div class="rev-Row">
4
+ <div class="rev-Col">
5
5
<h2 class="u-break-word">Edit <%= String.capitalize(@schema) %></h2>
6
- <% end %>
7
- <% end %>
8
- <%= form_for @changeset, Routes.admin_path(@conn, :update, @schema, @pk), [as: :data], fn f -> %>
9
- <%= row do %>
6
+ </div>
7
+ </div>
8
+ <%= form_for @changeset, Adminable.Router.Helpers.admin_path(@conn, :update, @schema, @pk), [as: :data], fn f -> %>
9
+ <div class="rev-Row">
10
10
<%= for field <- form_fields(@changeset) do %>
11
11
<%= field(f, @schema_module, field) %>
12
12
<% end %>
13
- <% end %>
13
+ </div>
14
14
15
- <%= row do %>
16
- <%= col do %>
15
+ <div class="rev-Row">
16
+ <div class="rev-Col">
17
17
<section class="u-noBorder-bottom u-flexAlignEnd">
18
18
<button class="rev-Button" type="submit">Edit</button>
19
19
</section>
20
- <% end %>
21
- <% end %>
20
+ </div>
21
+ </div>
22
22
23
23
<% end %>
24
- <% end %>
25
- <% end %>
24
+ </div>
25
+ </div>
changed lib/adminable/templates/admin/index.html.eex
 
@@ -1,17 +1,17 @@
1
- <%= row do %>
2
- <%= col do %>
1
+ <div class="rev-Row">
2
+ <div class="rev-Col">
3
3
<h1><%= String.capitalize(@schema) %></h1>
4
- <% end %>
5
- <% end %>
4
+ </div>
5
+ </div>
6
6
7
- <%= row do %>
8
- <%= col do %>
9
- <%= link "New #{String.capitalize(@schema)}", to: Routes.admin_path(@conn, :new, @schema), class: button_class() %>
10
- <% end %>
11
- <% end %>
7
+ <div class="rev-Row">
8
+ <div class="rev-Col">
9
+ <%= link "New #{String.capitalize(@schema)}", to: Adminable.Router.Helpers.admin_path(@conn, :new, @schema), class: "rev-Button" %>
10
+ </div>
11
+ </div>
12
12
13
- <%= row do %>
14
- <%= col do %>
13
+ <div class="rev-Row">
14
+ <div class="rev-Col">
15
15
<div class="rev-TableContainer">
16
16
<table class="rev-Table">
17
17
<thead class="rev-Table-head">
 
@@ -29,7 +29,7 @@
29
29
<td class="rev-Table-Data"><%= Map.get(schema, field) %></td>
30
30
<% end %>
31
31
<td>
32
- <%= link "Edit", to: Routes.admin_path(@conn, :edit, @schema, schema.id), class: button_class(secondary: true) %>
32
+ <%= link "Edit", to: Adminable.Router.Helpers.admin_path(@conn, :edit, @schema, schema.id), class: "rev-Button rev-Button--secondary" %>
33
33
</td>
34
34
<tr>
35
35
<% end %>
 
@@ -43,7 +43,7 @@
43
43
page_size: @page_size,
44
44
total_entries: @total_entries,
45
45
total_pages: @total_pages,
46
- url: Routes.admin_path(@conn, :index, @schema)
46
+ url: Adminable.Router.Helpers.admin_path(@conn, :index, @schema)
47
47
%>
48
- <% end %>
49
- <% end %>
48
+ </div>
49
+ </div>
changed lib/adminable/templates/admin/new.html.eex
 
@@ -1,25 +1,25 @@
1
- <%= row do %>
2
- <%= col class: "rev-Col--medium7 rev-Col--smallCentered" do %>
3
- <%= row do %>
4
- <%= col do %>
1
+ <div class="rev-Row">
2
+ <div class="rev-Col rev-Col--medium7 rev-Col--smallCentered">
3
+ <div class="rev-Row">
4
+ <div class="rev-Col">
5
5
<h2 class="u-break-word">New <%= String.capitalize(@schema) %></h2>
6
- <% end %>
7
- <% end %>
8
- <%= form_for @changeset, Routes.admin_path(@conn, :create, @schema), [as: :data], fn f -> %>
9
- <%= row do %>
6
+ </div>
7
+ </div>
8
+ <%= form_for @changeset, Adminable.Router.Helpers.admin_path(@conn, :create, @schema), [as: :data], fn f -> %>
9
+ <div class="rev-Row">
10
10
<%= for field <- form_fields(@changeset) do %>
11
11
<%= field(f, @schema_module, field) %>
12
12
<% end %>
13
- <% end %>
13
+ </div>
14
14
15
- <%= row do %>
16
- <%= col do %>
15
+ <div class="rev-Row">
16
+ <div class="rev-Col">
17
17
<section class="u-noBorder-bottom u-flexAlignEnd">
18
18
<button class="rev-Button" type="submit">Create</button>
19
19
</section>
20
- <% end %>
21
- <% end %>
20
+ </div>
21
+ </div>
22
22
23
23
<% end %>
24
- <% end %>
25
- <% end %>
24
+ </div>
25
+ </div>
changed lib/adminable/views/admin_view.ex
 
@@ -5,22 +5,5 @@ defmodule Adminable.AdminView do
5
5
root: "lib/adminable/templates",
6
6
namespace: Adminable
7
7
8
- # Use all HTML functionality (forms, tags, etc)
9
- use Phoenix.HTML
10
-
11
- alias Adminable.Router.Helpers, as: Routes
12
- import Harmonium
13
-
14
- def index_fields(schema_module) do
15
- schema_module.fields()
16
- end
17
-
18
- def form_fields(changeset) do
19
- schema = changeset.data
20
-
21
- fields = schema.__struct__.fields() -- [:inserted_at, :updated_at]
22
- fields -- schema.__struct__.__schema__(:primary_key)
23
- end
24
-
25
- defdelegate field(form, schema_module, field, opts \\ []), to: Adminable.Field
8
+ use Adminable.ViewHelpers
26
9
end
changed lib/adminable/views/field.ex
 
@@ -12,7 +12,7 @@ defmodule Adminable.Field do
12
12
defp field_html(form, field, :boolean, opts) do
13
13
~E"""
14
14
<%= col do %>
15
- <%= single_checkbox(form, field, Keyword.merge([label: String.capitalize(to_string(field))], opts)) %>
15
+ <%= single_checkbox(form, field, Keyword.merge([label: Phoenix.Naming.humanize(field)], opts)) %>
16
16
<% end %>
17
17
"""
18
18
end
 
@@ -23,7 +23,7 @@ defmodule Adminable.Field do
23
23
<%= number_input_stack(
24
24
form,
25
25
field,
26
- label: String.capitalize(to_string(field)),
26
+ label: Phoenix.Naming.humanize(field),
27
27
input: Keyword.merge([], opts))
28
28
%>
29
29
<% end %>
 
@@ -36,8 +36,8 @@ defmodule Adminable.Field do
36
36
<%= text_input_stack(
37
37
form,
38
38
field,
39
- label: String.capitalize(to_string(field)),
40
- input: Keyword.merge([placeholder: String.capitalize(to_string(field))], opts))
39
+ label: Phoenix.Naming.humanize(field),
40
+ input: Keyword.merge([placeholder: Phoenix.Naming.humanize(field)], opts))
41
41
%>
42
42
<% end %>
43
43
"""
removed lib/adminable/views/pagination_view.ex
 
@@ -1,65 +0,0 @@
1
- defmodule Adminable.PaginationView do
2
- @moduledoc false
3
-
4
- @page_links_to_show 2
5
-
6
- def make_next_page_link(conn, current_page, url) do
7
- make_page_link(conn, current_page + 1, url)
8
- end
9
-
10
- def make_previous_page_link(conn, current_page, url) do
11
- make_page_link(conn, current_page - 1, url)
12
- end
13
-
14
- def make_page_link(conn, page, url) do
15
- query_params = conn.query_params
16
-
17
- query_params = Map.put(query_params, "page", page)
18
-
19
- uri = URI.parse(url)
20
-
21
- query_params =
22
- if is_nil(uri.query) do
23
- query_params
24
- else
25
- URI.decode_query(uri.query, query_params)
26
- end
27
-
28
- uri = %{uri | query: Plug.Conn.Query.encode(query_params)}
29
-
30
- URI.to_string(uri)
31
- end
32
-
33
- def first_page?(1), do: true
34
- def first_page?(_), do: false
35
-
36
- def last_page?(page_number, total_pages) when page_number == total_pages, do: true
37
- def last_page?(_, _), do: false
38
-
39
- def show_pagination?(1), do: false
40
- def show_pagination?(_), do: true
41
-
42
- def selected_page_class(page_number, current_page) when page_number == current_page do
43
- "rev-Pagination-number--selected"
44
- end
45
-
46
- def selected_page_class(_, _) do
47
- ""
48
- end
49
-
50
- def show_previous_ellipsis?(1, _) do
51
- false
52
- end
53
-
54
- def show_previous_ellipsis?(page, page_number) do
55
- page == page_number - @page_links_to_show
56
- end
57
-
58
- def show_next_ellipsis?(page, page_number, total_pages) do
59
- page == page_number + @page_links_to_show and page != total_pages
60
- end
61
-
62
- def show_page_link?(page, page_number) do
63
- page >= page_number - @page_links_to_show and page <= page_number + @page_links_to_show
64
- end
65
- end
added lib/adminable/views/view_helpers.ex
 
@@ -0,0 +1,83 @@
1
+ defmodule Adminable.ViewHelpers do
2
+ @moduledoc false
3
+
4
+ defmacro __using__(_opts) do
5
+ quote do
6
+ use Phoenix.HTML
7
+ @page_links_to_show 2
8
+
9
+ def index_fields(schema_module) do
10
+ schema_module.fields()
11
+ end
12
+
13
+ def form_fields(changeset) do
14
+ schema = changeset.data
15
+
16
+ fields = schema.__struct__.fields() -- [:inserted_at, :updated_at]
17
+ fields -- schema.__struct__.__schema__(:primary_key)
18
+ end
19
+
20
+ defdelegate field(form, schema_module, field, opts \\ []), to: Adminable.Field
21
+
22
+ def make_next_page_link(conn, current_page, url) do
23
+ make_page_link(conn, current_page + 1, url)
24
+ end
25
+
26
+ def make_previous_page_link(conn, current_page, url) do
27
+ make_page_link(conn, current_page - 1, url)
28
+ end
29
+
30
+ def make_page_link(conn, page, url) do
31
+ query_params = conn.query_params
32
+
33
+ query_params = Map.put(query_params, "page", page)
34
+
35
+ uri = URI.parse(url)
36
+
37
+ query_params =
38
+ if is_nil(uri.query) do
39
+ query_params
40
+ else
41
+ URI.decode_query(uri.query, query_params)
42
+ end
43
+
44
+ uri = %{uri | query: Plug.Conn.Query.encode(query_params)}
45
+
46
+ URI.to_string(uri)
47
+ end
48
+
49
+ def first_page?(1), do: true
50
+ def first_page?(_), do: false
51
+
52
+ def last_page?(page_number, total_pages) when page_number == total_pages, do: true
53
+ def last_page?(_, _), do: false
54
+
55
+ def show_pagination?(1), do: false
56
+ def show_pagination?(_), do: true
57
+
58
+ def selected_page_class(page_number, current_page) when page_number == current_page do
59
+ "rev-Pagination-number--selected"
60
+ end
61
+
62
+ def selected_page_class(_, _) do
63
+ ""
64
+ end
65
+
66
+ def show_previous_ellipsis?(1, _) do
67
+ false
68
+ end
69
+
70
+ def show_previous_ellipsis?(page, page_number) do
71
+ page == page_number - @page_links_to_show
72
+ end
73
+
74
+ def show_next_ellipsis?(page, page_number, total_pages) do
75
+ page == page_number + @page_links_to_show and page != total_pages
76
+ end
77
+
78
+ def show_page_link?(page, page_number) do
79
+ page >= page_number - @page_links_to_show and page <= page_number + @page_links_to_show
80
+ end
81
+ end
82
+ end
83
+ end
added lib/mix/tasks/adminable.gen.view.ex
 
@@ -0,0 +1,23 @@
1
+ defmodule Mix.Tasks.Adminable.Gen.View do
2
+ @shortdoc "Generates views and templates"
3
+
4
+ @moduledoc """
5
+ Generates views and templates so that they can be modifed.
6
+ mix adminable.gen.view my_web_module
7
+
8
+ ## Arguments
9
+ * `my_web_module` - web_module to use for path and module names
10
+ """
11
+ use Mix.Task
12
+
13
+ @impl true
14
+ def run([web_module_string]) do
15
+ web_module = Module.concat([web_module_string])
16
+ Adminable.Exporter.export(web_module)
17
+ end
18
+
19
+ def run(_) do
20
+ Mix.Shell.IO.error("Invalid args. Usage mix adminable.gen.view my_web_module")
21
+ exit({:shutdown, 1})
22
+ end
23
+ end
changed mix.exs
 
@@ -4,7 +4,7 @@ defmodule Adminable.MixProject do
4
4
def project do
5
5
[
6
6
app: :adminable,
7
- version: "0.2.0",
7
+ version: "0.3.0",
8
8
elixir: "~> 1.8",
9
9
start_permanent: Mix.env() == :prod,
10
10
deps: deps(),