move webcam JS to its own file

This commit is contained in:
thomas girod 2024-09-19 22:16:39 +02:00 committed by Bartuccio Antoine
parent d47461ba40
commit 3d138d404f
2 changed files with 132 additions and 123 deletions

View File

@ -0,0 +1,110 @@
function alpine_webcam_builder(
default_picture,
delete_url,
can_delete_picture,
) {
return () => ({
can_edit_picture: false,
loading: false,
is_camera_enabled: false,
is_camera_error: false,
picture: null,
video: null,
picture_form: null,
init() {
this.video = this.$refs.video;
this.picture_form = this.$refs.form.getElementsByTagName("input");
if (this.picture_form.length > 0) {
this.picture_form = this.picture_form[0];
this.can_edit_picture = true;
// Link the displayed element to the form input
this.picture_form.onchange = (event) => {
let files = event.srcElement.files;
if (files.length > 0) {
this.picture = (window.URL || window.webkitURL).createObjectURL(
event.srcElement.files[0],
);
} else {
this.picture = null;
}
};
}
},
get_picture() {
return this.picture || default_picture;
},
delete_picture() {
// Only remove currently displayed picture
if (!!this.picture) {
let list = new DataTransfer();
this.picture_form.files = list.files;
this.picture_form.dispatchEvent(new Event("change"));
return;
}
if (!can_delete_picture) {
return;
}
// Remove user picture if correct rights are available
window.open(delete_url, "_self");
},
enable_camera() {
this.picture = null;
this.loading = true;
this.is_camera_error = false;
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
.then((stream) => {
this.loading = false;
this.is_camera_enabled = true;
this.video.srcObject = stream;
this.video.play();
})
.catch((err) => {
this.is_camera_error = true;
this.loading = false;
});
},
take_picture() {
let canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
/* Create the image */
let settings = this.video.srcObject.getTracks()[0].getSettings();
canvas.width = settings.width;
canvas.height = settings.height;
context.drawImage(this.video, 0, 0, canvas.width, canvas.height);
/* Stop camera */
this.video.pause();
this.video.srcObject.getTracks().forEach((track) => {
if (track.readyState === "live") {
track.stop();
}
});
canvas.toBlob((blob) => {
const filename = interpolate(gettext("captured.%s"), ["webp"]);
let file = new File([blob], filename, {
type: "image/webp",
});
let list = new DataTransfer();
list.items.add(file);
this.picture_form.files = list.files;
// No change event is triggered, we trigger it manually #}
this.picture_form.dispatchEvent(new Event("change"));
}, "image/webp");
canvas.remove();
this.is_camera_enabled = false;
},
});
}

View File

@ -8,7 +8,12 @@
<link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}"> <link rel="stylesheet" href="{{ scss('user/user_edit.scss') }}">
{%- endblock -%} {%- endblock -%}
{% block additional_js %}
<script defer src="{{ static("user/js/user_edit.js") }}"></script>
{% endblock %}
{% macro profile_picture(field_name) %} {% macro profile_picture(field_name) %}
{% set this_picture = form.instance[field_name] %}
<div class="profile-picture" x-data="camera_{{ field_name }}" > <div class="profile-picture" x-data="camera_{{ field_name }}" >
<div class="profile-picture-display" :aria-busy="loading" :class="{ 'camera-error': is_camera_error }"> <div class="profile-picture-display" :aria-busy="loading" :class="{ 'camera-error': is_camera_error }">
<img <img
@ -50,8 +55,8 @@
<div> <div>
{{ form[field_name] }} {{ form[field_name] }}
<button class="btn btn-red" @click.prevent="delete_picture()" <button class="btn btn-red" @click.prevent="delete_picture()"
{%- if not (user.is_root and form.instance[field_name]) -%} {%- if not (this_picture and this_picture.is_owned_by(user)) -%}
:disabled="picture == null" :disabled="!picture"
{%- endif -%} {%- endif -%}
x-cloak x-cloak
> >
@ -68,128 +73,22 @@
</div> </div>
</div> </div>
<script> <script>
document.addEventListener("alpine:init", () => { {%- if this_picture -%}
Alpine.data("camera_{{ field_name }}", () => ({ {% set default_picture = this_picture.get_download_url()|tojson %}
can_edit_picture: false, {% set delete_url = url('core:file_delete', file_id=this_picture.id, popup='')|tojson %}
loading: false,
is_camera_enabled: false,
is_camera_error: false,
picture: null,
video: null,
picture_form: null,
init() {
this.video = this.$refs.video;
this.picture_form = this.$refs.form.getElementsByTagName("input");
if (this.picture_form.length > 0){
this.picture_form = this.picture_form[0];
this.can_edit_picture = true;
{# Link the displayed element to the form input #}
this.picture_form.onchange = (event) => {
let files = event.srcElement.files;
if (files.length > 0){
this.picture = (window.URL || window.webkitURL)
.createObjectURL(event.srcElement.files[0]);
} else {
this.picture = null;
}
}
}
},
get_picture() {
if (this.picture != null) {
return this.picture;
}
{%- if form.instance[field_name] -%}
return "{{ form.instance[field_name].get_download_url() }}"
{%- else -%} {%- else -%}
return "{{ static('core/img/unknown.jpg') }}" {% set default_picture = static('core/img/unknown.jpg')|tojson %}
{% set delete_url = "null" %}
{%- endif -%} {%- endif -%}
}, document.addEventListener("alpine:init", () => {
Alpine.data(
delete_picture() { "camera_{{ field_name }}",
alpine_webcam_builder(
{# Only remove currently displayed picture #} {{ default_picture }},
if (this.picture != null){ {{ delete_url }},
let list = new DataTransfer(); {{ (this_picture and this_picture.is_owned_by(user))|tojson }}
this.picture_form.files = list.files; )
this.picture_form.dispatchEvent(new Event("change"));
return;
}
{# Remove user picture if correct rights are available #}
{%- if user.is_root and form.instance[field_name] -%}
window.open(
'{{ url(
'core:file_delete',
file_id=form.instance[field_name].id,
popup=''
) }}',
'_self');
{%- endif -%}
},
enable_camera() {
this.picture = null;
this.loading = true;
this.is_camera_error = false;
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
.then((stream) => {
this.loading = false;
this.is_camera_enabled = true;
this.video.srcObject = stream;
this.video.play();
})
.catch((err) => {
this.is_camera_error = true;
this.loading = false;
});
},
take_picture() {
let canvas = document.createElement("canvas")
const context = canvas.getContext("2d");
/* Create the image */
let settings = this.video.srcObject.getTracks()[0].getSettings();
canvas.width = settings.width;
canvas.height = settings.height;
context.drawImage(this.video, 0, 0, canvas.width, canvas.height);
/* Stop camera */
this.video.pause()
this.video.srcObject.getTracks().forEach((track) => {
if (track.readyState === 'live') {
track.stop();
}
});
canvas.toBlob((blob) => {
let file = new File(
[blob],
"{% trans %}captured{% endtrans %}.webp",
{ type: "image/webp" },
); );
let list = new DataTransfer();
list.items.add(file);
this.picture_form.files = list.files;
{# No change event is triggered, we trigger it manually #}
this.picture_form.dispatchEvent(new Event("change"));
}, "image/webp");
canvas.remove();
this.is_camera_enabled = false;
},
}));
}); });
</script> </script>
{% endmacro %} {% endmacro %}