-
Notifications
You must be signed in to change notification settings - Fork 0
/
link.ex
155 lines (110 loc) · 4.68 KB
/
link.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
defmodule Phoenix.WebComponent.Link do
@moduledoc """
Conveniences for working with links and URLs in HTML.
"""
import Phoenix.HTML.Tag
@doc """
Generates a link to the given URL.
## Examples
link("hello", to: "/world")
#=> <a href="/world">hello</a>
link("hello", to: URI.parse("https://elixir-lang.org"))
#=> <a href="https://elixir-lang.org">hello</a>
link("<hello>", to: "/world")
#=> <a href="/world"><hello></a>
link("<hello>", to: "/world", class: "btn")
#=> <a class="btn" href="/world"><hello></a>
link("delete", to: "/the_world", data: [confirm: "Really?"])
#=> <a data-confirm="Really?" href="/the_world">delete</a>
# If you supply a method other than `:get`:
link("delete", to: "/everything", method: :delete)
#=> <a href="/everything" data-csrf="csrf_token" data-method="delete" data-to="/everything">delete</a>
# You can use a `do ... end` block too:
link to: "/hello" do
"world"
end
#=> <a href="/hello">world<a>
## Options
* `:to` - the page to link to. This option is required
* `:method` - the method to use with the link. In case the
method is not `:get`, the link is generated inside the form
which sets the proper information. In order to submit the
form, JavaScript must be enabled
* `:csrf_token` - a custom token to use for links with a method
other than `:get`.
All other options are forwarded to the underlying `<a>` tag.
## Data attributes
Data attributes are added as a keyword list passed to the `data` key.
The following data attributes are supported:
* `data-confirm` - shows a confirmation prompt before
generating and submitting the form when `:method`
is not `:get`.
## CSRF Protection
By default, CSRF tokens are generated through `Plug.CSRFProtection`.
"""
def wc_link(text, opts)
def wc_link(opts, do: contents) when is_list(opts) do
wc_link(contents, opts)
end
def wc_link(_text, opts) when not is_list(opts) do
raise ArgumentError, "link/2 requires a keyword list as second argument"
end
def wc_link(text, opts) do
{to, opts} = pop_required_option!(opts, :to, "expected non-nil value for :to in link/2")
{method, opts} = Keyword.pop(opts, :method, :get)
if method == :get do
# Call link attributes to validate `to`
[data: data] = Phoenix.HTML.link_attributes(to, [])
content_tag(:a, text, [href: data[:to]] ++ Keyword.delete(opts, :csrf_token))
else
{csrf_token, opts} = Keyword.pop(opts, :csrf_token, true)
opts = Keyword.put_new(opts, :rel, "nofollow")
[data: data] =
Phoenix.HTML.link_attributes(to, method: method, csrf_token: csrf_token)
content_tag(:a, text, [data: data, href: data[:to]] ++ opts)
end
end
@doc """
Generates a button tag that uses the Javascript function handleClick()
(see phoenix_html.js) to submit the form data.
Useful to ensure that links that change data are not triggered by
search engines and other spidering software.
## Examples
button("hello", to: "/world")
#=> <button class="button" data-csrf="csrf_token" data-method="post" data-to="/world">hello</button>
button("hello", to: "/world", method: :get, class: "btn")
#=> <button class="btn" data-method="get" data-to="/world">hello</button>
## Options
* `:to` - the page to link to. This option is required
* `:method` - the method to use with the button. Defaults to :post.
All other options are forwarded to the underlying button input.
When the `:method` is set to `:get` and the `:to` URL contains query
parameters the generated form element will strip the parameters in accordance
with the [W3C](https://www.w3.org/TR/html401/interact/forms.html#h-17.13.3.4)
form specification.
## Data attributes
Data attributes are added as a keyword list passed to the
`data` key. The following data attributes are supported:
* `data-confirm` - shows a confirmation prompt before generating and
submitting the form.
"""
def wc_button(opts, do: contents) do
wc_button(contents, opts)
end
def wc_button(text, opts) do
{to, opts} = pop_required_option!(opts, :to, "option :to is required in button/2")
{link_opts, opts} =
opts
|> Keyword.put_new(:method, :post)
|> Keyword.split([:method, :csrf_token])
link_attributes = Phoenix.HTML.link_attributes(to, link_opts)
content_tag(:"mwc-button", text, link_attributes ++ opts)
end
defp pop_required_option!(opts, key, error_message) do
{value, opts} = Keyword.pop(opts, key)
unless value do
raise ArgumentError, error_message
end
{value, opts}
end
end