Skip to content

Commit

Permalink
Merge pull request #73 from 0x6b/embed-images-as-base64
Browse files Browse the repository at this point in the history
feat: add new advanced setting to embed images as base64 text
  • Loading branch information
0x6b authored Oct 9, 2020
2 parents bd0acf0 + b245ffa commit 69ee4f0
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 3 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ To change shortcut key, click gear icon on top-right and click **Manage Extensio
- Title Substitution -- line separated texts which will be removed from title text. If you add ` - Mozilla | MDN` to the textbox, the copied text wil be:
- From `[Add-ons - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons)`
- To `[Add-ons](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons)`
- Embed `img`s (.gif, .jpg, .jpeg, .png, and .webp) as base64 -- images will be encoded as base64 text, instead of URL, and added at the end of copied text. Sometime it might fail but useful for backup. See [Permissions](#privacy).

## Contributing

Expand All @@ -212,3 +213,15 @@ This extension is released under the MIT License. See [LICENSE](LICENSE) for det
## Privacy

The add-on does not store any user data outside of the Firefox user profile. The conversion to markdown is solely done locally. The add-on never send user action/data to any server.

### Permissions

See [permissions - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) for more detail.

| Permission | Optional | Description |
| ---------------- | :------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `activeTab` | | to run copy functionality at active tab |
| `clipboardWrite` | | to write to clipboard obviously |
| `contextMenus` | | to add context menus |
| `storage` | | to store preferences |
| `<all_urls>` | X | when [**Embed <code>img</code>s (.gif, .jpg, .jpeg, .png, and .webp) as base64 text as possible** option](#advanced) is set, the extension requests this permission since sometimes referenced images are hosted other than current active tab's URL so `activeTab` permission is not sufficient. If the option's not set, the extension removes this permission. |
3 changes: 2 additions & 1 deletion packages/core/src/copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ async function main() {
? false
: options.linkWithoutStyling;
options.img = typeof options.img === "undefined" ? false : options.img;
options.embedImage = typeof options.embedImage === "undefined" ? false : options.embedImage;
options.titleSubstitution =
typeof options.titleSubstitution === "undefined"
? ""
Expand Down Expand Up @@ -75,7 +76,7 @@ async function main() {
? `${title} (${document.URL})`
: `[${title}](${document.URL})`;
let html = `<a href="${document.URL}">${title}</a>`;
let selection = getSelectionAsMarkdown(options);
let selection = await getSelectionAsMarkdown(options);

if (selection.output !== "") {
if (options["use-quote"]) {
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/plugins/img-reference-style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default function img(turndownService) {
turndownService.addRule("img", {
filter: ["img"],
references: [],
replacement: function (content, node) {
const id = this.references.length + 1;
let title = "";
title = node.title ? node.title : node.alt ? node.alt : "";
this.references.push("[img" + id + "]: " + node.src);
return "![" + title + "][img" + id + "]";
},
append: function () {
let references = "";
if (this.references.length) {
references = "\n\n" + this.references.join("\n") + "\n\n";
this.references = [];
}
return references;
},
});
}
2 changes: 2 additions & 0 deletions packages/core/src/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ <h2>Markdown</h2>
<h2>Advanced</h2>
<label for="titleSubstitution">Title Substitution -- line separated texts which will be removed from title text</label>
<textarea id="titleSubstitution" rows="5"></textarea>
<input type="checkbox" id="embedImage">
<label for="embedImage">Embed <code>img</code>s (.gif, .jpg, .jpeg, .png, and .webp) as base64 text as possible -- images will be encoded as base64 text, instead of URL, and added at the end of copied text. <strong>Ask for the permission to access all websites when clicking Save button, since sometimes referenced images are hosted other than current active tab so <code>activeTab</code> permission is not sufficient.</strong> Unchecking this removes the additional permission.</label>
</div>

<button type="submit">Save</button>
Expand Down
18 changes: 17 additions & 1 deletion packages/core/src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ document.addEventListener("DOMContentLoaded", () => {
: result.linkWithoutStyling;
document.querySelector("#img").checked =
typeof result.img === "undefined" ? false : result.img;
document.querySelector("#embedImage").checked =
typeof result.embedImage === "undefined" ? false : result.embedImage;
document.querySelector("#titleSubstitution").value =
typeof result.titleSubstitution === "undefined"
? ""
Expand All @@ -62,8 +64,21 @@ document.addEventListener("DOMContentLoaded", () => {
);
});

document.querySelector("form").addEventListener("submit", (e) => {
document.querySelector("form").addEventListener("submit", async (e) => {
e.preventDefault();

let embedImage = document.querySelector("#embedImage").checked || false;

if (embedImage) {
embedImage = await browser.permissions.request({
origins: ["<all_urls>"],
permissions: [],
});
document.querySelector("#embedImage").checked = embedImage;
} else {
await browser.permissions.remove({ origins: ["<all_urls>"] });
}

browser.storage.local.set({
"use-quote": document.querySelector("#quote").checked,
"link-to-source": document.querySelector("#link").checked,
Expand All @@ -80,6 +95,7 @@ document.querySelector("form").addEventListener("submit", (e) => {
gfm: document.querySelector("#gfm").checked,
linkWithoutStyling: document.querySelector("#linkWithoutStyling").checked,
img: document.querySelector("#img").checked,
embedImage,
titleSubstitution: document.querySelector("#titleSubstitution").value,
reduceListItemPadding: document.querySelector("#reduceListItemPadding")
.value,
Expand Down
42 changes: 41 additions & 1 deletion packages/core/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import TurndownService from "turndown";
import turndownPluginMathJax from "./plugins/mathjax";
import turndownPluginGfmStrikethrough from "./plugins/gfm-strikethrough";
import turndownPluginImg from "./plugins/img";
import turndownPluginImgReferenceStyle from "./plugins/img-reference-style";
import turndownPluginLinkWithoutStyling from "./plugins/link-without-styling";
import turndownPluginListItem from "./plugins/list-item";
import { tables, taskListItems } from "turndown-plugin-gfm";
import * as clipboard from "clipboard-polyfill";

const url = require("url");

const getSelectionAsMarkdown = (options) => {
const getSelectionAsMarkdown = async (options) => {
let turndownService = TurndownService(options);

if (options.mathjax) {
Expand Down Expand Up @@ -135,6 +136,25 @@ const getSelectionAsMarkdown = (options) => {
}
}

if (options.embedImage) {
turndownService.use(turndownPluginImgReferenceStyle);
for (let img of container.getElementsByTagName("img")) {
if (
img.hasAttribute("src") &&
img.getAttribute("src").startsWith("http") &&
(
img.getAttribute("src").split("?", 2)[0].endsWith("gif") ||
img.getAttribute("src").split("?", 2)[0].endsWith("jpg") ||
img.getAttribute("src").split("?", 2)[0].endsWith("jpeg") ||
img.getAttribute("src").split("?", 2)[0].endsWith("png") ||
img.getAttribute("src").split("?", 2)[0].endsWith("webp")
)
) {
img.setAttribute("src", await imgToDataUrl(img));
}
}
}

html = container.innerHTML;
}

Expand All @@ -148,4 +168,24 @@ const doCopy = (text, html) => {
clipboard.write(dt);
};

const imgToDataUrl = (image) => {
return new Promise((resolve) => {
let img = new Image();
img.setAttribute("crossorigin", "anonymous");
img.onload = function () {
let canvas = document.createElement("canvas");
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;

canvas.getContext("2d").drawImage(this, 0, 0);
image.setAttribute("src", canvas.toDataURL("image/png"));

resolve(image.src);
canvas = null;
};

img.src = image.getAttribute("src");
});
};

export { getSelectionAsMarkdown, doCopy };
1 change: 1 addition & 0 deletions packages/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
}
},
"permissions": ["activeTab", "clipboardWrite", "contextMenus", "storage"],
"optional_permissions": ["<all_urls>"],
"applications": {
"gecko": {
"id": "{db9a72da-7bc5-4805-bcea-da3cb1a15316}"
Expand Down

0 comments on commit 69ee4f0

Please sign in to comment.