Skip to content

Commit 1f105ed

Browse files
committed
Add new events and move some event-related logic to surface_form
1 parent 2f7870e commit 1f105ed

File tree

8 files changed

+204
-385
lines changed

8 files changed

+204
-385
lines changed

lib/surface/components/events.ex

Lines changed: 0 additions & 43 deletions
This file was deleted.

lib/surface/components/link.ex

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,26 @@ defmodule Surface.Components.Link do
3535
@moduledoc deprecated: "Use liveview's built-in `<.link>` instead"
3636

3737
use Surface.Component
38-
use Surface.Components.Events
3938

40-
import Surface.Components.Utils
39+
@valid_uri_schemes [
40+
"http:",
41+
"https:",
42+
"ftp:",
43+
"ftps:",
44+
"mailto:",
45+
"news:",
46+
"irc:",
47+
"gopher:",
48+
"nntp:",
49+
"feed:",
50+
"telnet:",
51+
"mms:",
52+
"rtsp:",
53+
"svn:",
54+
"tel:",
55+
"fax:",
56+
"xmpp:"
57+
]
4158

4259
@doc "The page to link to"
4360
prop to, :any, required: true
@@ -61,6 +78,43 @@ defmodule Surface.Components.Link do
6178
"""
6279
prop opts, :keyword, default: []
6380

81+
@doc "Triggered when the component receives click"
82+
prop click, :event
83+
84+
@doc "Triggered when a click event happens outside of the element"
85+
prop click_away, :event
86+
87+
# TODO: Remove this when LV min is >= v0.20.15
88+
@doc "Triggered when the component captures click"
89+
prop capture_click, :event
90+
91+
@doc "Triggered when the component loses focus"
92+
prop blur, :event
93+
94+
@doc "Triggered when the component receives focus"
95+
prop focus, :event
96+
97+
@doc "Triggered when the page loses focus"
98+
prop window_blur, :event
99+
100+
@doc "Triggered when the page receives focus"
101+
prop window_focus, :event
102+
103+
@doc "Triggered when a key on the keyboard is pressed"
104+
prop keydown, :event
105+
106+
@doc "Triggered when a key on the keyboard is released"
107+
prop keyup, :event
108+
109+
@doc "Triggered when a key on the keyboard is pressed (window-level)"
110+
prop window_keydown, :event
111+
112+
@doc "Triggered when a key on the keyboard is released (window-level)"
113+
prop window_keyup, :event
114+
115+
@doc "List values that will be sent as part of the payload triggered by an event"
116+
prop values, :keyword, default: []
117+
64118
@doc """
65119
The content of the generated `<a>` element. If no content is provided,
66120
the value of property `label` is used instead.
@@ -101,4 +155,93 @@ defmodule Surface.Components.Link do
101155
Keyword.merge(opts, data: data, rel: "nofollow")
102156
end
103157
end
158+
159+
def csrf_data(to, opts) do
160+
case Keyword.pop(opts, :csrf_token, true) do
161+
{csrf, opts} when is_binary(csrf) ->
162+
{[csrf: csrf], opts}
163+
164+
{true, opts} ->
165+
{[csrf: csrf_token(to)], opts}
166+
167+
{false, opts} ->
168+
{[], opts}
169+
end
170+
end
171+
172+
defp csrf_token(to) do
173+
{mod, fun, args} = Application.fetch_env!(:surface, :csrf_token_reader)
174+
apply(mod, fun, [to | args])
175+
end
176+
177+
def valid_destination!(%URI{} = uri, context) do
178+
valid_destination!(URI.to_string(uri), context)
179+
end
180+
181+
def valid_destination!({:safe, to}, context) do
182+
{:safe, valid_string_destination!(IO.iodata_to_binary(to), context)}
183+
end
184+
185+
def valid_destination!({other, to}, _context) when is_atom(other) do
186+
[Atom.to_string(other), ?:, to]
187+
end
188+
189+
def valid_destination!(to, context) do
190+
valid_string_destination!(IO.iodata_to_binary(to), context)
191+
end
192+
193+
for scheme <- @valid_uri_schemes do
194+
def valid_string_destination!(unquote(scheme) <> _ = string, _context), do: string
195+
end
196+
197+
def valid_string_destination!(to, context) do
198+
if not match?("/" <> _, to) and String.contains?(to, ":") do
199+
raise ArgumentError, """
200+
unsupported scheme given to #{context}. In case you want to link to an
201+
unknown or unsafe scheme, such as javascript, use a tuple: {:javascript, rest}
202+
"""
203+
else
204+
to
205+
end
206+
end
207+
208+
def events_to_opts(assigns) do
209+
[
210+
event_to_opts(assigns.capture_click, :"phx-capture-click"),
211+
event_to_opts(assigns.click, :"phx-click"),
212+
event_to_opts(assigns.click_away, :"phx-click-away"),
213+
event_to_opts(assigns.window_focus, :"phx-window-focus"),
214+
event_to_opts(assigns.window_blur, :"phx-window-blur"),
215+
event_to_opts(assigns.focus, :"phx-focus"),
216+
event_to_opts(assigns.blur, :"phx-blur"),
217+
event_to_opts(assigns.window_keyup, :"phx-window-keyup"),
218+
event_to_opts(assigns.window_keydown, :"phx-window-keydown"),
219+
event_to_opts(assigns.keyup, :"phx-keyup"),
220+
event_to_opts(assigns.keydown, :"phx-keydown"),
221+
values_to_opts(assigns.values)
222+
]
223+
|> List.flatten()
224+
end
225+
226+
defp values_to_opts([]) do
227+
[]
228+
end
229+
230+
defp values_to_opts(values) when is_list(values) do
231+
values_to_attrs(values)
232+
end
233+
234+
defp values_to_opts(_values) do
235+
[]
236+
end
237+
238+
defp values_to_attrs(values) when is_list(values) do
239+
for {key, value} <- values do
240+
{:"phx-value-#{key}", value}
241+
end
242+
end
243+
244+
def skip_csrf(opts) do
245+
Keyword.delete(opts, :csrf_token)
246+
end
104247
end

lib/surface/components/utils.ex

Lines changed: 0 additions & 122 deletions
This file was deleted.

lib/surface/directive/events.ex

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@ defmodule Surface.Directive.Events do
22
use Surface.Directive
33

44
@events [
5+
# Click Events
56
"click",
67
"click-away",
8+
# TODO: Remove this when LV min is >= v0.20.15
79
"capture-click",
8-
"blur",
9-
"focus",
10+
# Form Events
1011
"change",
1112
"submit",
13+
# Focus Events
14+
"blur",
15+
"focus",
16+
"window-blur",
17+
"window-focus",
18+
# Key Events
1219
"keydown",
1320
"keyup",
14-
"window-focus",
15-
"window-blur",
1621
"window-keydown",
17-
"window-keyup"
22+
"window-keyup",
23+
# Scroll Events
24+
"viewport-top",
25+
"viewport-bottom"
1826
]
1927

2028
@phx_events Enum.map(@events, &"phx-#{&1}")

0 commit comments

Comments
 (0)