Skip to content

Commit 8e6adbc

Browse files
committed
feat: live_video_preview
1 parent 35de681 commit 8e6adbc

3 files changed

Lines changed: 119 additions & 0 deletions

File tree

assets/js/phoenix_live_view/hooks.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ let Hooks = {
4343
URL.revokeObjectURL(this.url)
4444
}
4545
},
46+
// Currently this is exactly the same as the LiveImgPreview, but I wanted to add this
47+
// so possibly this can have functionality specific to videos in the future.
48+
LiveVideoPreview: {
49+
mounted(){
50+
this.ref = this.el.getAttribute("data-phx-entry-ref")
51+
this.inputEl = document.getElementById(this.el.getAttribute(PHX_UPLOAD_REF))
52+
LiveUploader.getEntryDataURL(this.inputEl, this.ref, url => {
53+
this.url = url
54+
this.el.src = url
55+
})
56+
},
57+
destroyed(){
58+
URL.revokeObjectURL(this.url)
59+
}
60+
},
4661
FocusWrap: {
4762
mounted(){
4863
this.focusStart = this.el.firstElementChild

lib/phoenix_component.ex

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,46 @@ defmodule Phoenix.Component do
25822582
raise ArgumentError, "missing required :entry attribute to <.live_img_preview/>"
25832583
end
25842584

2585+
@doc """
2586+
Generates a video preview on the client for a selected file.
2587+
2588+
## Examples
2589+
2590+
```heex
2591+
<%= for entry <- @uploads.avatar.entries do %>
2592+
<.live_video_preview entry={entry} width="400" />
2593+
<% end %>
2594+
```
2595+
"""
2596+
@doc type: :component
2597+
def live_video_preview(assigns)
2598+
2599+
# attr :entry, Phoenix.LiveView.UploadEntry, required: true
2600+
# attr :rest, :global
2601+
def live_video_preview(%{entry: %Phoenix.LiveView.UploadEntry{ref: ref} = entry} = assigns) do
2602+
rest =
2603+
assigns
2604+
|> assigns_to_attributes([:entry])
2605+
|> Keyword.put_new_lazy(:id, fn -> "phx-preview-#{ref}" end)
2606+
2607+
assigns = assign(assigns, entry: entry, ref: ref, rest: rest)
2608+
2609+
~H"""
2610+
<video
2611+
controls
2612+
data-phx-upload-ref={@entry.upload_ref}
2613+
data-phx-entry-ref={@ref}
2614+
data-phx-hook="Phoenix.LiveVideoPreview"
2615+
data-phx-update="ignore"
2616+
{@rest}
2617+
/>
2618+
"""
2619+
end
2620+
2621+
def live_video_preview(_assigns) do
2622+
raise ArgumentError, "missing required :entry attribute to <.live_video_preview/>"
2623+
end
2624+
25852625
@doc """
25862626
Intersperses separator slot between an enumerable.
25872627

test/phoenix_component/components_test.exs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,70 @@ defmodule Phoenix.LiveView.ComponentsTest do
479479
end
480480
end
481481

482+
describe "live_img_preview/1" do
483+
test "basic usage" do
484+
entry = %Phoenix.LiveView.UploadEntry{
485+
progress: 100,
486+
preflighted?: true,
487+
upload_config: :poster_imgix_src,
488+
upload_ref: "phx-Fz1Xjn4seffww0vC",
489+
ref: "1",
490+
uuid: "898e29b9-1724-4b5f-b42f-2389b85bb9f4",
491+
valid?: true,
492+
done?: true,
493+
cancelled?: false,
494+
client_name: "an_image.jpg",
495+
client_relative_path: "",
496+
client_size: 2065187,
497+
client_type: "image/jpeg",
498+
client_last_modified: 1646642130571
499+
}
500+
assigns = %{entry: entry}
501+
502+
assert render(~H|<.live_img_preview entry={@entry}/>|) == ~s|<img data-phx-upload-ref="phx-Fz1Xjn4seffww0vC" data-phx-entry-ref="1" data-phx-hook="Phoenix.LiveImgPreview" data-phx-update="ignore" id="phx-preview-1">|
503+
end
504+
505+
test "requires an entry to be given" do
506+
assigns = %{}
507+
508+
assert_raise ArgumentError, "missing required :entry attribute to <.live_img_preview/>", fn ->
509+
render(~H|<.live_img_preview />|)
510+
end
511+
end
512+
end
513+
514+
describe "live_video_preview/1" do
515+
test "basic usage" do
516+
entry = %Phoenix.LiveView.UploadEntry{
517+
progress: 100,
518+
preflighted?: true,
519+
upload_config: :some_field,
520+
upload_ref: "phx-Fz1Xjn4tLhvww0xC",
521+
ref: "0",
522+
uuid: "e3ae39ee-8251-4e24-9655-d1574adef682",
523+
valid?: true,
524+
done?: true,
525+
cancelled?: false,
526+
client_name: "a_video.mp4",
527+
client_relative_path: "",
528+
client_size: 17116709,
529+
client_type: "video/mp4",
530+
client_last_modified: 1671742709575
531+
}
532+
assigns = %{entry: entry}
533+
534+
assert render(~H|<.live_video_preview entry={@entry}/>|) == ~s|<video controls data-phx-upload-ref="phx-Fz1Xjn4tLhvww0xC" data-phx-entry-ref="0" data-phx-hook="Phoenix.LiveImgPreview" data-phx-update="ignore" id="phx-preview-0"></video>|
535+
end
536+
537+
test "requires an entry to be given" do
538+
assigns = %{}
539+
540+
assert_raise ArgumentError, "missing required :entry attribute to <.live_video_preview/>", fn ->
541+
render(~H|<.live_video_preview />|)
542+
end
543+
end
544+
end
545+
482546
describe "intersperse" do
483547
test "generates form with no options" do
484548
assigns = %{}

0 commit comments

Comments
 (0)