templates/editor: variavel mobile insere na posicao do cursor
Antes: variavel inseria sempre no fim do texto no mobile.
Causa: usavamos append direto no form (form[field] += tag) porque
o foco estava no drawer e Jodit.insertHTML travava.
Fix: capturar selection ANTES do drawer abrir, restaurar antes de
inserir.
JoditEmailEditor expose API estendida:
- saveSelection() -> retorna markers (jodit.selection.save())
- restoreSelection(markers) -> re-foca editor + restaura markers
- focus() -> foca o editor
DocumentTemplateEditor:
- ref savedSelection capturada em openDrawer('vars'): snapshot dos
markers do Jodit no momento (cursor original)
- insertVariable mobile: setTimeout 280ms apos fechar drawer ->
restaura markers -> insertHTML (cursor volta pra onde estava ->
variavel aparece no ponto exato)
- Fallback append no form se restore falhar
- savedSelection limpa em fecharDrawer + apos insert
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -194,7 +194,24 @@ watch(
|
||||
|
||||
// ── API exposta ───────────────────────────────────────────────
|
||||
defineExpose({
|
||||
insertHTML: (html) => jodit?.selection.insertHTML(html)
|
||||
insertHTML: (html) => jodit?.selection.insertHTML(html),
|
||||
// Salva markers da seleção atual antes do foco sair do editor
|
||||
// (ex: usuário abre drawer e perde o cursor). Retorna o array de
|
||||
// markers que pode ser passado pra restoreSelection depois.
|
||||
saveSelection: () => {
|
||||
if (!jodit) return null;
|
||||
try { return jodit.selection.save(); }
|
||||
catch { return null; }
|
||||
},
|
||||
// Restaura selection a partir dos markers salvos. Re-foca o editor.
|
||||
restoreSelection: (markers) => {
|
||||
if (!jodit) return;
|
||||
try {
|
||||
jodit.focus();
|
||||
if (markers) jodit.selection.restore(markers);
|
||||
} catch { /* silencioso */ }
|
||||
},
|
||||
focus: () => jodit?.focus()
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -66,31 +66,43 @@ const editorRodape = ref(null)
|
||||
|
||||
function insertVariable(varKey) {
|
||||
const tag = `{{${varKey}}}`
|
||||
|
||||
// No mobile: 1) fecha drawer (imediato); 2) deferir append do form e
|
||||
// re-render do Jodit pra DEPOIS da transição (250ms). Modificar o form
|
||||
// durante a transição causa concorrência entre repaint do drawer
|
||||
// saindo + Jodit re-rendering com novo HTML → trava.
|
||||
if (isMobile.value) {
|
||||
drawerOpen.value = false;
|
||||
const field = cursorField.value;
|
||||
// setTimeout > duração da transição CSS (.dte-mobile-drawer = 250ms)
|
||||
setTimeout(() => {
|
||||
form.value[field] = (form.value[field] || '') + tag;
|
||||
if (!form.value.variaveis.includes(varKey)) {
|
||||
form.value.variaveis = [...form.value.variaveis, varKey];
|
||||
}
|
||||
}, 280);
|
||||
return;
|
||||
}
|
||||
|
||||
// Desktop: insertHTML mantém posição do cursor
|
||||
const editorMap = {
|
||||
cabecalho_html: editorCabecalho,
|
||||
corpo_html: editorCorpo,
|
||||
rodape_html: editorRodape
|
||||
}
|
||||
const editorRef = editorMap[cursorField.value]
|
||||
|
||||
// No mobile: fecha drawer + defere insertHTML pós-transição.
|
||||
// Restaura a selection capturada quando o drawer abriu (cursor
|
||||
// original do usuário) antes de inserir → variável aparece no
|
||||
// ponto certo do texto, não no final.
|
||||
if (isMobile.value) {
|
||||
drawerOpen.value = false;
|
||||
const markers = savedSelection.value;
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (markers && editorRef?.value?.restoreSelection) {
|
||||
editorRef.value.restoreSelection(markers);
|
||||
}
|
||||
if (editorRef?.value?.insertHTML) {
|
||||
editorRef.value.insertHTML(tag);
|
||||
} else {
|
||||
// Fallback se a API expose falhar
|
||||
form.value[cursorField.value] = (form.value[cursorField.value] || '') + tag;
|
||||
}
|
||||
} catch {
|
||||
form.value[cursorField.value] = (form.value[cursorField.value] || '') + tag;
|
||||
}
|
||||
if (!form.value.variaveis.includes(varKey)) {
|
||||
form.value.variaveis = [...form.value.variaveis, varKey];
|
||||
}
|
||||
savedSelection.value = null;
|
||||
}, 280);
|
||||
return;
|
||||
}
|
||||
|
||||
// Desktop: insertHTML mantém posição do cursor (foco já tá no editor)
|
||||
if (editorRef?.value?.insertHTML) {
|
||||
editorRef.value.insertHTML(tag)
|
||||
} else {
|
||||
@@ -119,11 +131,32 @@ function _onMqMobileChange(e) {
|
||||
isMobile.value = e.matches;
|
||||
if (!e.matches) drawerOpen.value = false;
|
||||
}
|
||||
// Selection salva do editor ativo no momento de abrir o drawer de
|
||||
// variáveis. Permite inserir na posição original do cursor mesmo
|
||||
// depois do user navegar pelo drawer/perder foco.
|
||||
const savedSelection = ref(null);
|
||||
|
||||
function openDrawer(tab) {
|
||||
drawerTab.value = tab || 'form';
|
||||
// Quando abre "Variáveis", salva selection do editor ativo agora
|
||||
// (cursor original do usuário) pra restaurar depois da inserção.
|
||||
if (tab === 'vars') {
|
||||
const editorMap = {
|
||||
cabecalho_html: editorCabecalho,
|
||||
corpo_html: editorCorpo,
|
||||
rodape_html: editorRodape
|
||||
};
|
||||
const editorRef = editorMap[cursorField.value];
|
||||
savedSelection.value = editorRef?.value?.saveSelection?.() || null;
|
||||
} else {
|
||||
savedSelection.value = null;
|
||||
}
|
||||
drawerOpen.value = true;
|
||||
}
|
||||
function fecharDrawer() { drawerOpen.value = false; }
|
||||
function fecharDrawer() {
|
||||
drawerOpen.value = false;
|
||||
savedSelection.value = null;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (typeof window !== 'undefined' && window.matchMedia) {
|
||||
|
||||
Reference in New Issue
Block a user