fix keyboard ui
This commit is contained in:
1 parent
83f4d7c728
commit
a26ae28189
5 files changed
+54
-8
No files matched your search
@@ -28,20 +28,40 @@ document.querySelectorAll('[data-conversation-workspace]').forEach(workspace=>{
|
||||
const layoutObserver='ResizeObserver' in window?new ResizeObserver(()=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false))}):null;
|
||||
layoutObserver?.observe(scroller);
|
||||
if(composer)layoutObserver?.observe(composer);
|
||||
window.addEventListener('appviewportchange',()=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false))});
|
||||
let stableViewportHeight=Math.max(window.visualViewport?.height||window.innerHeight,window.innerHeight);
|
||||
let inputVisibilityFrame=0;
|
||||
const ensureInputVisible=()=>{
|
||||
inputVisibilityFrame=0;
|
||||
if(!composer||!input||document.activeElement!==input||composer.classList.contains('is-collapsed'))return;
|
||||
const composerBox=composer.getBoundingClientRect(),inputBox=input.getBoundingClientRect(),padding=10;
|
||||
if(inputBox.top<composerBox.top+padding)composer.scrollTop+=inputBox.top-composerBox.top-padding;
|
||||
else if(inputBox.bottom>composerBox.bottom-padding)composer.scrollTop+=inputBox.bottom-composerBox.bottom+padding;
|
||||
};
|
||||
const scheduleInputVisibility=()=>{if(!inputVisibilityFrame)inputVisibilityFrame=requestAnimationFrame(()=>requestAnimationFrame(ensureInputVisible))};
|
||||
const updateKeyboardState=height=>{
|
||||
const inputFocused=document.activeElement===input;
|
||||
if(!inputFocused)stableViewportHeight=Math.max(stableViewportHeight,height);
|
||||
const keyboardOpen=inputFocused&&stableViewportHeight-height>120;
|
||||
composer?.classList.toggle('is-keyboard-active',keyboardOpen);
|
||||
composer?.setAttribute('data-keyboard-open',String(keyboardOpen));
|
||||
if(keyboardOpen)scheduleInputVisibility();
|
||||
};
|
||||
window.addEventListener('appviewportchange',event=>{if(followLatest)requestAnimationFrame(()=>scrollLatest(false));updateKeyboardState(event.detail?.height||window.visualViewport?.height||window.innerHeight)});
|
||||
input?.addEventListener('focus',()=>{updateKeyboardState(window.visualViewport?.height||window.innerHeight);scheduleInputVisibility()});
|
||||
input?.addEventListener('blur',()=>setTimeout(()=>updateKeyboardState(window.visualViewport?.height||window.innerHeight),0));
|
||||
|
||||
const groupDates=()=>{scroller.querySelectorAll('.date-divider').forEach(item=>item.remove());let previousDate='';scroller.querySelectorAll('[data-message]').forEach(message=>{if(message.dataset.date!==previousDate){const divider=document.createElement('div');divider.className='date-divider';divider.innerHTML=`<span>${message.dataset.dayLabel}</span>`;message.before(divider);previousDate=message.dataset.date}})};
|
||||
groupDates();
|
||||
document.body.addEventListener('htmx:beforeSwap',event=>{if(event.detail.target?.matches('[data-load-older]')){scroller.dataset.previousHeight=scroller.scrollHeight}});
|
||||
document.body.addEventListener('htmx:afterSwap',event=>{if(event.detail.target?.matches('[data-load-older]')){const previous=Number(scroller.dataset.previousHeight||0);groupDates();scroller.scrollTop+=scroller.scrollHeight-previous}});
|
||||
|
||||
const resize=()=>{if(!input)return;input.style.height='auto';input.style.height=`${Math.min(Math.max(input.scrollHeight,112),240)}px`};
|
||||
const resize=()=>{if(!input)return;input.style.height='auto';input.style.height=`${Math.min(Math.max(input.scrollHeight,112),240)}px`;scheduleInputVisibility()};
|
||||
const draftKey=()=>`${baseKey}-${mode}`;
|
||||
const status=workspace.querySelector('[data-draft-status]');
|
||||
const replyResult=workspace.dataset.replyResult||new URLSearchParams(location.search).get('reply_result')||'';
|
||||
const submissionSucceeded=replyResult==='reply'||replyResult==='note';
|
||||
if(submissionSucceeded){sessionStorage.removeItem(`${baseKey}-reply`);sessionStorage.removeItem(`${baseKey}-note`)}
|
||||
const setComposerOpen=(open,focus=true)=>{const keepLatestVisible=followLatest||atBottom();composer?.classList.toggle('is-collapsed',!open);composerToggle?.setAttribute('aria-expanded',String(open));[0,80,240].forEach(delay=>setTimeout(()=>{if(keepLatestVisible)scrollLatest(false)},delay));if(open&&focus)setTimeout(()=>input?.focus({preventScroll:true}),80)};
|
||||
const setComposerOpen=(open,focus=true)=>{const keepLatestVisible=followLatest||atBottom();composer?.classList.toggle('is-collapsed',!open);composerToggle?.setAttribute('aria-expanded',String(open));[0,80,240].forEach(delay=>setTimeout(()=>{if(keepLatestVisible)scrollLatest(false)},delay));if(open&&focus)setTimeout(()=>{input?.focus({preventScroll:true});scheduleInputVisibility()},80)};
|
||||
const saveDraft=()=>{if(!input)return;sessionStorage.setItem(draftKey(),input.value);if(status){status.textContent=input.value?'پیشنویس ذخیره شد':'';clearTimeout(saveDraft.timer);saveDraft.timer=setTimeout(()=>status.textContent='',1800)}};
|
||||
const loadDraft=()=>{if(!input)return;input.value=sessionStorage.getItem(draftKey())||'';resize();input.dispatchEvent(new Event('input',{bubbles:true}))};
|
||||
if(input){input.setAttribute('rows','5');input.setAttribute('placeholder','شرح کامل پاسخ، اطلاعات تکمیلی و نتیجه مورد انتظار خود را بنویسید…');input.addEventListener('input',()=>{resize();saveDraft()});loadDraft()}
|
||||
@@ -122,7 +142,7 @@ document.querySelectorAll('[data-conversation-workspace]').forEach(workspace=>{
|
||||
// cancel a recursively scheduled timeout. pollRunning prevents overlap and
|
||||
// nextPollAt preserves the normal interval and network-error backoff.
|
||||
const pollHeartbeat=setInterval(startPolling,1000);
|
||||
window.addEventListener('beforeunload',()=>{clearInterval(pollHeartbeat);stopPolling();layoutObserver?.disconnect()},{once:true});
|
||||
window.addEventListener('beforeunload',()=>{clearInterval(pollHeartbeat);stopPolling();layoutObserver?.disconnect();if(inputVisibilityFrame)cancelAnimationFrame(inputVisibilityFrame)},{once:true});
|
||||
startPolling();
|
||||
|
||||
const resetMessageMenu=menu=>{if(!menu)return;const editor=menu.querySelector('[data-message-editor]');const choices=menu.querySelector('[data-message-menu-choices]');const input=menu.querySelector('[data-message-edit-input]');if(editor)editor.hidden=true;if(choices)choices.hidden=false;if(input){input.value=input.dataset.originalValue||'';input.dispatchEvent(new Event('input',{bubbles:true}))}};
|
||||
|
||||
Reference in new issue
Block a user