Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove class_inactive option #14

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add `phoenix_active_link` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[{:phoenix_active_link, "~> 0.2.1"}]
[{:phoenix_active_link, "~> 0.3.0"}]
end
```

Expand All @@ -26,34 +26,34 @@ to the `quote` of the `view` function in your `web.ex`.

You can then use the functions as follow:

```erb
<header>
```eex
<%= active_link(@conn, to: "/") do %>
<img src="logo.png">
<% end %>

<nav>
<ul>
<%= active_link(@conn, "Dashboard", to: "/", active: [{Dashboard, :index}], wrap_tag: :li) %>
<%= active_link(@conn, "Dashboard", to: "/", wrap_tag: :li, active: [{Dashboard, :index}]) %>
<%= active_link(@conn, "Users", to: "/users", wrap_tag: :li) %>
<%= active_link(@conn, to: "/users", wrap_tag: :li) do %>
<img src="foo.png">
<% end %>
</ul>
</header>
</nav>
```

If you prefer to write `PhoenixActiveLink.active_link` explicitly, you can skip
the first step.
If you prefer to write `PhoenixActiveLink.active_link` explicitly, you can skip the first step.

### Example of Active Tags
### Example for Bootstrap navigation

To specify the active and inactive tags for the wrap tag, use `class_active` and `class_inactive`. Example:
You can create active Bootstrap navigation items as follows:

```erb
<%= active_link(@conn, "Home", to: "/", wrap_tag: :li, class_active: "active nav-item", class_inactive: "nav-item") %>
```ex
active_link(@conn, "Home", to: "/", class: "nav-link", wrap_tag: :li, wrap_tag_opts: [class: "nav-item"])
```
*Defaults can be set in the `config.ex` as noted in the [documentation](https://hexdocs.pm/phoenix_active_link/PhoenixActiveLink.html)*

_Defaults can be set in the `config.ex` as noted in the [documentation](https://hexdocs.pm/phoenix_active_link/PhoenixActiveLink.html#module-configuration)._

## Documentation

For more information, take a look at the [documentation](https://hexdocs.pm/phoenix_active_link/PhoenixActiveLink.html)
For more information, take a look at the [documentation](https://hexdocs.pm/phoenix_active_link/PhoenixActiveLink.html).

## Credits

Expand Down
39 changes: 19 additions & 20 deletions lib/phoenix_active_link.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ defmodule PhoenixActiveLink do

config :phoenix_active_link, :defaults,
wrap_tag: :li,
class_active: "enabled",
class_inactive: "disabled"
class_active: "enabled"
```

## Integrate in Phoenix
Expand All @@ -26,7 +25,7 @@ defmodule PhoenixActiveLink do
import Plug.Conn
alias Plug.Conn.Query

@opts ~w(active wrap_tag class_active class_inactive active_disable wrap_tag_opts)a
@opts ~w(active wrap_tag class_active active_disable wrap_tag_opts)a

@doc """
`active_link/3` is a wrapper around `Phoenix.HTML.Link.link/2`.
Expand All @@ -37,19 +36,21 @@ defmodule PhoenixActiveLink do
## Options

* `:active` - See `active_path?/2` documentation for more information
* `:wrap_tag` - Wraps the link in another tag which will also have the same active class.
This options is useful for usage with `li` in bootstrap for example.
* `:class_active` - The class to add when the link is active. Defaults to `"active"`
* `:class_inactive` - The class to add when the link is not active. Empty by default.
* `:active_disable` - Uses a `span` element instead of an anchor when not active.
* `:active_disable` - The true, it uses a `span` element instead of an anchor when active.
* `:wrap_tag` - Wraps the link in another tag which will also have the same active class.
This option is useful for usage with `li` in bootstrap for example.
* `:wrap_tag_opts` - Options to pass along with the `:wrap_tag`.

## Examples

```elixir
<%= active_link(@conn, "Link text", to: "/my/path") %>
<%= active_link(@conn, "Link text", to: "/my/path", wrap_tag: :li) %>
<%= active_link(@conn, "Link text", to: "/my/path", active: :exact) %>
```
```elixir
active_link(@conn, "Link text", to: "/path")
active_link(@conn, "Link text", to: "/path", active: :exact)
active_link(@conn, "Link text", to: "/path", wrap_tag: :li)
active_link(@conn, "Link", to: "/path", class: "nav-link", wrap_tag: :li, wrap_tag_opts: [class: "nav-item"])
```

"""
def active_link(conn, opts, do: contents) when is_list(opts) do
active_link(conn, contents, opts)
Expand All @@ -61,6 +62,7 @@ defmodule PhoenixActiveLink do
extra_class = extra_class(active?, opts)
opts = append_class(opts, extra_class)
link = make_link(active?, text, opts)

cond do
tag = opts[:wrap_tag] -> content_tag(tag, link, wrap_tag_opts(extra_class, opts))
true -> link
Expand Down Expand Up @@ -173,7 +175,8 @@ defmodule PhoenixActiveLink do
defp map_include?(in_map, %{} = map), do: Enum.all?(map, &map_include?(in_map, &1))

defp wrap_tag_opts(extra_class, opts) do
Keyword.get(opts, :wrap_tag_opts, [])
opts
|> Keyword.get(:wrap_tag_opts, [])
|> append_class(extra_class)
end

Expand All @@ -185,13 +188,8 @@ defmodule PhoenixActiveLink do
end
end

defp extra_class(active?, opts) do
if active? do
opts[:class_active] || "active"
else
opts[:class_inactive] || ""
end
end
defp extra_class(true, opts), do: opts[:class_active] || "active"
defp extra_class(false, _), do: ""

defp append_class(opts, class) do
class =
Expand All @@ -201,6 +199,7 @@ defmodule PhoenixActiveLink do
|> List.insert_at(0, class)
|> Enum.reject(&(&1 == ""))
|> Enum.join(" ")

Keyword.put(opts, :class, class)
end

Expand Down
167 changes: 86 additions & 81 deletions test/phoenix_active_link_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,108 +2,113 @@ defmodule PhoenixActiveLinkTest do
use ExUnit.Case
use Phoenix.HTML
import TestHelpers
import PhoenixActiveLink

doctest PhoenixActiveLink

import PhoenixActiveLink

test "active_path? when :active is true" do
assert active_path?(conn(), active: true)
end
describe "active_path?/2" do
test "when :active is true" do
assert active_path?(conn(), active: true)
end

test "active_path? when :active is false" do
refute active_path?(conn(), active: false)
end
test "when :active is false" do
refute active_path?(conn(), active: false)
end

test "active_path? when :active is :inclusive" do
assert active_path?(conn(path: "/foo/bar"), to: "/foo", active: :inclusive)
refute active_path?(conn(path: "/foo"), to: "/foo/bar", active: :inclusive)
assert active_path?(conn(path: "/foo/"), to: "/foo", active: :inclusive)
assert active_path?(conn(path: "/foo"), to: "/foo/", active: :inclusive)
assert active_path?(conn(path: "/foo"), to: "/foo?param=bar", active: :inclusive)
assert active_path?(conn(path: "/foo?param=bar"), to: "/foo", active: :inclusive)
refute active_path?(conn(path: "/foo"), to: "/", active: :inclusive)
refute active_path?(conn(path: "/"), to: "/foo", active: :inclusive)
end
test "when :active is :inclusive" do
assert active_path?(conn(path: "/foo/bar"), to: "/foo", active: :inclusive)
refute active_path?(conn(path: "/foo"), to: "/foo/bar", active: :inclusive)
assert active_path?(conn(path: "/foo/"), to: "/foo", active: :inclusive)
assert active_path?(conn(path: "/foo"), to: "/foo/", active: :inclusive)
assert active_path?(conn(path: "/foo"), to: "/foo?param=bar", active: :inclusive)
assert active_path?(conn(path: "/foo?param=bar"), to: "/foo", active: :inclusive)
refute active_path?(conn(path: "/foo"), to: "/", active: :inclusive)
refute active_path?(conn(path: "/"), to: "/foo", active: :inclusive)
end

test "active_path? when :active is not passed" do
assert active_path?(conn(path: "/foo/bar"), to: "/foo")
end
test "when :active is not passed" do
assert active_path?(conn(path: "/foo/bar"), to: "/foo")
end

test "active_path? when :active is :exclusive" do
assert active_path?(conn(path: "/foo"), to: "/foo", active: :exclusive)
assert active_path?(conn(path: "/foo/"), to: "/foo", active: :exclusive)
assert active_path?(conn(path: "/foo"), to: "/foo/", active: :exclusive)
refute active_path?(conn(path: "/foo/bar"), to: "/foo", active: :exclusive)
end
test "when :active is :exclusive" do
assert active_path?(conn(path: "/foo"), to: "/foo", active: :exclusive)
assert active_path?(conn(path: "/foo/"), to: "/foo", active: :exclusive)
assert active_path?(conn(path: "/foo"), to: "/foo/", active: :exclusive)
refute active_path?(conn(path: "/foo/bar"), to: "/foo", active: :exclusive)
end

test "active_path? when :active is :exact" do
assert active_path?(conn(path: "/foo"), to: "/foo", active: :exact)
refute active_path?(conn(path: "/foo/"), to: "/foo", active: :exact)
refute active_path?(conn(path: "/foo"), to: "/foo/", active: :exact)
end
test "when :active is :exact" do
assert active_path?(conn(path: "/foo"), to: "/foo", active: :exact)
refute active_path?(conn(path: "/foo/"), to: "/foo", active: :exact)
refute active_path?(conn(path: "/foo"), to: "/foo/", active: :exact)
end

test "active_path? when :acitve is :exact_with_params" do
assert active_path?(conn(path: "/foo", query_string: "bar=1"), to: "/foo?bar=1", active: :exact_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=1&baz=2"), to: "/foo?bar=1", active: :exact_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar[x]=1&bar[y]=1"), to: "/foo?bar[x]=1&bar[y]=1", active: :exact_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=baz%20foo"), to: "/foo?bar=baz foo", active: :exact_with_params)
end
test "when :acitve is :exact_with_params" do
assert active_path?(conn(path: "/foo", query_string: "bar=1"), to: "/foo?bar=1", active: :exact_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=1&baz=2"), to: "/foo?bar=1", active: :exact_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar[x]=1&bar[y]=1"), to: "/foo?bar[x]=1&bar[y]=1", active: :exact_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=baz%20foo"), to: "/foo?bar=baz foo", active: :exact_with_params)
end

test "active_path? when :active is :inclusive_with_params" do
assert active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo?baz=2", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar%5Bx%5D=2&bar%5By%5D=2"), to: "/foo?bar[x]=2", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar[x]=2&bar[y]=2"), to: "/foo?bar[x]=2", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo?baz=2&bax=6", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar[x]=2&bar[y]=2"), to: "/foo?bar[x]=2&bar[z]=6", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foobar?baz=2",active: :inclusive_with_params)
end
test "when :active is :inclusive_with_params" do
assert active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo?baz=2", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar%5Bx%5D=2&bar%5By%5D=2"), to: "/foo?bar[x]=2", active: :inclusive_with_params)
assert active_path?(conn(path: "/foo", query_string: "bar[x]=2&bar[y]=2"), to: "/foo?bar[x]=2", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foo?baz=2&bax=6", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar[x]=2&bar[y]=2"), to: "/foo?bar[x]=2&bar[z]=6", active: :inclusive_with_params)
refute active_path?(conn(path: "/foo", query_string: "bar=2&baz=2"), to: "/foobar?baz=2",active: :inclusive_with_params)
end

test "active_path? when :active is a regex" do
assert active_path?(conn(path: "/foo"), active: ~r(^/foo.*))
refute active_path?(conn(path: "/bar/foo"), active: ~r(^/foo.*))
assert active_path?(conn(path: "/bar/foo"), active: ~r(foo.*))
end
test "when :active is a regex" do
assert active_path?(conn(path: "/foo"), active: ~r(^/foo.*))
refute active_path?(conn(path: "/bar/foo"), active: ~r(^/foo.*))
assert active_path?(conn(path: "/bar/foo"), active: ~r(foo.*))
end

test "active_path? when :active is a {controller, action} list" do
conn = conn(controller: Foo, action: Bar)
assert active_path?(conn, active: [{Foo, Bar}])
assert active_path?(conn, active: [{:any, Bar}])
assert active_path?(conn, active: [{Foo, :any}])
refute active_path?(conn, active: [{Bar, Foo}])
test "when :active is a {controller, action} list" do
conn = conn(controller: Foo, action: Bar)
assert active_path?(conn, active: [{Foo, Bar}])
assert active_path?(conn, active: [{:any, Bar}])
assert active_path?(conn, active: [{Foo, :any}])
refute active_path?(conn, active: [{Bar, Foo}])
end
end

test "active_link without :wrap_tag" do
assert active_link(conn(path: "/"), "Link", to: "/foo") == link("Link", to: "/foo", class: "")
assert active_link(conn(path: "/foo"), "Link", to: "/foo") == link("Link", to: "/foo", class: "active")
assert active_link(conn(path: "/foo"), "Link", to: "/foo", class: "bar") == link("Link", to: "/foo", class: "active bar")
link = active_link(conn(path: "/foo"), "Link", to: "/foo", class: "bar", class_active: "enabled")
assert link == link("Link", to: "/foo", class: "enabled bar")
link = active_link(conn(path: "/bar"), "Link", to: "/foo", class: "bar", class_inactive: "disabled")
assert link == link("Link", to: "/foo", class: "disabled bar")
end
describe "active_link/3" do
test "without :wrap_tag" do
assert active_link(conn(path: "/"), "Link", to: "/foo") == link("Link", to: "/foo", class: "")
assert active_link(conn(path: "/foo"), "Link", to: "/foo") == link("Link", to: "/foo", class: "active")
assert active_link(conn(path: "/foo"), "Link", to: "/foo", class: "bar") == link("Link", to: "/foo", class: "active bar")

test "active_link with a block" do
content = content_tag(:p, "Hello")
expected = link(to: "/foo", class: "") do
content
link = active_link(conn(path: "/foo"), "Link", to: "/foo", class: "bar", class_active: "enabled")
assert link == link("Link", to: "/foo", class: "enabled bar")
end

result = active_link(conn(path: "/"), to: "/foo") do
content
test "with a block" do
content = content_tag(:p, "Hello")

expected = link(to: "/foo", class: "") do
content
end

result = active_link(conn(path: "/"), to: "/foo") do
content
end

assert result == expected
end

assert result == expected
end
test "with :wrap_tag" do
link = active_link(conn(path: "/foo"), "Link", to: "/foo", wrap_tag: :li)
assert link == content_tag(:li, link("Link", to: "/foo", class: "active"), class: "active")

test "active_link with :wrap_tag" do
expected = content_tag(:li, link("Link", to: "/foo", class: "active"), class: "active")
assert active_link(conn(path: "/foo"), "Link", to: "/foo", wrap_tag: :li) == expected
link = active_link(conn(path: "/bar"), "Link", to: "/foo", class: "nav-link", wrap_tag: :li, wrap_tag_opts: [class: "nav-item"])
assert link == content_tag(:li, link("Link", to: "/foo", class: "nav-link"), class: "nav-item")

expected = content_tag(:li, link("Link", to: "/foo", class: "disabled"), class: "disabled foo")
link = active_link(conn(path: "/bar"), "Link", to: "/foo", class_inactive: "disabled", wrap_tag: :li, wrap_tag_opts: [class: "foo"])
assert link == expected
link = active_link(conn(path: "/foo"), "Link", to: "/foo", class: "nav-link", wrap_tag: :li, wrap_tag_opts: [class: "nav-item"])
assert link == content_tag(:li, link("Link", to: "/foo", class: "active nav-link"), class: "active nav-item")
end
end

test "customize defaults" do
Expand Down