mirror of
https://github.com/gabriele-cusato/HandTranscriptMd.git
synced 2026-07-22 06:14:06 +00:00
agginti ulteriori fix per controllo obsidian
This commit is contained in:
parent
bcc689411b
commit
b42451f65a
14 changed files with 44 additions and 26 deletions
|
|
@ -58,8 +58,8 @@ export function registerEmbed(plugin: HandwritingPlugin) {
|
|||
// Legge dimensioni reali dal viewBox per preservare l'altezza raggiunta con auto-expand.
|
||||
// Usare plugin.settings.canvasHeight causerebbe il "collasso" degli SVG cresciuti.
|
||||
const dimMatch = content.match(/viewBox="0 0 (\d+) (\d+)"/);
|
||||
const svgWidth = dimMatch ? parseInt(dimMatch[1]!) : plugin.settings.canvasWidth;
|
||||
const svgHeight = dimMatch ? parseInt(dimMatch[2]!) : plugin.settings.canvasHeight;
|
||||
const svgWidth = dimMatch ? parseInt(dimMatch[1]) : plugin.settings.canvasWidth;
|
||||
const svgHeight = dimMatch ? parseInt(dimMatch[2]) : plugin.settings.canvasHeight;
|
||||
const newSvg = strokesToSvg(
|
||||
remapped,
|
||||
svgWidth,
|
||||
|
|
@ -72,9 +72,9 @@ export function registerEmbed(plugin: HandwritingPlugin) {
|
|||
plugin.refreshPreview(embedId, newSvg);
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- async listener stored in a Set that expects void; Promise result intentionally ignored
|
||||
plugin.bgModeListeners.add(onBgModeRemap);
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- same reason: async callback passed to plugin.register cleanup
|
||||
plugin.register(() => plugin.bgModeListeners.delete(onBgModeRemap));
|
||||
|
||||
// --- NUOVO: MutationObserver su document.body ---
|
||||
|
|
@ -147,18 +147,15 @@ function setupMutationObserver(plugin: HandwritingPlugin) {
|
|||
// Aggiorna l'altezza del wrapper (se espanso) dopo ogni refresh dell'img.
|
||||
// Su Android, CM6 Live Preview non rileva i cambi organici di altezza.
|
||||
const syncWrapperHeight = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
const wrapper = span.querySelector('.hwm_clip-wrapper') as HTMLElement | null;
|
||||
const wrapper = span.querySelector<HTMLElement>('.hwm_clip-wrapper');
|
||||
if (!wrapper || wrapper.classList.contains('hwm_overflow-hidden')) return;
|
||||
const newH = wrapper.scrollHeight;
|
||||
// eslint-disable-next-line obsidianmd/no-static-styles-assignment
|
||||
wrapper.style.transition = 'none';
|
||||
wrapper.style.height = newH + 'px';
|
||||
// Disable transition temporarily so the height sync is instant (no visual flash).
|
||||
wrapper.classList.add('hwm_no-transition');
|
||||
wrapper.style.setProperty('height', newH + 'px');
|
||||
requestAnimationFrame(() => {
|
||||
// eslint-disable-next-line obsidianmd/no-static-styles-assignment
|
||||
wrapper.style.height = '';
|
||||
// eslint-disable-next-line obsidianmd/no-static-styles-assignment
|
||||
wrapper.style.transition = '';
|
||||
wrapper.style.removeProperty('height');
|
||||
wrapper.classList.remove('hwm_no-transition');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -691,8 +688,7 @@ function createPortalPanel(
|
|||
// Animiamo il wrapper (non il container span) così il ResizeObserver
|
||||
// di Obsidian Mobile non si attiva sul container e non re-imposta le dimensioni dell'img.
|
||||
const ensureWrapper = (): HTMLElement | null => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
let wrapper = container.querySelector('.hwm_clip-wrapper') as HTMLElement | null;
|
||||
let wrapper = container.querySelector<HTMLElement>('.hwm_clip-wrapper');
|
||||
if (wrapper) return wrapper;
|
||||
const img = container.querySelector('img');
|
||||
if (!img || !img.parentElement) return null;
|
||||
|
|
@ -710,15 +706,14 @@ function createPortalPanel(
|
|||
const wrapper = ensureWrapper();
|
||||
if (wrapper) {
|
||||
// Anima da altezza corrente (px) → altezza piena (scrollHeight).
|
||||
wrapper.style.height = wrapper.scrollHeight + 'px';
|
||||
wrapper.style.setProperty('height', wrapper.scrollHeight + 'px');
|
||||
// Cleanup: rimuove altezza fissa e overflow al termine dell'animazione.
|
||||
// Su Android WebView transitionend non è affidabile → setTimeout fallback.
|
||||
let done = false;
|
||||
const cleanup = () => {
|
||||
if (done) return;
|
||||
done = true;
|
||||
// eslint-disable-next-line obsidianmd/no-static-styles-assignment
|
||||
wrapper.style.height = '';
|
||||
wrapper.style.removeProperty('height');
|
||||
wrapper.classList.remove('hwm_overflow-hidden');
|
||||
};
|
||||
wrapper.addEventListener('transitionend', cleanup, { once: true });
|
||||
|
|
@ -748,7 +743,7 @@ function createPortalPanel(
|
|||
wrapper.classList.add('hwm_overflow-hidden');
|
||||
if (startH <= naturalH) {
|
||||
// SVG non espanso: altezza già nella norma, nessuna area vuota da tagliare.
|
||||
wrapper.style.height = startH + 'px';
|
||||
wrapper.style.setProperty('height', startH + 'px');
|
||||
} else {
|
||||
// SVG auto-espanso: anima da startH → naturalH per nascondere l'area vuota.
|
||||
// WAAPI garantisce keyframe px→px senza dipendere da height:auto come "from".
|
||||
|
|
@ -757,7 +752,7 @@ function createPortalPanel(
|
|||
{ duration: 300, easing: 'ease', fill: 'forwards' }
|
||||
);
|
||||
anim.onfinish = () => {
|
||||
wrapper.style.height = naturalH + 'px';
|
||||
wrapper.style.setProperty('height', naturalH + 'px');
|
||||
anim.cancel(); // cede il controllo all'inline style
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Erforderlich für die OCR-Handschrifterkennung. Erhalten Sie ihn von Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "OCR-Sprachen",
|
||||
"ocr_langs_desc": "Kommagetrennte BCP-47-Sprachcodes (z. B. \"it, en, fr\"). Wird vom KI-Modell für OCR verwendet.",
|
||||
"gemini_key_placeholder": "API-Schlüssel eingeben",
|
||||
"ocr_langs_placeholder": "z. B. it, en, fr",
|
||||
"debug_mode_name": "Debug-Modus",
|
||||
"debug_mode_desc": "Echtzeit-Benachrichtigungen für IME/Touch-Ereignisse anzeigen (nützlich zur Diagnose von Android-Problemen).",
|
||||
"keywords_summary": "Vom OCR-Parser erkannte Schlüsselwörter",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
"gemini_key_desc": "Required for handwriting OCR recognition. Get it from Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "OCR languages",
|
||||
"ocr_langs_desc": "Comma-separated BCP-47 language codes (e.g. \"it, en, fr\"). Used by the AI model for OCR.",
|
||||
"gemini_key_placeholder": "Enter API key",
|
||||
"ocr_langs_placeholder": "e.g. it, en, fr",
|
||||
"debug_mode_name": "Debug mode",
|
||||
"debug_mode_desc": "Show real-time notifications for IME/touch events (useful for diagnosing issues on Android).",
|
||||
"keywords_summary": "Keywords recognized by the OCR parser",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Necesaria para el reconocimiento OCR de escritura a mano. Obténgala en Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Idiomas OCR",
|
||||
"ocr_langs_desc": "Códigos de idioma BCP-47 separados por comas (p. ej. \"it, en, fr\"). Usados por el modelo de IA para el OCR.",
|
||||
"gemini_key_placeholder": "Introduce la clave API",
|
||||
"ocr_langs_placeholder": "p. ej. it, en, fr",
|
||||
"debug_mode_name": "Modo depuración",
|
||||
"debug_mode_desc": "Muestra notificaciones en tiempo real para eventos IME/táctil (útil para diagnosticar problemas en Android).",
|
||||
"keywords_summary": "Palabras clave reconocidas por el parser OCR",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Nécessaire pour la reconnaissance OCR de l'écriture manuscrite. Obtenez-la sur Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Langues OCR",
|
||||
"ocr_langs_desc": "Codes de langue BCP-47 séparés par des virgules (ex. : \"it, en, fr\"). Utilisés par le modèle IA pour l'OCR.",
|
||||
"gemini_key_placeholder": "Saisir la clé API",
|
||||
"ocr_langs_placeholder": "ex. it, en, fr",
|
||||
"debug_mode_name": "Mode débogage",
|
||||
"debug_mode_desc": "Affiche des notifications en temps réel pour les événements IME/tactile (utile pour diagnostiquer les problèmes sur Android).",
|
||||
"keywords_summary": "Mots-clés reconnus par le parser OCR",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
"gemini_key_desc": "Necessaria per il riconoscimento OCR della scrittura a mano. Ottienila da Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Lingue OCR",
|
||||
"ocr_langs_desc": "Codici lingua BCP-47 separati da virgola (es. \"it, en, fr\"). Usati dal modello AI per utilizzare l'OCR.",
|
||||
"gemini_key_placeholder": "Inserisci la chiave API",
|
||||
"ocr_langs_placeholder": "es. it, en, fr",
|
||||
"debug_mode_name": "Modalità debug",
|
||||
"debug_mode_desc": "Mostra notifiche in tempo reale per eventi IME/touch (utile per diagnosticare problemi su Android).",
|
||||
"keywords_summary": "Keyword riconosciute dal parser OCR",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "手書きOCR認識に必要です。Google AI Studio(aistudio.google.com)から取得してください。",
|
||||
"ocr_langs_name": "OCR言語",
|
||||
"ocr_langs_desc": "カンマ区切りのBCP-47言語コード(例:「it, en, fr」)。AIモデルのOCRに使用されます。",
|
||||
"gemini_key_placeholder": "APIキーを入力",
|
||||
"ocr_langs_placeholder": "例:it, en, fr",
|
||||
"debug_mode_name": "デバッグモード",
|
||||
"debug_mode_desc": "IME/タッチイベントのリアルタイム通知を表示します(Androidの問題診断に役立ちます)。",
|
||||
"keywords_summary": "OCRパーサーが認識するキーワード",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Wymagany do rozpoznawania OCR pisma odręcznego. Uzyskaj go w Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Języki OCR",
|
||||
"ocr_langs_desc": "Kody języków BCP-47 oddzielone przecinkami (np. \"it, en, fr\"). Używane przez model AI do OCR.",
|
||||
"gemini_key_placeholder": "Wprowadź klucz API",
|
||||
"ocr_langs_placeholder": "np. it, en, fr",
|
||||
"debug_mode_name": "Tryb debugowania",
|
||||
"debug_mode_desc": "Pokazuje powiadomienia w czasie rzeczywistym dla zdarzeń IME/dotyk (przydatne do diagnozowania problemów na Androidzie).",
|
||||
"keywords_summary": "Słowa kluczowe rozpoznawane przez parser OCR",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Necessária para o reconhecimento OCR de manuscrito. Obtenha no Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Idiomas OCR",
|
||||
"ocr_langs_desc": "Códigos de idioma BCP-47 separados por vírgula (ex: \"it, en, fr\"). Usados pelo modelo de IA para OCR.",
|
||||
"gemini_key_placeholder": "Insira a chave de API",
|
||||
"ocr_langs_placeholder": "ex.: it, en, fr",
|
||||
"debug_mode_name": "Modo debug",
|
||||
"debug_mode_desc": "Mostra notificações em tempo real para eventos IME/toque (útil para diagnosticar problemas no Android).",
|
||||
"keywords_summary": "Palavras-chave reconhecidas pelo parser OCR",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "Необходим для OCR-распознавания рукописного текста. Получите в Google AI Studio (aistudio.google.com).",
|
||||
"ocr_langs_name": "Языки OCR",
|
||||
"ocr_langs_desc": "Коды языков BCP-47, разделённые запятой (например \"it, en, fr\"). Используются моделью ИИ для OCR.",
|
||||
"gemini_key_placeholder": "Введите API-ключ",
|
||||
"ocr_langs_placeholder": "напр. it, en, fr",
|
||||
"debug_mode_name": "Режим отладки",
|
||||
"debug_mode_desc": "Показывать уведомления в реальном времени для событий IME/касания (полезно для диагностики проблем на Android).",
|
||||
"keywords_summary": "Ключевые слова, распознаваемые парсером OCR",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"gemini_key_desc": "手写OCR识别所需。从Google AI Studio (aistudio.google.com)获取。",
|
||||
"ocr_langs_name": "OCR语言",
|
||||
"ocr_langs_desc": "逗号分隔的BCP-47语言代码(例如\"it, en, fr\")。用于AI模型的OCR识别。",
|
||||
"gemini_key_placeholder": "输入API密钥",
|
||||
"ocr_langs_placeholder": "例如:it, en, fr",
|
||||
"debug_mode_name": "调试模式",
|
||||
"debug_mode_desc": "显示IME/触摸事件的实时通知(用于诊断Android问题)。",
|
||||
"keywords_summary": "OCR解析器识别的关键词",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
export function normalizeMarkdownSymbols(rawText: string): string {
|
||||
// Rimuove BOM e caratteri zero-width Unicode che Gemini inserisce all'inizio
|
||||
// del testo o all'inizio di righe (U+FEFF, U+200B, U+200C, U+200D, U+2060)
|
||||
// eslint-disable-next-line no-misleading-character-class
|
||||
// eslint-disable-next-line no-misleading-character-class -- intentional: each codepoint in this class is a distinct zero-width character, not a combining sequence
|
||||
const cleaned = rawText.replace(/[\uFEFF\u200B\u200C\u200D\u2060]/gu, '');
|
||||
|
||||
const lines = cleaned.split('\n');
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export class HandwritingSettingTab extends PluginSettingTab {
|
|||
// Prima voce: automatico
|
||||
drop.addOption('auto', t('ui_language_auto'));
|
||||
// Una voce per ogni lingua disponibile nel plugin, con nome nativo
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- forEach callback is sync but DropdownComponent.addOption return type triggers the rule; Promise result intentionally ignored
|
||||
availableLocales().forEach(code => drop.addOption(code, localeNames[code] ?? code));
|
||||
drop.setValue(this.plugin.settings.uiLanguage);
|
||||
drop.onChange((value) => { void (async () => {
|
||||
|
|
@ -195,8 +195,7 @@ export class HandwritingSettingTab extends PluginSettingTab {
|
|||
.setDesc(t('gemini_key_desc'))
|
||||
.addText(text => {
|
||||
text
|
||||
// eslint-disable-next-line obsidianmd/ui/sentence-case
|
||||
.setPlaceholder('AIza...')
|
||||
.setPlaceholder(t('gemini_key_placeholder'))
|
||||
.setValue(this.plugin.settings.geminiApiKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.geminiApiKey = value.trim();
|
||||
|
|
@ -213,8 +212,7 @@ export class HandwritingSettingTab extends PluginSettingTab {
|
|||
.addText(text => text
|
||||
// Mostra l'array come stringa "it, en"
|
||||
.setValue(this.plugin.settings.ocrLanguages.join(', '))
|
||||
// eslint-disable-next-line obsidianmd/ui/sentence-case
|
||||
.setPlaceholder('it, en')
|
||||
.setPlaceholder(t('ocr_langs_placeholder'))
|
||||
.onChange(async (value) => {
|
||||
// Parsa la stringa in array, rimuovendo spazi e voci vuote
|
||||
const langs = value
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Disabilita transizioni CSS temporaneamente (usato in syncWrapperHeight) */
|
||||
.hwm_no-transition {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
/* Animazione altezza del wrapper clip (collapse/expand nuovo formato) */
|
||||
.hwm_clip-wrapper {
|
||||
transition: height 0.3s ease;
|
||||
|
|
|
|||
Loading…
Reference in a new issue