diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/assets/icon-128.png b/assets/icon-128.png new file mode 100644 index 0000000..8dc789d Binary files /dev/null and b/assets/icon-128.png differ diff --git a/assets/icon-16.png b/assets/icon-16.png new file mode 100644 index 0000000..696e6a2 Binary files /dev/null and b/assets/icon-16.png differ diff --git a/assets/icon-32.png b/assets/icon-32.png new file mode 100644 index 0000000..9c85987 Binary files /dev/null and b/assets/icon-32.png differ diff --git a/assets/icon-48.png b/assets/icon-48.png new file mode 100644 index 0000000..baf945b Binary files /dev/null and b/assets/icon-48.png differ diff --git a/background.js b/background.js index 6c860f8..9b16f2f 100644 --- a/background.js +++ b/background.js @@ -1,6 +1,9 @@ // Let Chrome open the panel when the toolbar icon is clicked +// Guard: some Chromium variants may not expose sidePanel +const hasSidePanel = !!chrome.sidePanel?.setOptions; + chrome.runtime.onInstalled.addListener(() => { - chrome.sidePanel?.setPanelBehavior?.({ openPanelOnActionClick: true }); + if (hasSidePanel) chrome.sidePanel.setPanelBehavior?.({ openPanelOnActionClick: true }); }); // If you still want to ensure the correct path on click, setOptions ONLY: @@ -19,7 +22,8 @@ chrome.action.onClicked.addListener(async () => { try { await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['content.js'] }); } catch {} } - await chrome.sidePanel.setOptions({ tabId: tab.id, path: "panel.html" }); // Chrome opens it + await chrome.sidePanel.setOptions({ tabId: tab.id, path: "panel.html" }); + try { await chrome.sidePanel.open({ tabId: tab.id }); } catch {} }); // Keyboard shortcut: we do open() here (this is a user gesture) diff --git a/content.js b/content.js index c42890b..c451314 100644 --- a/content.js +++ b/content.js @@ -6,6 +6,16 @@ if (window.__dewemoji_cs_installed) { window.__dewemoji_cs_installed = true; // (keep the rest of your file below as-is) + // Throttle to animation frame to avoid excessive work on rapid events + function rafThrottle(fn){ + let scheduled = false; + return function(...args){ + if (scheduled) return; + scheduled = true; + requestAnimationFrame(() => { scheduled = false; fn.apply(this,args); }); + }; + } + let lastEditable = null; // HTMLElement (input/textarea/contenteditable root) let lastRange = null; // Range for contenteditable let lastStart = 0, lastEnd = 0; @@ -59,10 +69,17 @@ if (window.__dewemoji_cs_installed) { captureCaret(); + // Use a non-throttled handler for focusin so we snapshot *before* focus leaves to the side panel. document.addEventListener('focusin', captureCaret, true); - document.addEventListener('keyup', captureCaret, true); - document.addEventListener('mouseup', captureCaret, true); - document.addEventListener('selectionchange', captureCaret, true); + + // Throttled handlers for noisy updates + const captureCaretThrottled = rafThrottle(captureCaret); + document.addEventListener('keyup', captureCaretThrottled, true); + document.addEventListener('mouseup', captureCaretThrottled, true); + document.addEventListener('selectionchange', captureCaretThrottled, true); + + // Extra safety: when the page is about to hide (e.g., side panel opens), keep the last known caret + document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') captureCaret(); }, true); // Attempt to insert text at the last saved position function insertAtCaret(text) { diff --git a/manifest.json b/manifest.json index 6390921..9c6e1d1 100644 --- a/manifest.json +++ b/manifest.json @@ -1,41 +1,65 @@ { - "name": "Dewemoji - Emojis Made Effortless", - "description": "Search emojis and insert into any text field.", - "version": "1.0.0", - "manifest_version": 3, - - "permissions": ["storage", "scripting", "activeTab", "sidePanel", "identity", "identity.email"], - - "side_panel": { - "default_path": "panel.html" - }, + "name": "Dewemoji - Emojis Made Effortless", + "description": "Find and copy emojis instantly. Optional Pro license unlocks tone lock, insert mode, and more.", + "version": "1.0.0", + "offline_enabled": false, + "permissions": [ + "storage", + "scripting", + "activeTab", + "sidePanel" + ], + "host_permissions": [ + "", + "https://api.dewemoji.com/*" + ], + "web_accessible_resources": [ + { + "resources": [ + "assets/*.png", + "assets/*.svg", + "styles.css" + ], + "matches": [""] + } + ], + "homepage_url": "https://dewemoji.com", + "manifest_version": 3, - "host_permissions": [""], - - "action": { - "default_title": "Emoji Widget" - }, - - "background": { - "service_worker": "background.js" - }, - - "commands": { - "toggle-panel": { - "suggested_key": { - "default": "Ctrl+Shift+E", - "mac": "Command+Shift+E" - }, - "description": "Toggle Emoji Side Panel" - } - }, + "minimum_chrome_version": "114", - "content_scripts": [ - { - "matches": [""], - "js": ["content.js"], - "run_at": "document_idle", - "all_frames": false - } - ] - } \ No newline at end of file + "side_panel": { + "default_path": "panel.html" + }, + + "action": { + "default_title": "Dewemoji", + "default_icon": { + "16": "assets/icon-16.png", + "32": "assets/icon-32.png", + "48": "assets/icon-48.png", + "128": "assets/icon-128.png" + } + }, + + "icons": { + "16": "assets/icon-16.png", + "32": "assets/icon-32.png", + "48": "assets/icon-48.png", + "128": "assets/icon-128.png" + }, + + "background": { + "service_worker": "background.js" + }, + + "commands": { + "toggle-panel": { + "suggested_key": { + "default": "Ctrl+Shift+E", + "mac": "Command+Shift+E" + }, + "description": "Toggle Emoji Side Panel" + } + } +} \ No newline at end of file diff --git a/panel.html b/panel.html index b53fb81..7a8ecbf 100644 --- a/panel.html +++ b/panel.html @@ -11,7 +11,7 @@

Find Your Emoji Free

- + @@ -37,7 +37,7 @@ -