New:Socket for Asana Is Now Available.Learn more
Get Started

z.WebKeyBind

Package Overview
Versions
2
Alerts
File Explorer
Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

z-webkeybind@yourdomain.com - firefox Package Compare versions

Comparing version
1.0.1
to
1.0.2
+163
-73
import_export.js

@@ -21,2 +21,5 @@ document.addEventListener('DOMContentLoaded', () => {

// --- CHECK IF WE ARE IN THE "BROWSE ONLY" FULL TAB ---
const isFullTabMode = new URLSearchParams(window.location.search).get('importMode') === 'true';
// --- 1. FOCUS TRAP LOGIC ---

@@ -102,3 +105,3 @@ function handleFocusTrap(e) {

// --- 4. IMPORT LOGIC ---
// --- 4. THE FULL TAB IMPORT TRICK ---
function openModal() {

@@ -109,3 +112,3 @@ importModal.style.display = 'flex';

setTimeout(() => { document.getElementById('silent-start')?.focus(); }, 50);
if(window.showAccessibleAlert) window.showAccessibleAlert("Import menu opened. Drop or select a JSON file.", "info");
if(window.showAccessibleAlert) window.showAccessibleAlert("Import menu opened. Select a JSON file.", "info");
}

@@ -117,7 +120,26 @@

document.removeEventListener('keydown', handleFocusTrap);
if (btnImport) btnImport.focus();
if(window.showAccessibleAlert) window.showAccessibleAlert("Import menu closed.", "info");
if (window.showAccessibleAlert) window.showAccessibleAlert("Import menu closed.", "info");
// If in the full tab, closing the modal should close the entire tab
if (isFullTabMode) {
window.close();
} else if (btnImport) {
btnImport.focus();
}
}
if (btnImport) btnImport.addEventListener('click', openModal);
if (btnImport) {
btnImport.addEventListener('click', () => {
if (isFullTabMode) {
openModal();
} else {
// Open THIS file in a new tab to bypass Firefox security
const currentHtmlFile = window.location.pathname;
chrome.tabs.create({ url: currentHtmlFile + "?importMode=true" });
window.close(); // Close the tiny popup
}
});
}
if (btnCloseImport) btnCloseImport.addEventListener('click', closeModal);

@@ -130,13 +152,39 @@

// --- 5. DRAG & DROP HANDLING ---
// --- ISOLATE THE BROWSE BOX IN FULL TAB MODE ---
if (isFullTabMode) {
// 1. Move the import modal to the very top level of the body
document.body.appendChild(importModal);
// 2. Hide everything else in the extension so it looks like a clean, dedicated page
Array.from(document.body.children).forEach(child => {
if (child !== importModal && child.tagName !== 'SCRIPT') {
child.style.display = 'none';
}
});
// 3. Make the modal fill the screen with a clean background
importModal.style.display = 'flex';
importModal.style.position = 'fixed';
importModal.style.top = '0';
importModal.style.left = '0';
importModal.style.width = '100vw';
importModal.style.height = '100vh';
importModal.style.backgroundColor = '#f8f9fa'; // Clean light grey background
importModal.style.zIndex = '999999';
// 4. Hide the "Close" button since they can just close the browser tab to cancel
if (btnCloseImport) btnCloseImport.style.display = 'none';
// Trigger the focus trap for accessibility
setTimeout(openModal, 100);
}
// --- 5. STANDARD FILE CLICK ---
if (dropZone) {
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); fileInput.click(); } });
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.style.backgroundColor = '#f0ebff'; });
dropZone.addEventListener('dragleave', () => { dropZone.style.backgroundColor = '#f9f9f9'; });
dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.style.backgroundColor = '#f9f9f9'; if (e.dataTransfer.files.length) processFile(e.dataTransfer.files[0]); });
}
if (fileInput) fileInput.addEventListener('change', (e) => { if (e.target.files.length) processFile(e.target.files[0]); fileInput.value = ''; });
// --- NEW: 4-BUTTON ACCESSIBLE CONFLICT MODAL WITH CANCEL BEHAVIOR ---
// --- ACCESSIBLE CONFLICT MODAL ---
function showConflictResolutionModal(msg, onReplace, onReplaceAll, onSkip, onSkipAll, onCancel) {

@@ -162,3 +210,2 @@ let popupAnnouncer = document.getElementById('wkb-conflict-announcer');

modal.setAttribute('aria-modal', 'true');
// FIX: Applied modal-fadein here
modal.style.cssText = `position: relative; background: white; padding: 24px; border-radius: 8px; width: 380px; max-width: 90%; box-shadow: 0 10px 25px rgba(0,0,0,0.2); text-align: center; font-family: sans-serif; animation: modal-fadein 0.2s ease-out; display: flex; flex-direction: column; gap: 16px;`;

@@ -225,3 +272,3 @@

// --- 6. FILE PROCESSOR ---
// --- 6. FILE PROCESSOR (FIREFOX SAFE BATCH SAVE) ---
function processFile(file) {

@@ -234,79 +281,122 @@ if (!file.name.endsWith('.json')) {

reader.onload = (e) => {
let importedData;
try {
const importedData = JSON.parse(e.target.result);
if (!Array.isArray(importedData)) throw new Error();
importedData = JSON.parse(e.target.result);
if (!Array.isArray(importedData)) throw new Error("Not array");
} catch (err) {
if(window.showAccessibleAlert) window.showAccessibleAlert("Invalid JSON file format.", "error");
return;
}
chrome.storage.local.get(null, (existingItems) => {
const existingShortcuts = Object.values(existingItems).filter(item => item.id && item.key);
let importCount = 0, skipCount = 0, replaceCount = 0;
chrome.storage.local.get(null, (existingItems) => {
const existingShortcuts = Object.values(existingItems).filter(item => item.id && item.key);
let importCount = 0, skipCount = 0, replaceCount = 0;
let globalConflictAction = null;
let pendingSaves = {};
let keysToRemove = [];
const finalizeBatchSave = () => {
importModal.style.display = 'none';
document.removeEventListener('keydown', handleFocusTrap);
let globalConflictAction = null;
const handleCancel = () => {
importModal.style.display = 'none';
document.removeEventListener('keydown', handleFocusTrap);
if (window.showAccessibleAlert) window.showAccessibleAlert(`Import Cancelled. Added: ${importCount}, Replaced: ${replaceCount}, Skipped: ${skipCount}`, "info");
const finishUp = () => {
if (window.showAccessibleAlert) window.showAccessibleAlert(`Import Complete! Added: ${importCount}, Replaced: ${replaceCount}, Skipped: ${skipCount}`, "success");
if (window.loadShortcuts) window.loadShortcuts();
if (btnImport) btnImport.focus();
// Wait 1.5 seconds so they can see/hear the success alert, then close the tab!
if (isFullTabMode) {
setTimeout(() => { window.close(); }, 1500);
} else if (btnImport) {
btnImport.focus();
}
};
const processItem = (index) => {
if (index >= importedData.length) {
importModal.style.display = 'none'; document.removeEventListener('keydown', handleFocusTrap);
if (window.showAccessibleAlert) window.showAccessibleAlert(`Import Complete! Added: ${importCount}, Replaced: ${replaceCount}, Skipped: ${skipCount}`, "success");
if (window.loadShortcuts) window.loadShortcuts();
if (btnImport) btnImport.focus();
return;
}
if (keysToRemove.length > 0) {
chrome.storage.local.remove(keysToRemove, () => {
if (Object.keys(pendingSaves).length > 0) chrome.storage.local.set(pendingSaves, finishUp);
else finishUp();
});
} else if (Object.keys(pendingSaves).length > 0) {
chrome.storage.local.set(pendingSaves, finishUp);
} else {
finishUp();
}
};
const item = importedData[index];
if (!item.id || !item.key || !item.url) { processItem(index + 1); return; }
const handleCancel = () => {
importModal.style.display = 'none';
document.removeEventListener('keydown', handleFocusTrap);
if (window.showAccessibleAlert) window.showAccessibleAlert(`Import Cancelled. Added: ${importCount}, Replaced: ${replaceCount}, Skipped: ${skipCount}`, "info");
if (window.loadShortcuts) window.loadShortcuts();
if (isFullTabMode) {
window.close();
} else if (btnImport) {
btnImport.focus();
}
};
const normImpUrl = getNormUrl(item.url);
const conflict = existingShortcuts.find(ex => ex.key === item.key && (getNormUrl(ex.url) === normImpUrl || ex.url === "<URL>" || item.url === "<URL>"));
const processItem = (index) => {
if (index >= importedData.length) {
finalizeBatchSave();
return;
}
const saveItem = (isReplace) => {
chrome.storage.local.set({ [`shortcut_${item.id}`]: item }, () => {
if (isReplace) replaceCount++; else importCount++;
processItem(index + 1);
});
};
const item = importedData[index];
if (!item.id || !item.key || !item.url) { processItem(index + 1); return; }
const handleReplace = () => {
chrome.storage.local.remove(`shortcut_${conflict.id}`, () => {
const cIndex = existingShortcuts.findIndex(e => e.id === conflict.id);
if (cIndex > -1) existingShortcuts.splice(cIndex, 1);
existingShortcuts.push(item); saveItem(true);
});
};
const normImpUrl = getNormUrl(item.url);
const conflict = existingShortcuts.find(ex => ex.key === item.key && (getNormUrl(ex.url) === normImpUrl || ex.url === "<URL>" || item.url === "<URL>"));
const handleSkip = () => { skipCount++; processItem(index + 1); };
const handleReplace = () => {
keysToRemove.push(`shortcut_${conflict.id}`);
const cIndex = existingShortcuts.findIndex(e => e.id === conflict.id);
if (cIndex > -1) existingShortcuts.splice(cIndex, 1);
// Guarantee new unique ID
const newId = Date.now().toString() + Math.random().toString(36).substring(2, 6);
item.id = newId;
existingShortcuts.push(item);
pendingSaves[`shortcut_${newId}`] = item;
replaceCount++;
processItem(index + 1);
};
if (conflict) {
if (globalConflictAction === 'replace_all') {
handleReplace();
} else if (globalConflictAction === 'skip_all') {
handleSkip();
} else {
const msg = `Conflict! Key '${item.key}' is already used for '${conflict.name}'. What would you like to do?`;
showConflictResolutionModal(
msg,
() => { handleReplace(); },
() => { globalConflictAction = 'replace_all'; handleReplace(); },
() => { handleSkip(); },
() => { globalConflictAction = 'skip_all'; handleSkip(); },
() => { handleCancel(); }
);
}
} else {
existingShortcuts.push(item);
saveItem(false);
const handleSkip = () => { skipCount++; processItem(index + 1); };
if (conflict) {
if (globalConflictAction === 'replace_all') {
handleReplace();
} else if (globalConflictAction === 'skip_all') {
handleSkip();
} else {
const msg = `Conflict! Key '${item.key}' is already used for '${conflict.name}'. What would you like to do?`;
showConflictResolutionModal(
msg,
() => { handleReplace(); },
() => { globalConflictAction = 'replace_all'; handleReplace(); },
() => { handleSkip(); },
() => { globalConflictAction = 'skip_all'; handleSkip(); },
() => { handleCancel(); }
);
}
};
processItem(0);
});
} catch (err) { if(window.showAccessibleAlert) window.showAccessibleAlert("Invalid JSON file format.", "error"); }
} else {
const newId = Date.now().toString() + Math.random().toString(36).substring(2, 6);
item.id = newId;
existingShortcuts.push(item);
pendingSaves[`shortcut_${newId}`] = item;
importCount++;
processItem(index + 1);
}
};
processItem(0);
});
};
reader.readAsText(file);
}
});
{
"manifest_version": 3,
"name": "z.WebKeyBind",
"version": "1.0.1",
"version": "1.0.2",
"description": "Use Custom Shortcut key to Trigger the button of the page. ",

@@ -6,0 +6,0 @@ "permissions": [

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet