Implement autofit for edit textarea
| @@ -849,11 +849,9 @@ export let is_send_press = false; //Send generation | |||
| 849 | 849 | ||
| 850 | let this_del_mes = -1; | 850 | let this_del_mes = -1; |
| 851 | 851 | ||
| 852 | //message editing and chat scroll position persistence | 852 | //message editing |
| 853 | var this_edit_mes_chname = ''; | 853 | var this_edit_mes_chname = ''; |
| 854 | var this_edit_mes_id; | 854 | var this_edit_mes_id; |
| 855 | var scroll_holder = 0; | ||
| 856 | var is_use_scroll_holder = false; | ||
| 857 | 855 | ||
| 858 | //settings | 856 | //settings |
| 859 | export let settings; | 857 | export let settings; |
| @@ -9727,25 +9725,7 @@ jQuery(async function () { | |||
| 9727 | chooseBogusFolder($(this), tagId); | 9725 | chooseBogusFolder($(this), tagId); |
| 9728 | }); | 9726 | }); |
| 9729 | 9727 | ||
| 9730 | /** | 9728 | const cssAutofit = CSS.supports('field-sizing', 'content'); |
| 9731 | * Sets the scroll height of the edit textarea to fit the content. | ||
| 9732 | * @param {HTMLTextAreaElement} e Textarea element to auto-fit | ||
| 9733 | */ | ||
| 9734 | function autoFitEditTextArea(e) { | ||
| 9735 | scroll_holder = chatElement[0].scrollTop; | ||
| 9736 | e.style.height = '0px'; | ||
| 9737 | const newHeight = e.scrollHeight + 4; | ||
| 9738 | e.style.height = `${newHeight}px`; | ||
| 9739 | is_use_scroll_holder = true; | ||
| 9740 | } | ||
| 9741 | const autoFitEditTextAreaDebounced = debounce(autoFitEditTextArea, debounce_timeout.short); | ||
| 9742 | document.addEventListener('input', e => { | ||
| 9743 | if (e.target instanceof HTMLTextAreaElement && e.target.classList.contains('edit_textarea')) { | ||
| 9744 | const scrollbarShown = e.target.clientWidth < e.target.offsetWidth && e.target.offsetHeight >= window.innerHeight * 0.75; | ||
| 9745 | const immediately = (e.target.scrollHeight > e.target.offsetHeight && !scrollbarShown) || e.target.value === ''; | ||
| 9746 | immediately ? autoFitEditTextArea(e.target) : autoFitEditTextAreaDebounced(e.target); | ||
| 9747 | } | ||
| 9748 | }); | ||
| 9749 | const chatElementScroll = document.getElementById('chat'); | 9729 | const chatElementScroll = document.getElementById('chat'); |
| 9750 | const chatScrollHandler = function () { | 9730 | const chatScrollHandler = function () { |
| 9751 | if (power_user.waifuMode) { | 9731 | if (power_user.waifuMode) { |
| @@ -9767,12 +9747,26 @@ jQuery(async function () { | |||
| 9767 | }; | 9747 | }; |
| 9768 | chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true }); | 9748 | chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true }); |
| 9769 | chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true }); | 9749 | chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true }); |
| 9770 | chatElementScroll.addEventListener('scroll', function () { | 9750 | |
| 9771 | if (is_use_scroll_holder) { | 9751 | if (!cssAutofit) { |
| 9772 | this.scrollTop = scroll_holder; | 9752 | /** |
| 9773 | is_use_scroll_holder = false; | 9753 | * Sets the scroll height of the edit textarea to fit the content. |
| 9774 | } | 9754 | * @param {HTMLTextAreaElement} e Textarea element to auto-fit |
| 9775 | }, { passive: true }); | 9755 | */ |
| 9756 | function autoFitEditTextArea(e) { | ||
| 9757 | e.style.height = '0px'; | ||
| 9758 | const newHeight = e.scrollHeight + 4; | ||
| 9759 | e.style.height = `${newHeight}px`; | ||
| 9760 | } | ||
| 9761 | const autoFitEditTextAreaDebounced = debounce(autoFitEditTextArea, debounce_timeout.short); | ||
| 9762 | document.addEventListener('input', e => { | ||
| 9763 | if (e.target instanceof HTMLTextAreaElement && e.target.classList.contains('edit_textarea')) { | ||
| 9764 | const scrollbarShown = e.target.clientWidth < e.target.offsetWidth && e.target.offsetHeight >= window.innerHeight * 0.75; | ||
| 9765 | const immediately = (e.target.scrollHeight > e.target.offsetHeight && !scrollbarShown) || e.target.value === ''; | ||
| 9766 | immediately ? autoFitEditTextArea(e.target) : autoFitEditTextAreaDebounced(e.target); | ||
| 9767 | } | ||
| 9768 | }); | ||
| 9769 | } | ||
| 9776 | 9770 | ||
| 9777 | $(document).on('click', '.mes', function () { | 9771 | $(document).on('click', '.mes', function () { |
| 9778 | //when a 'delete message' parent div is clicked | 9772 | //when a 'delete message' parent div is clicked |
| @@ -10517,8 +10511,10 @@ jQuery(async function () { | |||
| 10517 | let edit_textarea = $(this) | 10511 | let edit_textarea = $(this) |
| 10518 | .closest('.mes_block') | 10512 | .closest('.mes_block') |
| 10519 | .find('.edit_textarea'); | 10513 | .find('.edit_textarea'); |
| 10520 | edit_textarea.height(0); | 10514 | if (!cssAutofit) { |
| 10521 | edit_textarea.height(edit_textarea[0].scrollHeight); | 10515 | edit_textarea.height(0); |
| 10516 | edit_textarea.height(edit_textarea[0].scrollHeight); | ||
| 10517 | } | ||
| 10522 | edit_textarea.focus(); | 10518 | edit_textarea.focus(); |
| 10523 | edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text | 10519 | edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text |
| 10524 | String(edit_textarea.val()).length, | 10520 | String(edit_textarea.val()).length, |
| @@ -890,9 +890,6 @@ export function initRossMods() { | |||
| 890 | const cssAutofit = CSS.supports('field-sizing', 'content'); | 890 | const cssAutofit = CSS.supports('field-sizing', 'content'); |
| 891 | 891 | ||
| 892 | if (cssAutofit) { | 892 | if (cssAutofit) { |
| 893 | sendTextArea.style['fieldSizing'] = 'content'; | ||
| 894 | sendTextArea.style['height'] = 'auto'; | ||
| 895 | |||
| 896 | let lastHeight = chatBlock.offsetHeight; | 893 | let lastHeight = chatBlock.offsetHeight; |
| 897 | const chatBlockResizeObserver = new ResizeObserver((entries) => { | 894 | const chatBlockResizeObserver = new ResizeObserver((entries) => { |
| 898 | for (const entry of entries) { | 895 | for (const entry of entries) { |
| @@ -919,6 +916,8 @@ export function initRossMods() { | |||
| 919 | saveUserInputDebounced(); | 916 | saveUserInputDebounced(); |
| 920 | 917 | ||
| 921 | if (cssAutofit) { | 918 | if (cssAutofit) { |
| 919 | // Unset modifications made with a manual resize | ||
| 920 | sendTextArea.style.height = 'auto'; | ||
| 922 | return; | 921 | return; |
| 923 | } | 922 | } |
| 924 | 923 | ||
| @@ -1264,6 +1264,7 @@ button { | |||
| 1264 | text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor); | 1264 | text-shadow: 0px 0px calc(var(--shadowWidth) * 1px) var(--SmartThemeShadowColor); |
| 1265 | flex: 1; | 1265 | flex: 1; |
| 1266 | order: 3; | 1266 | order: 3; |
| 1267 | field-sizing: content; | ||
| 1267 | 1268 | ||
| 1268 | --progColor: rgb(146, 190, 252); | 1269 | --progColor: rgb(146, 190, 252); |
| 1269 | --progFlashColor: rgb(215, 136, 114); | 1270 | --progFlashColor: rgb(215, 136, 114); |
| @@ -4111,6 +4112,7 @@ input[type="range"]::-webkit-slider-thumb { | |||
| 4111 | line-height: calc(var(--mainFontSize) + .25rem); | 4112 | line-height: calc(var(--mainFontSize) + .25rem); |
| 4112 | max-height: 75vh; | 4113 | max-height: 75vh; |
| 4113 | max-height: 75dvh; | 4114 | max-height: 75dvh; |
| 4115 | field-sizing: content; | ||
| 4114 | } | 4116 | } |
| 4115 | 4117 | ||
| 4116 | #anchor_order { | 4118 | #anchor_order { |