// ==UserScript== // @name staging notes v1 // @namespace http://tampermonkey.net/ // @version 1 // @description 暂存便签 // @author yeeel // @license MIT // @match *://*/* // @icon https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @downloadURL https://update.greasyfork.icu/scripts/533805/staging%20notes%20v1.user.js // @updateURL https://update.greasyfork.icu/scripts/533805/staging%20notes%20v1.meta.js // ==/UserScript== (function() { 'use strict'; // --- CSS with Container/Icon Box-Shadow Removed --- GM_addStyle(` /* --- Base Wrapper --- */ .goodnote-wrapper { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2000; /* Low z-index */ } /* --- Note Icon --- */ .note-icon { display: flex; align-items: center; justify-content: center; position: fixed; z-index: 2002; /* Low z-index */ pointer-events: auto; width: 24px; height: 24px; cursor: move; user-select: none; border-radius: 5px; background-color: rgba(255, 255, 255, 0.7); border: 1px solid rgba(200, 200, 200, 0.8); /* box-shadow: 0 2px 8px rgba(0,0,0,0.25); */ /* <-- REMOVED */ opacity: 0.9; backdrop-filter: blur(10px); transition: transform 0.15s ease, background-color 0.2s ease, opacity 0.2s ease; transform: translate3d(0, 0, 0); will-change: transform; } .note-icon svg { width: 18px; height: 18px; fill: #333; } .note-icon:hover { opacity: 1; background-color: rgba(255, 255, 255, 0.9); transform: scale(1.1); } .note-icon:active { cursor: grabbing; transform: scale(0.95); } /* --- Note Container --- */ .note-container { display: none; position: fixed; z-index: 2001; /* Low z-index */ pointer-events: auto; color: #333; min-width: 380px; padding: 12px; border-radius: 8px; background: rgba(255, 255, 255, 0.95); border: 1px solid #bbb; /* box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); */ /* <-- REMOVED */ backdrop-filter: blur(12px); /* NO Animation properties */ } .note-container.active { /* Only display:block handled by JS */ } /* --- Note Header --- */ .note-header { display: flex; align-items: center; justify-content: flex-start; margin-bottom: 10px; gap: 10px; user-select: none; padding-left: 2px; } /* --- Action Buttons --- */ .note-action-button, .pin-button { cursor: pointer; font-size: 20px; color: #555; padding: 3px; user-select: none; line-height: 1; transition: color 0.2s, transform 0.2s ease; } .note-action-button:hover, .pin-button:hover { color: #007aff; transform: scale(1.15); } .note-action-button:active, .pin-button:active { transform: scale(0.9); } .note-container.pinned .pin-button { color: #ff3b30; } .note-container.pinned .pin-button:hover { color: #ff6b6b; } /* --- Text Area --- */ .note-textarea { display: block; margin-bottom: 0 !important; background: #ffffff; color:#1c1c1e; min-height: 250px; min-width: 350px; height: 280px; width: 100%; border: 1px solid #d1d1d6; border-radius: 6px; padding: 12px; font-size: 15px; resize: both; overflow: auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; word-break: break-word; text-align: left; outline: none; box-sizing: border-box; -webkit-overflow-scrolling: touch; } .note-textarea:focus { outline: none; border-color: #007aff; box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2); } /* Keep textarea focus shadow */ .note-textarea a, .note-textarea a:visited { color: #007aff; text-decoration: underline; cursor: pointer; } .note-textarea a:hover { opacity: 0.7; } /* --- Selection Popup --- */ #goodnote-selection-popup { position: absolute; background-color: #007aff; color: white; border: none; border-radius: 5px; padding: 5px 10px; font-size: 13px; cursor: pointer; z-index: 2003; box-shadow: 0 2px 5px rgba(0,0,0,0.2); opacity: 0; transform: translateY(5px); pointer-events: none; white-space: nowrap; transition: opacity 0.2s ease, transform 0.2s ease; display: none; /* Start hidden, JS will set display:block */ } #goodnote-selection-popup.visible { opacity: 1; transform: translateY(0); pointer-events: auto; display: block !important; } /* Use class again, JS sets this */ /* --- Flash Message --- */ #goodnote-message { position: fixed; bottom: 25px; left: 50%; transform: translateX(-50%); padding: 10px 18px; border-radius: 6px; color: white; font-size: 14px; z-index: 2003; opacity: 0; transition: opacity 0.4s ease; pointer-events: none; text-align: center; background-color: rgba(40, 167, 69, 0.85); box-shadow: 0 3px 10px rgba(0,0,0,0.2); } #goodnote-message.error { background-color: rgba(220, 53, 69, 0.85); } #goodnote-message.visible { opacity: 1; } `); // --- Full JavaScript Code Below (Reverted Popup JS to use .visible class) --- // PASTE THE FULL JS CODE HERE (from Final v3/v4, make sure popup logic uses .visible class again) // ... // --- DOM元素创建 (Create DOM Elements) --- const wrapper = document.createElement('div'); wrapper.className = 'goodnote-wrapper'; if (document.body) { document.body.appendChild(wrapper); } else { document.addEventListener('DOMContentLoaded', () => document.body.appendChild(wrapper)); } const noteIcon = document.createElement('div'); noteIcon.className = 'note-icon'; noteIcon.title = '打开/关闭笔记 (Ctrl+Shift+M)'; noteIcon.innerHTML = ``; wrapper.appendChild(noteIcon); const noteContainer = document.createElement('div'); noteContainer.className = 'note-container'; wrapper.appendChild(noteContainer); const header = document.createElement('div'); header.className = 'note-header'; noteContainer.appendChild(header); const pinButton = document.createElement('span'); pinButton.className = 'pin-button'; pinButton.textContent = '📌'; pinButton.title = '置顶/取消置顶笔记'; header.appendChild(pinButton); const cutButton = document.createElement('span'); cutButton.className = 'note-action-button cut-button'; cutButton.textContent = '✂️'; cutButton.title = '剪切全部笔记内容 (Ctrl+Alt+P)'; header.appendChild(cutButton); const copyButton = document.createElement('span'); copyButton.className = 'note-action-button copy-button'; copyButton.textContent = '📄'; copyButton.title = '复制全部笔记内容'; header.appendChild(copyButton); const textarea = document.createElement('div'); textarea.className = 'note-textarea'; textarea.contentEditable = true; textarea.spellcheck = false; textarea.setAttribute('placeholder', '在这里输入你的笔记...'); noteContainer.appendChild(textarea); let selectionPopup = null; // --- 存储键 (Storage Keys) --- const storageKey = "goodnote_global_note_v3_final_v6"; // Use a new key const positionKey = "goodnote_global_position_v3_final_v6"; // --- 核心功能函数 (Core Functions) --- function linkify(text) { const urlRegex = /(https?:\/\/[^\s<>"'`]+)/g; return text.replace(urlRegex, (url) => { if (url.includes('')) return url; return `${url}`; }); } function saveNote() { const content = textarea.innerHTML; GM_setValue(storageKey, content); } function loadNote() { const savedNote = GM_getValue(storageKey, ''); if (textarea.innerHTML !== savedNote) textarea.innerHTML = savedNote; } function convertHtmlToPlainTextWithNewlines(html) { const tempDiv = document.createElement('div'); let processedHtml = html.replace(//gi, '\n'); tempDiv.innerHTML = processedHtml; let plainText = tempDiv.textContent || tempDiv.innerText || ""; return plainText.trim(); } // --- 事件监听 (Event Listeners) --- let saveTimeout; const SAVE_DELAY = 150; textarea.addEventListener('input', () => { clearTimeout(saveTimeout); saveTimeout = setTimeout(saveNote, SAVE_DELAY); }); textarea.addEventListener('paste', (e) => { e.preventDefault(); const text = e.clipboardData.getData('text/plain'); if (!text) return; const textWithBreaks = text.replace(/\r\n|\n/g, '
'); const linkedText = linkify(textWithBreaks); document.execCommand('insertHTML', false, linkedText); textarea.dispatchEvent(new Event('input', { bubbles: true, cancelable: true })); }); textarea.addEventListener('click', (e) => { if (e.target.tagName === 'A' && e.target.classList.contains('note-link')) { e.preventDefault(); window.open(e.target.href, '_blank', 'noopener,noreferrer'); } }); // --- Selection Handling (Using .visible class again) --- function removeSelectionPopup() { if (selectionPopup && selectionPopup.parentNode) { selectionPopup.classList.remove('visible'); // Allow animation to finish before removing setTimeout(() => { if (selectionPopup && selectionPopup.parentNode) { selectionPopup.parentNode.removeChild(selectionPopup); } selectionPopup = null; }, 250); // Match CSS transition duration } // Ensure variable is nulled even if removal is delayed if(selectionPopup && !selectionPopup.classList.contains('visible')) { selectionPopup = null; } } document.addEventListener('mouseup', (e) => { // console.log("Mouse Up Detected"); // Keep debug logs if needed if (noteContainer.contains(e.target) || noteIcon.contains(e.target) || (selectionPopup && selectionPopup.contains(e.target))) { // console.log("Mouse Up ignored (inside component)"); return; } setTimeout(() => { const selection = window.getSelection(); if (!selection || selection.rangeCount === 0 || selection.isCollapsed) { // console.log("No selection or collapsed, removing popup"); removeSelectionPopup(); return; } const selectedText = selection.toString().trim(); // console.log("Selected Text:", selectedText); removeSelectionPopup(); // Remove any existing first if (selectedText.length > 0) { const range = selection.getRangeAt(0); if (textarea.contains(range.commonAncestorContainer)) { // console.log("Selection inside textarea, ignored"); return; } const rect = range.getBoundingClientRect(); if (rect.width === 0 && rect.height === 0 && selectedText.length < 5) { // console.log("Selection too small or invisible, ignored"); return; } // console.log("Creating Selection Popup"); selectionPopup = document.createElement('button'); selectionPopup.id = 'goodnote-selection-popup'; selectionPopup.textContent = '➕'; // Ensure it starts hidden if CSS relies on opacity/transform selectionPopup.style.display = 'none'; // Explicitly hide initially document.body.appendChild(selectionPopup); // Calculate position let popupTop = window.pageYOffset + rect.bottom + 8; let popupLeft = window.pageXOffset + rect.left + (rect.width / 2) - (selectionPopup.offsetWidth / 2); const popupWidth = selectionPopup.offsetWidth; const popupHeight = selectionPopup.offsetHeight; if (popupLeft + popupWidth > window.innerWidth - 10) popupLeft = window.innerWidth - popupWidth - 10; if (popupTop + popupHeight > window.innerHeight + window.pageYOffset - 10) popupTop = window.pageYOffset + rect.top - popupHeight - 8; popupLeft = Math.max(10 + window.pageXOffset, popupLeft); popupTop = Math.max(10 + window.pageYOffset, popupTop); // console.log("Popup Position:", {top: popupTop, left: popupLeft}); selectionPopup.style.top = `${popupTop}px`; selectionPopup.style.left = `${popupLeft}px`; selectionPopup.style.display = ''; // Clear display style override // --- Use .visible class to trigger CSS animation --- // console.log("Adding .visible class to popup"); requestAnimationFrame(() => { // Ensure element is ready for transition selectionPopup.classList.add('visible'); }); // --- END CHANGE --- selectionPopup.addEventListener('click', function handleAddClick(event) { event.stopPropagation(); // console.log("Add to Note Clicked"); const currentContent = textarea.innerHTML.trim(); const textToAdd = selectedText.replace(/\r\n|\n/g, '
'); const linkedText = linkify(textToAdd); textarea.innerHTML += (currentContent ? '

' : '') + linkedText; saveNote(); removeSelectionPopup(); window.getSelection().removeAllRanges(); flashMessage("已添加到笔记"); }); } else { // console.log("Selected text is empty after trim"); } }, 100); }); document.addEventListener('mousedown', (e) => { if (selectionPopup && !selectionPopup.contains(e.target)) { /* console.log("Mousedown outside popup, removing"); */ removeSelectionPopup(); } }); // --- UI Action Buttons & Flash Message --- let messageTimeout; function flashMessage(message, isError = false) { let msgDiv = document.getElementById('goodnote-message'); if (!msgDiv) { msgDiv = document.createElement('div'); msgDiv.id = 'goodnote-message'; if (document.body) document.body.appendChild(msgDiv); else document.addEventListener('DOMContentLoaded', () => document.body.appendChild(msgDiv)); } msgDiv.textContent = message; msgDiv.classList.toggle('error', isError); msgDiv.classList.add('visible'); clearTimeout(messageTimeout); messageTimeout = setTimeout(() => { if (msgDiv) msgDiv.classList.remove('visible'); }, 2500); } copyButton.addEventListener('click', (e) => { e.stopPropagation(); const htmlContent = textarea.innerHTML; const textToCopy = convertHtmlToPlainTextWithNewlines(htmlContent); if (textToCopy) { navigator.clipboard.writeText(textToCopy).then(() => flashMessage("笔记已复制!")).catch(err => { console.error('GoodNote: 复制失败', err); flashMessage("复制失败", true); }); } else { flashMessage("笔记为空", true); } }); cutButton.addEventListener('click', (e) => { e.stopPropagation(); performCutNoteAction(); }); // --- Drag Logic --- let isDragging = false; let dragOffsetX, dragOffsetY; function dragStart(e) { if (e.button === 0 && (e.target === noteIcon || noteIcon.contains(e.target))) { isDragging = true; const rect = noteIcon.getBoundingClientRect(); dragOffsetX = e.clientX - rect.left; dragOffsetY = e.clientY - rect.top; noteIcon.style.cursor = 'grabbing'; noteIcon.style.transition = 'none'; e.preventDefault(); } } function drag(e) { if (isDragging) { let newX = e.clientX - dragOffsetX; let newY = e.clientY - dragOffsetY; const iconWidth = noteIcon.offsetWidth; const iconHeight = noteIcon.offsetHeight; newX = Math.max(0, Math.min(newX, window.innerWidth - iconWidth)); newY = Math.max(0, Math.min(newY, window.innerHeight - iconHeight)); noteIcon.style.left = `${newX}px`; noteIcon.style.top = `${newY}px`; noteIcon.style.right = ''; noteIcon.style.bottom = ''; } } function dragEnd(e) { if (isDragging) { isDragging = false; noteIcon.style.cursor = 'move'; noteIcon.style.transition = 'transform 0.15s ease, background-color 0.2s ease, opacity 0.2s ease'; GM_setValue(positionKey, { top: noteIcon.style.top, left: noteIcon.style.left }); } } noteIcon.addEventListener('mousedown', dragStart); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', dragEnd); // --- Load Icon Position --- function loadIconPosition() { const savedPosition = GM_getValue(positionKey, null); if (savedPosition && typeof savedPosition.left === 'string' && typeof savedPosition.top === 'string') { noteIcon.style.left = savedPosition.left; noteIcon.style.top = savedPosition.top; noteIcon.style.right = ''; noteIcon.style.bottom = ''; } else { setDefaultIconPosition(); if (savedPosition) GM_setValue(positionKey, null); } } function setDefaultIconPosition() { noteIcon.style.top = '20px'; noteIcon.style.right = '20px'; noteIcon.style.left = ''; noteIcon.style.bottom = ''; } // --- Note Visibility Logic --- let isVisible = false; let isPinned = false; let hoverTimeout; pinButton.addEventListener('click', (e) => { e.stopPropagation(); isPinned = !isPinned; noteContainer.classList.toggle('pinned', isPinned); pinButton.title = isPinned ? '取消置顶笔记' : '置顶笔记'; if (isPinned) { flashMessage("笔记已置顶"); if (!isVisible) toggleNote(true); clearTimeout(hoverTimeout); } else { flashMessage("笔记已取消置顶"); handleMouseLeave(); } }); // --- Action Functions (Cut/Paste) --- async function performCutNoteAction() { const htmlContent = textarea.innerHTML; const textToCopy = convertHtmlToPlainTextWithNewlines(htmlContent); if (textToCopy) { try { await navigator.clipboard.writeText(textToCopy); textarea.innerHTML = ''; saveNote(); flashMessage("笔记已剪切!"); return true; } catch (err) { console.error('GoodNote: 剪切失败', err); flashMessage("剪切失败", true); return false; } } else { flashMessage("笔记为空", true); return false; } } async function performPasteAction() { const activeElement = document.activeElement; const isEditable = activeElement && (activeElement.isContentEditable || activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'); if (isEditable) { try { const text = await navigator.clipboard.readText(); if (!text) { flashMessage("剪贴板为空", true); return false; } if (activeElement.isContentEditable) { document.execCommand('insertText', false, text); if (activeElement === textarea) textarea.dispatchEvent(new Event('input', { bubbles: true, cancelable: true })); } else { const start = activeElement.selectionStart; const end = activeElement.selectionEnd; const originalValue = activeElement.value; activeElement.value = originalValue.substring(0, start) + text + originalValue.substring(end); const newCursorPos = start + text.length; activeElement.selectionStart = newCursorPos; activeElement.selectionEnd = newCursorPos; activeElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true })); } return true; } catch (err) { if (err.name === 'NotAllowedError') flashMessage('需要剪贴板读取权限', true); else { console.error('GoodNote: 粘贴失败', err); flashMessage('粘贴失败', true); } return false; } } else { flashMessage("当前光标位置不可粘贴", true); return false; } } // --- Keyboard Shortcuts --- document.addEventListener('keydown', async (e) => { if (e.ctrlKey && e.altKey && e.key && e.key.toLowerCase() === 'p') { e.preventDefault(); performCutNoteAction(); return; } if (e.ctrlKey && e.altKey && e.key && e.key.toLowerCase() === 'o') { e.preventDefault(); performPasteAction(); return; } if (e.ctrlKey && e.altKey && e.key && e.key.toLowerCase() === 'v') { e.preventDefault(); try { const cutSuccess = await performCutNoteAction(); if (cutSuccess) await performPasteAction(); } catch (error) { console.error("GoodNote: Ctrl+Alt+V 操作失败:", error); flashMessage("剪切粘贴操作失败", true); } return; } if (e.key === 'Escape' && isVisible && !isPinned) { if (textarea.contains(document.activeElement)) { toggleNote(); e.preventDefault(); return; } const targetTagName = e.target.tagName; const isInputFocused = e.target.isContentEditable || ['INPUT', 'TEXTAREA', 'SELECT'].includes(targetTagName); if (!isInputFocused && !selectionPopup) { toggleNote(); e.preventDefault(); return; } } const targetTagNameGlobal = e.target.tagName; if (!e.target.isContentEditable && !['INPUT', 'TEXTAREA', 'SELECT'].includes(targetTagNameGlobal)) { const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform); if ((isMac ? e.metaKey : e.ctrlKey) && e.shiftKey && e.key && e.key.toLowerCase() === 'm') { e.preventDefault(); toggleNote(); return; } } }); // --- Icon Click/Hover/Leave Logic --- noteIcon.addEventListener('click', (e) => { if (!isDragging && !isTouchDragging) toggleNote(); }); noteIcon.addEventListener('mouseenter', () => { clearTimeout(hoverTimeout); if (!isDragging && !isTouchDragging && !isVisible && !isPinned) toggleNote(true); }); function handleMouseLeave() { clearTimeout(hoverTimeout); if (isVisible && !isPinned) { hoverTimeout = setTimeout(() => { const activeElement = document.activeElement; if (!isVisible || isPinned || noteContainer.contains(activeElement)) return; if (!noteIcon.matches(':hover') && !noteContainer.matches(':hover')) toggleNote(); }, 600); } } noteIcon.addEventListener('mouseleave', handleMouseLeave); noteContainer.addEventListener('mouseleave', handleMouseLeave); noteContainer.addEventListener('mouseenter', () => clearTimeout(hoverTimeout)); document.addEventListener('click', (e) => { if (isVisible && !isPinned && !noteContainer.contains(e.target) && !noteIcon.contains(e.target) && (!selectionPopup || !selectionPopup.contains(e.target))) { clearTimeout(hoverTimeout); toggleNote(); } }, true); // --- Touch Drag Logic --- let touchStartX, touchStartY, touchInitialX, touchInitialY; let isTouchDragging = false; let touchStartTime = 0; let touchMoveDistance = 0; let touchHasDragged = false; noteIcon.addEventListener('touchstart', (e) => { if (e.touches.length === 1) { const touch = e.touches[0]; isTouchDragging = true; isDragging = false; touchHasDragged = false; const rect = noteIcon.getBoundingClientRect(); touchStartX = touch.clientX; touchStartY = touch.clientY; touchInitialX = rect.left; touchInitialY = rect.top; touchStartTime = Date.now(); touchMoveDistance = 0; noteIcon.style.transition = 'none'; } }, { passive: true }); noteIcon.addEventListener('touchmove', (e) => { if (!isTouchDragging || e.touches.length !== 1) return; const touch = e.touches[0]; const dx = touch.clientX - touchStartX; const dy = touch.clientY - touchStartY; touchMoveDistance = Math.sqrt(dx * dx + dy * dy); if (touchMoveDistance > 10) { touchHasDragged = true; let newX = touchInitialX + dx; let newY = touchInitialY + dy; const iconWidth = noteIcon.offsetWidth; const iconHeight = noteIcon.offsetHeight; newX = Math.max(0, Math.min(newX, window.innerWidth - iconWidth)); newY = Math.max(0, Math.min(newY, window.innerHeight - iconHeight)); noteIcon.style.left = `${newX}px`; noteIcon.style.top = `${newY}px`; noteIcon.style.right = ''; noteIcon.style.bottom = ''; if (e.cancelable) e.preventDefault(); } }, { passive: false }); noteIcon.addEventListener('touchend', (e) => { if (!isTouchDragging) return; noteIcon.style.transition = 'transform 0.15s ease, background-color 0.2s ease, opacity 0.2s ease'; const duration = Date.now() - touchStartTime; if (touchHasDragged) { GM_setValue(positionKey, { top: noteIcon.style.top, left: noteIcon.style.left }); } else if (duration < 300) toggleNote(); isTouchDragging = false; touchHasDragged = false; }); // --- Polling Sync Logic --- let pollingInterval = null; const POLLING_INTERVAL_MS = 800; function checkAndUpdateNoteViaPolling() { if (document.activeElement !== textarea) { const storedNote = GM_getValue(storageKey, ''); if (textarea.innerHTML !== storedNote) textarea.innerHTML = storedNote; } } function startPolling() { if (pollingInterval === null && !isVisible) { checkAndUpdateNoteViaPolling(); pollingInterval = setInterval(checkAndUpdateNoteViaPolling, POLLING_INTERVAL_MS); } } function stopPolling() { if (pollingInterval !== null) { clearInterval(pollingInterval); pollingInterval = null; } } // --- Modified toggleNote (No container animation at all) --- function toggleNote(forceOpen = false) { const shouldBeVisible = forceOpen || !isVisible; if (shouldBeVisible) { // Opening if (isVisible && !forceOpen) return; stopPolling(); const storedNoteBeforeShow = GM_getValue(storageKey, ''); if (textarea.innerHTML !== storedNoteBeforeShow) textarea.innerHTML = storedNoteBeforeShow; const iconRect = noteIcon.getBoundingClientRect(); const padding = 15; const containerStyle = getComputedStyle(noteContainer); const containerMinWidth = parseInt(containerStyle.minWidth) || 380; const containerMinHeight = 300; let left = iconRect.right + padding; let top = Math.max(padding, iconRect.top); if (left + containerMinWidth > window.innerWidth - padding) left = iconRect.left - containerMinWidth - padding; left = Math.max(padding, left); const estimatedHeight = Math.max(containerMinHeight, noteContainer.offsetHeight); if (top + estimatedHeight > window.innerHeight - padding) top = window.innerHeight - estimatedHeight - padding; top = Math.max(padding, top); noteContainer.style.top = `${top}px`; noteContainer.style.left = `${left}px`; noteContainer.style.display = 'block'; noteContainer.classList.add('active'); setTimeout(() => { if (!selectionPopup && noteContainer.classList.contains('active')) { textarea.focus(); try { const range = document.createRange(); const sel = window.getSelection(); range.selectNodeContents(textarea); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); } catch(e) { console.warn("GoodNote: Setting cursor position failed.", e); } } }, 50); isVisible = true; } else { // Closing if (!isVisible || isPinned) return; noteContainer.style.display = 'none'; noteContainer.classList.remove('active'); isVisible = false; startPolling(); } } // --- Initialization --- console.log("GoodNote Final v6 Initializing..."); loadNote(); loadIconPosition(); startPolling(); })(); // --- END OF SCRIPT ---