From d8059a0f62534637d6ddc09b328b3e27f62c257c Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 16 Sep 2016 20:20:02 -0400 Subject: [PATCH] added context menu and copying usernames/passwords options --- src/background.js | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/src/background.js b/src/background.js index 567c392a..af89d732 100644 --- a/src/background.js +++ b/src/background.js @@ -6,7 +6,58 @@ var siteService = new SiteService(cryptoService, userService, apiService); var folderService = new FolderService(cryptoService, userService, apiService); var syncService = new SyncService(siteService, folderService, userService, apiService); +function buildContextMenu() { + chrome.contextMenus.removeAll(); + chrome.contextMenus.create({ + type: 'normal', + id: 'autofill', + title: 'Auto-fill' + }); + + chrome.contextMenus.create({ + type: 'normal', + id: 'copy-username', + title: 'Copy Username' + }); + + chrome.contextMenus.create({ + type: 'normal', + id: 'copy-password', + title: 'Copy Password' + }); + + chrome.contextMenus.create({ + type: 'separator' + }); + + chrome.contextMenus.create({ + type: 'normal', + id: 'generate-password', + title: 'Generate Password' + }); +} + +chrome.tabs.onActivated.addListener(function (activeInfo) { + buildContextMenu(); + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + var tab = null; + if (tabs.length > 0) { + tab = tabs[0]; + } + + if (!tab || !tab.url) { + return; + } + + buildContextMenuOptions(tab.url); + }); +}); + +var loadedMenuOnUpdate = false; chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { + loadedMenuOnUpdate = false; + buildContextMenu(); + if (!tab.url) { return; } @@ -20,9 +71,16 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { chrome.browserAction.setBadgeBackgroundColor({ color: '#294e5f' }); siteService.getAllDecrypted().then(function (sites) { + if (loadedMenuOnUpdate) { + return; + } + loadedMenuOnUpdate = true; + + sortSites(sites); for (var i = 0; i < sites.length; i++) { if (sites[i].domain && tabDomain == sites[i].domain) { count++; + loadContextMenuOptions(sites[i]); } } @@ -40,3 +98,105 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { } }); }); + +chrome.contextMenus.onClicked.addListener(function (info, tab) { + if (info.parentMenuItemId === 'copy-username' || info.parentMenuItemId === 'copy-password') { + var id = info.menuItemId.split('_')[1]; + siteService.getAllDecrypted().then(function (sites) { + for (var i = 0; i < sites.length; i++) { + if (sites[i].id == id) { + if (info.parentMenuItemId === 'copy-username') { + copyToClipboard(sites[i].username); + } + else if (info.parentMenuItemId === 'copy-password') { + copyToClipboard(sites[i].password); + } + return; + } + } + }); + } +}); + +function sortSites(sites) { + sites.sort(function (a, b) { + var nameA = (a.name + '_' + a.username).toUpperCase(); + var nameB = (b.name + '_' + b.username).toUpperCase(); + + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + + return 0; + }); +} + +function buildContextMenuOptions(url) { + var tabDomain = tldjs.getDomain(url); + if (!tabDomain) { + return; + } + + siteService.getAllDecrypted().then(function (sites) { + sortSites(sites); + for (var i = 0; i < sites.length; i++) { + if (sites[i].domain && tabDomain == sites[i].domain) { + loadContextMenuOptions(sites[i]); + } + } + }); +} + +function loadContextMenuOptions(site) { + var title = site.name + ' (' + site.username + ')'; + chrome.contextMenus.create({ + type: 'normal', + id: 'autofill_' + site.id, + parentId: 'autofill', + title: title + }); + + chrome.contextMenus.create({ + type: 'normal', + id: 'copy-username_' + site.id, + parentId: 'copy-username', + title: title + }); + + chrome.contextMenus.create({ + type: 'normal', + id: 'copy-password_' + site.id, + parentId: 'copy-password', + title: title + }); +} + +function copyToClipboard(text) { + if (window.clipboardData && window.clipboardData.setData) { + // IE specific code path to prevent textarea being shown while dialog is visible. + return clipboardData.setData('Text', text); + } + else if (document.queryCommandSupported && document.queryCommandSupported('copy')) { + var textarea = document.createElement('textarea'); + textarea.textContent = text; + // Prevent scrolling to bottom of page in MS Edge. + textarea.style.position = 'fixed'; + document.body.appendChild(textarea); + textarea.select(); + + try { + // Security exception may be thrown by some browsers. + return document.execCommand('copy'); + } + catch (ex) { + console.warn('Copy to clipboard failed.', ex); + return false; + } + finally { + document.body.removeChild(textarea); + } + } +}