Add deletion control for attached videos

0fa1b26fa44de4c4f1182cd9182426f8580e7d6b

Cohee <18619528+Cohee1207@users.noreply.github.com>

4 files changed, +74 -33Ignore whitespace
public/index.html+23 -13
@@ -6844,19 +6844,19 @@
6844 <div class="mes_reasoning"></div>6844 <div class="mes_reasoning"></div>
6845 </details>6845 </details>
6846 <div class="mes_text"></div>6846 <div class="mes_text"></div>
6847 <div class="mes_img_container">6847 <div class="mes_img_container">
6848 <div class="mes_img_controls">6848 <div class="mes_img_controls">
6849 <div title="Expand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_img_enlarge" data-i18n="[title]Expand and zoom"></div>6849 <div title="Expand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_img_enlarge" data-i18n="[title]Expand and zoom"></div>
6850 <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div>6850 <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div>
6851 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_img_delete" data-i18n="[title]Delete"></div>6851 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_img_delete" data-i18n="[title]Delete"></div>
6852 </div>6852 </div>
6853 <div class="mes_img_swipes">6853 <div class="mes_img_swipes">
6854 <div title="Swipe left" class="right_menu_button fa-lg fa-solid fa-chevron-left mes_img_swipe_left" data-i18n="[title]Swipe left"></div>6854 <div title="Swipe left" class="right_menu_button fa-lg fa-solid fa-chevron-left mes_img_swipe_left" data-i18n="[title]Swipe left"></div>
6855 <div class="mes_img_swipe_counter">1/1</div>6855 <div class="mes_img_swipe_counter">1/1</div>
6856 <div title="Swipe right" class="right_menu_button fa-lg fa-solid fa-chevron-right mes_img_swipe_right" data-i18n="[title]Swipe right"></div>6856 <div title="Swipe right" class="right_menu_button fa-lg fa-solid fa-chevron-right mes_img_swipe_right" data-i18n="[title]Swipe right"></div>
6857 </div>6857 </div>
6858 <img class="mes_img" src="" />6858 <img class="mes_img" src="" />
6859 </div>6859 </div>
6860 <div class="mes_bias"></div>6860 <div class="mes_bias"></div>
6861 </div>6861 </div>
6862 <div class="flex-container swipeRightBlock flexFlowColumn flexNoGap">6862 <div class="flex-container swipeRightBlock flexFlowColumn flexNoGap">
@@ -7066,6 +7066,16 @@
7066 <div class="right_menu_button mes_file_delete fa-solid fa-trash-can" title="Remove the file" data-i18n="[title]Remove the file"></div>7066 <div class="right_menu_button mes_file_delete fa-solid fa-trash-can" title="Remove the file" data-i18n="[title]Remove the file"></div>
7067 </div>7067 </div>
7068 </div>7068 </div>
7069
7070 <div id="message_video_template" class="template_element">
7071 <div class="mes_video_container">
7072 <div class="mes_video_controls">
7073 <div><!-- Placeholder --></div>
7074 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_video_delete" data-i18n="[title]Delete"></div>
7075 </div>
7076 <video class="mes_video" controls preload="metadata"></video>
7077 </div>
7078 </div>
7069 </div>7079 </div>
7070 <div id="movingDivs">7080 <div id="movingDivs">
7071 <div id="floatingPrompt" class="drawer-content flexGap5">7081 <div id="floatingPrompt" class="drawer-content flexGap5">
public/script.js+5 -10
@@ -2505,16 +2505,11 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) {
25052505
2506 // Add video to message2506 // Add video to message
2507 if (mes.extra?.video) {2507 if (mes.extra?.video) {
2508 const container = messageElement.find('.mes_block');2508 const container = $('#message_video_template .mes_video_container').clone();
2509 messageElement.find('.mes_video_container').remove();
2510 messageElement.find('.mes_block').append(container);
2509 const chatHeight = $('#chat').prop('scrollHeight');2511 const chatHeight = $('#chat').prop('scrollHeight');
25102512 const video = container.find('.mes_video');
2511 // Create video element if it doesn't exist
2512 let video = messageElement.find('.mes_video');
2513 if (video.length === 0) {
2514 video = $('<video class="mes_video" controls preload="metadata"></video>');
2515 container.append(video);
2516 }
2517
2518 video.off('loadedmetadata').on('loadedmetadata', function () {2513 video.off('loadedmetadata').on('loadedmetadata', function () {
2519 if (!adjustScroll) {2514 if (!adjustScroll) {
2520 return;2515 return;
@@ -2527,7 +2522,7 @@ export function appendMediaToMessage(mes, messageElement, adjustScroll = true) {
25272522
2528 video.attr('src', mes.extra?.video);2523 video.attr('src', mes.extra?.video);
2529 } else {2524 } else {
2530 messageElement.find('.mes_video').remove();2525 messageElement.find('.mes_video_container').remove();
2531 }2526 }
25322527
2533 // Add file to message2528 // Add file to message
public/scripts/chats.js+22 -0
@@ -893,6 +893,27 @@ async function deleteMessageImage() {
893 await saveChatConditional();893 await saveChatConditional();
894}894}
895895
896async function deleteMessageVideo() {
897 const confirm = await Popup.show.confirm(t`Delete video from message?`, t`This action can't be undone.`);
898 if (!confirm) {
899 return;
900 }
901
902 const mesBlock = $(this).closest('.mes');
903 const mesId = mesBlock.attr('mesid');
904 const message = chat[mesId];
905
906 if (!message?.extra?.video) {
907 console.warn('Message has no video or it is empty');
908 return;
909 }
910
911 delete message.extra.video;
912 mesBlock.find('.mes_video_container').remove();
913
914 await saveChatConditional();
915}
916
896/**917/**
897 * Deletes file from the server.918 * Deletes file from the server.
898 * @param {string} url Path to the file on the server919 * @param {string} url Path to the file on the server
@@ -1856,6 +1877,7 @@ export function initChatUtilities() {
1856 $(document).on('click', '.mes_img', expandMessageImage);1877 $(document).on('click', '.mes_img', expandMessageImage);
1857 $(document).on('click', '.mes_img_enlarge', expandAndZoomMessageImage);1878 $(document).on('click', '.mes_img_enlarge', expandAndZoomMessageImage);
1858 $(document).on('click', '.mes_img_delete', deleteMessageImage);1879 $(document).on('click', '.mes_img_delete', deleteMessageImage);
1880 $(document).on('click', '.mes_video_delete', deleteMessageVideo);
18591881
1860 $('#file_form_input').on('change', async () => {1882 $('#file_form_input').on('change', async () => {
1861 const fileInput = document.getElementById('file_form_input');1883 const fileInput = document.getElementById('file_form_input');
public/style.css+24 -10
@@ -5033,8 +5033,9 @@ a:hover {
5033 display: none;5033 display: none;
5034}5034}
50355035
5036/* Message images */5036/* Message images/video */
5037.mes .mes_img_container {5037.mes .mes_img_container,
5038.mes .mes_video_container {
5038 max-width: 100%;5039 max-width: 100%;
5039 /*to fit inside single window height of mobile landscape*/5040 /*to fit inside single window height of mobile landscape*/
5040 display: none;5041 display: none;
@@ -5044,8 +5045,12 @@ a:hover {
5044 padding: 0.5rem;5045 padding: 0.5rem;
5045}5046}
50465047
5048.mes .mes_video_container:has(.mes_video[src]) {
5049 display: flex;
5050}
5051
5047.mes_img {5052.mes_img {
5048 border-radius: 10px;5053 border-radius: 5px;
5049 max-width: 100%;5054 max-width: 100%;
5050 max-height: 40vh;5055 max-height: 40vh;
5051 image-rendering: -webkit-optimize-contrast;5056 image-rendering: -webkit-optimize-contrast;
@@ -5059,7 +5064,8 @@ a:hover {
5059}5064}
50605065
5061.mes_img_swipes,5066.mes_img_swipes,
5062.mes_img_controls {5067.mes_img_controls,
5068.mes_video_controls {
5063 position: absolute;5069 position: absolute;
5064 top: 0.1em;5070 top: 0.1em;
5065 left: 0;5071 left: 0;
@@ -5070,6 +5076,8 @@ a:hover {
5070 justify-content: space-between;5076 justify-content: space-between;
5071 align-items: center;5077 align-items: center;
5072 padding: 1em;5078 padding: 1em;
5079 z-index: 1;
5080 transition: opacity var(--animation-duration) ease-in-out;
5073}5081}
50745082
5075.mes_img_swipes {5083.mes_img_swipes {
@@ -5078,7 +5086,8 @@ a:hover {
5078}5086}
50795087
5080.mes_img_swipes .right_menu_button,5088.mes_img_swipes .right_menu_button,
5081.mes_img_controls .right_menu_button {5089.mes_img_controls .right_menu_button,
5090.mes_video_controls .right_menu_button {
5082 filter: brightness(90%);5091 filter: brightness(90%);
5083 text-shadow: 1px 1px var(--SmartThemeShadowColor) !important;5092 text-shadow: 1px 1px var(--SmartThemeShadowColor) !important;
5084 padding: 1px;5093 padding: 1px;
@@ -5087,23 +5096,29 @@ a:hover {
5087}5096}
50885097
5089.mes_img_swipes .right_menu_button::before,5098.mes_img_swipes .right_menu_button::before,
5090.mes_img_controls .right_menu_button::before {5099.mes_img_controls .right_menu_button::before,
5100.mes_video_controls .right_menu_button::before {
5091 /* Fix weird alignment with this font-awesome icons on focus */5101 /* Fix weird alignment with this font-awesome icons on focus */
5092 position: relative;5102 position: relative;
5093 top: 0.6125em;5103 top: 0.6125em;
5094}5104}
50955105
5096.mes_img_swipes .right_menu_button:hover,5106.mes_img_swipes .right_menu_button:hover,
5097.mes_img_controls .right_menu_button:hover {5107.mes_img_controls .right_menu_button:hover,
5108.mes_video_controls .right_menu_button:hover {
5098 filter: brightness(150%);5109 filter: brightness(150%);
5099}5110}
51005111
5112/* It's better to show controls only when the video is not playing */
5113/* but :playing pseudo-class is not supported in all browsers */
5114/* .mes_video_container:focus-within .mes_video_controls:not(:has(.mes_video:playing)), */
5101.mes_img_container:has(.mes_img.error) .mes_img_swipes,5115.mes_img_container:has(.mes_img.error) .mes_img_swipes,
5102.mes_img_container:has(.mes_img.error) .mes_img_controls,5116.mes_img_container:has(.mes_img.error) .mes_img_controls,
5103.mes_img_container:hover .mes_img_swipes,5117.mes_img_container:hover .mes_img_swipes,
5104.mes_img_container:focus-within .mes_img_swipes,5118.mes_img_container:focus-within .mes_img_swipes,
5105.mes_img_container:hover .mes_img_controls,5119.mes_img_container:hover .mes_img_controls,
5106.mes_img_container:focus-within .mes_img_controls {5120.mes_img_container:focus-within .mes_img_controls,
5121.mes_video_container:hover .mes_video_controls {
5107 opacity: 1;5122 opacity: 1;
5108}5123}
51095124
@@ -5203,9 +5218,8 @@ body:not(.sd) .mes_img_swipes {
5203.mes_video {5218.mes_video {
5204 max-width: 100%;5219 max-width: 100%;
5205 max-height: 400px;5220 max-height: 400px;
5206 border-radius: 8px;5221 border-radius: 5px;
5207 background: #000;5222 background: #000;
5208 margin: 0.5rem;
5209}5223}
52105224
5211/* Ensure video controls are visible */5225/* Ensure video controls are visible */