diff --git a/chrome/browserSpecific.js b/chrome/browserSpecific.js index 6478d1e..cd5196c 100644 --- a/chrome/browserSpecific.js +++ b/chrome/browserSpecific.js @@ -38,10 +38,9 @@ export function getShortcutInstructions() { /** * createContextMenus creates the context menu options. - * @param {string} markupLanguage - the markup language the user chose. * @returns {void} */ -export function createContextMenus(markupLanguage) { +export function createContextMenus() { // This function should do nothing. It needs to exist because the Firefox extension // uses a function by the same name that is imported into the background script. } @@ -57,10 +56,9 @@ let isTableSelected = false; * of HTML element the mouse is interacting with. This only has an effect if the context * menu is not currently visible. * @param {string} context - info about the element the mouse is interacting with. - * @param {string} markupLanguage - the markup language the user chose. * @returns {Promise} */ -export async function updateContextMenu(context, markupLanguage) { +export async function updateContextMenu(context) { // The `browser.contextMenus.update` method doesn't work well in Chromium because // when it's used to hide all but one context menu option, the one remaining would // appear under a "Stardown" parent menu option instead of being in the root of the @@ -88,48 +86,12 @@ export async function updateContextMenu(context, markupLanguage) { } browser.contextMenus.create(menu.selectionItem); + browser.contextMenus.create(menu.selectionWithSourceItem); + browser.contextMenus.create(menu.selectionQuoteItem); browser.contextMenus.create(menu.pageItem); browser.contextMenus.create(menu.pageSectionItem); browser.contextMenus.create(menu.videoItem); browser.contextMenus.create(menu.audioItem); } - - updateContextMenuLanguage(markupLanguage); - } -} - -/** - * updateContextMenuLanguage changes the context menu options to reflect the user's - * chosen markup language. - * @param {string} markupLanguage - the markup language the user chose. - * @returns {void} - */ -export function updateContextMenuLanguage(markupLanguage) { - if (markupLanguage === 'html') { - markupLanguage = 'HTML'; - } else if (markupLanguage === 'markdown with some html') { - markupLanguage = 'markdown'; } - - browser.contextMenus.update('page', { - title: `Copy ${markupLanguage} link for this page`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('pageSection', { - title: `Copy ${markupLanguage} link for this section`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('selection', { - title: `Copy ${markupLanguage} of selection`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('link', { - title: `Copy ${markupLanguage} of link`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('image', { - title: `Copy ${markupLanguage} of image`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('video', { - title: `Copy ${markupLanguage} of video`, - }, () => { if (browser.runtime.lastError) return; }); - browser.contextMenus.update('audio', { - title: `Copy ${markupLanguage} of audio`, - }, () => { if (browser.runtime.lastError) return; }); } diff --git a/docs/manual-testing.md b/docs/manual-testing.md index 2ac0ad0..f6e29b4 100644 --- a/docs/manual-testing.md +++ b/docs/manual-testing.md @@ -49,24 +49,22 @@ When the user right-clicks part of a web page, their browser detects the type of - [ ] **Pressing any button in the popup** should do what the button's text describes. - [ ] **Pressing Alt+C (Mac: ⌥+C)** copies a markdown link for the page, unless part of the page is selected in which case markdown of the selection is copied instead. -- [ ] **Right-clicking an empty part of a page** shows the "Copy markdown link for this page" and "Copy markdown link for this section" options. -- [ ] **Right-clicking a website's unselected header** shows the "Copy markdown link for this page" and "Copy markdown link for this section" options. -- [ ] **Right-clicking selected text** shows the "Copy markdown of selection" option. -- [ ] **Right-clicking an unselected image** shows the "Copy markdown of image" option. -- [ ] **Selecting text, then right-clicking an unselected image**, due to browser limitations, shows no context menu option in Chromium and shows "Copy markdown of selection" in Firefox. -- [ ] **Selecting text and image(s), then right-clicking the selected text** shows the "Copy markdown of selection" option. -- [ ] **Selecting text and image(s), then right-clicking a selected image** shows the "Copy markdown of selection" option. -- [ ] **Selecting text and link(s), then right-clicking a selected link** shows the "Copy markdown of selection" option. -- [ ] **Right-clicking a link that is not an image** shows the "Copy markdown of link" option. -- [ ] **Right-clicking a link that is an image** might not show any context menu options due to browser limitations. If a context menu option appears, it should be "Copy markdown of image". -- [ ] **Right-clicking a video** shows the "Copy markdown of video" option, but may require a second right-click for the correct context menu to appear because some videos (e.g. YouTube videos) have a special context menu. -- [ ] **Right-clicking an audio player** shows the "Copy markdown of audio" option. +- [ ] **Right-clicking an unselected part of a page** shows the "Copy link for this page" and "Copy link for this section" options. +- [ ] **Right-clicking an unselected image** shows the "Copy image" option. +- [ ] **Selecting text and/or image(s), then right-clicking the selection** shows the options "Copy selection", "Copy selection with source", and "Copy selection quote". +- [ ] **Right-clicking a link that is not an image** shows the "Copy link" option. +- [ ] **Right-clicking a link that is an image** might not show any context menu options due to browser limitations. If a context menu option appears, it should be "Copy image". +- [ ] **Right-clicking a video** shows the "Copy video" option, but may require a second right-click for the correct context menu to appear because some videos (e.g. YouTube videos) have a special context menu. +- [ ] **Right-clicking an audio player** shows the "Copy audio" option. - [ ] **Selecting the contents of a table and right-clicking the selection** shows several options: "Copy markdown of table", "Copy TSV of table", "Copy CSV of table", "Copy JSON of table", and "Copy HTML of table". Each option should result in a table with everything aligned correctly, leaving some cells empty and others duplicated as necessary. -- [ ] "Copy markdown link for this page" copies a markdown link for the page. The link is guaranteed to not have an HTML element ID nor a text fragment. -- [ ] "Copy markdown link for this section" copies a markdown link for the page with the nearest HTML element ID above (*above* in the HTML element tree sense) where the page was right-clicked. -- [ ] "Copy markdown of selection", by default, copies markdown of the selected text (including all of the page's formatting that markdown supports), and a markdown link containing a text fragment and possibly an HTML element ID. -- [ ] "Copy markdown of image" copies markdown of the image using the image's URL and any alt text. -- [ ] "Copy markdown of link" copies markdown of the link, using the same title and URL as the link in the page (except for any character escapes or encodings). -- [ ] "Copy markdown of video" copies markdown of the video using the video source's URL. -- [ ] "Copy markdown of audio" copies a markdown link to either an audio file or a site that plays the audio. +- [ ] Context menu options + - [ ] "Copy link for this page" copies a markdown link for the page. The link is guaranteed to not have an HTML element ID nor a text fragment. + - [ ] "Copy link for this section" copies a markdown link for the page with the nearest HTML element ID above (*above* in the HTML element tree sense) where the page was right-clicked. + - [ ] "Copy selection" copies markdown of the selection (including all of the page's formatting that markdown supports). + - [ ] "Copy selection with source" does the same as "Copy selection" but also includes a markdown link containing a text fragment and possibly an HTML element ID. + - [ ] "Copy selection quote" does the same as "Copy selection with source" but formats the output as a markdown block quote. + - [ ] "Copy image" copies markdown of the image using the image's URL and any alt text. + - [ ] "Copy link" copies markdown of the link, using the same title and URL as the link in the page (except for any character escapes or encodings). + - [ ] "Copy video" copies markdown of the video using the video source's URL. + - [ ] "Copy audio" copies a markdown link to either an audio file or a site that plays the audio. - [ ] **Change settings and repeat as necessary** diff --git a/firefox/browserSpecific.js b/firefox/browserSpecific.js index 07848ed..7862598 100644 --- a/firefox/browserSpecific.js +++ b/firefox/browserSpecific.js @@ -40,14 +40,15 @@ export function getShortcutInstructions() { /** * createContextMenus creates the context menu options. - * @param {string} markupLanguage - the markup language the user chose. * @returns {void} */ -export function createContextMenus(markupLanguage) { +export function createContextMenus() { browser.runtime.onInstalled.addListener(() => { browser.contextMenus.create(menu.pageItem); browser.contextMenus.create(menu.pageSectionItem); browser.contextMenus.create(menu.selectionItem); + browser.contextMenus.create(menu.selectionWithSourceItem); + browser.contextMenus.create(menu.selectionQuoteItem); browser.contextMenus.create(menu.linkItem); browser.contextMenus.create(menu.imageItem); browser.contextMenus.create(menu.videoItem); @@ -63,8 +64,6 @@ export function createContextMenus(markupLanguage) { browser.contextMenus.update('csvTable', { visible: false }); browser.contextMenus.update('jsonTable', { visible: false }); browser.contextMenus.update('htmlTable', { visible: false }); - - updateContextMenuLanguage(markupLanguage); }); } @@ -73,10 +72,9 @@ export function createContextMenus(markupLanguage) { * of HTML element the mouse is interacting with. This only has an effect if the context * menu is not currently visible. * @param {string} context - info about the element the mouse is interacting with. - * @param {string} markupLanguage - the markup language the user chose. * @returns {Promise} */ -export async function updateContextMenu(context, markupLanguage) { +export async function updateContextMenu(context) { switch (context.mouseover) { case 'selection': browser.contextMenus.update('link', { visible: false }); @@ -96,6 +94,8 @@ export async function updateContextMenu(context, markupLanguage) { await sleep(100); // wait for the context menu browser.contextMenus.update('selection', { visible: false }); + browser.contextMenus.update('selectionWithSource', { visible: false }); + browser.contextMenus.update('selectionQuote', { visible: false }); browser.contextMenus.update('markdownTable', { visible: true }); browser.contextMenus.update('tsvTable', { visible: true }); @@ -104,6 +104,8 @@ export async function updateContextMenu(context, markupLanguage) { browser.contextMenus.update('htmlTable', { visible: true }); } else if (context.selectionchange) { browser.contextMenus.update('selection', { visible: true }); + browser.contextMenus.update('selectionWithSource', { visible: true }); + browser.contextMenus.update('selectionQuote', { visible: true }); browser.contextMenus.update('markdownTable', { visible: false }); browser.contextMenus.update('tsvTable', { visible: false }); @@ -111,42 +113,4 @@ export async function updateContextMenu(context, markupLanguage) { browser.contextMenus.update('jsonTable', { visible: false }); browser.contextMenus.update('htmlTable', { visible: false }); } - - updateContextMenuLanguage(markupLanguage); -} - -/** - * updateContextMenuLanguage changes the context menu options to reflect the user's - * chosen markup language. - * @param {string} markupLanguage - the markup language the user chose. - * @returns {void} - */ -export function updateContextMenuLanguage(markupLanguage) { - if (markupLanguage === 'html') { - markupLanguage = 'HTML'; - } else if (markupLanguage === 'markdown with some html') { - markupLanguage = 'markdown'; - } - - browser.contextMenus.update('page', { - title: `Copy ${markupLanguage} link for this page`, - }); - browser.contextMenus.update('pageSection', { - title: `Copy ${markupLanguage} link for this section`, - }); - browser.contextMenus.update('selection', { - title: `Copy ${markupLanguage} of selection`, - }); - browser.contextMenus.update('link', { - title: `Copy ${markupLanguage} of link`, - }); - browser.contextMenus.update('image', { - title: `Copy ${markupLanguage} of image`, - }); - browser.contextMenus.update('video', { - title: `Copy ${markupLanguage} of video`, - }); - browser.contextMenus.update('audio', { - title: `Copy ${markupLanguage} of audio`, - }); } diff --git a/src/background.js b/src/background.js index 3a1fb05..1a64c9e 100644 --- a/src/background.js +++ b/src/background.js @@ -14,11 +14,10 @@ limitations under the License. */ -import { browser, sleep, createContextMenus, updateContextMenu, updateContextMenuLanguage } from './browserSpecific.js'; +import { browser, sleep, createContextMenus, updateContextMenu } from './browserSpecific.js'; import { getSetting } from './getSetting.js'; import { createTabLink } from './generators/md.js'; -let markupLanguage = 'markdown'; let jsonDestination = 'clipboard'; let windowId = null; @@ -28,10 +27,7 @@ browser.runtime.onInstalled.addListener(async details => { } }); -getSetting('markupLanguage').then(value => { - markupLanguage = value; - createContextMenus(value); -}); +createContextMenus(); getSetting('jsonDestination').then(value => jsonDestination = value); browser.tabs.query({ currentWindow: true, active: true }).then(tabs => { windowId = tabs[0].windowId; @@ -85,7 +81,7 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { // because the contextMenus.update method cannot update a context menu that // is already open. The content script listens for mouseover and mouseup // events. - await updateContextMenu(message.context, markupLanguage); + await updateContextMenu(message.context); break; case 'downloadFile': await downloadFile(message.file); @@ -118,10 +114,6 @@ browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { case 'settingsButtonPressed': browser.runtime.openOptionsPage(); break; - case 'markupLanguage': - markupLanguage = message.markupLanguage; - updateContextMenuLanguage(markupLanguage); - break; case 'jsonDestination': jsonDestination = message.jsonDestination; break; @@ -148,6 +140,16 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => { tab, { category: 'selectionRightClick' }, { frameId: info.frameId }, ); break; + case 'selectionWithSource': + await handleInteraction( + tab, { category: 'selectionWithSourceRightClick' }, { frameId: info.frameId }, + ); + break; + case 'selectionQuote': + await handleInteraction( + tab, { category: 'selectionQuoteRightClick' }, { frameId: info.frameId }, + ); + break; case 'link': // In Chromium unlike in Firefox, `info.linkText` is undefined and no // property in `info` has the link's text. @@ -304,6 +306,7 @@ async function handleCopyMultipleTabs(activeTab) { // create the links let text = ''; + const markupLanguage = await getSetting('markupLanguage'); switch (markupLanguage) { case 'html': const result = ['