feat(clipper): Added "Clip as screenshot" switch to allow clipping content as a screenshot and save it to Files
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { runtime, action, browserAction, windows, storage } from 'webextension-polyfill'
|
||||
import { RuntimeMessage, RuntimeMessageTypes } from '../types/message'
|
||||
import { ClipPayload, RuntimeMessage, RuntimeMessageTypes } from '../types/message'
|
||||
|
||||
const isFirefox = navigator.userAgent.indexOf('Firefox/') !== -1
|
||||
|
||||
const openPopupAndClipSelection = async (payload: { title: string; content: string }) => {
|
||||
const openPopupAndClipSelection = async (payload: ClipPayload) => {
|
||||
await storage.local.set({ clip: payload })
|
||||
|
||||
if (isFirefox) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { runtime } from 'webextension-polyfill'
|
||||
import { Readability } from '@mozilla/readability'
|
||||
import { RuntimeMessage, RuntimeMessageTypes } from '../types/message'
|
||||
import { toPng } from 'html-to-image'
|
||||
|
||||
let isSelectingNodeForClipping = false
|
||||
let isScreenshotMode = false
|
||||
|
||||
runtime.onMessage.addListener(async (message: RuntimeMessage) => {
|
||||
switch (message.type) {
|
||||
@@ -10,6 +12,10 @@ runtime.onMessage.addListener(async (message: RuntimeMessage) => {
|
||||
isSelectingNodeForClipping = true
|
||||
return
|
||||
}
|
||||
case RuntimeMessageTypes.ToggleScreenshotMode: {
|
||||
isScreenshotMode = message.enabled
|
||||
return
|
||||
}
|
||||
case RuntimeMessageTypes.HasSelection: {
|
||||
const selection = window.getSelection()
|
||||
|
||||
@@ -40,6 +46,11 @@ runtime.onMessage.addListener(async (message: RuntimeMessage) => {
|
||||
return { title: document.title, content: result.innerHTML, url: window.location.href }
|
||||
}
|
||||
case RuntimeMessageTypes.GetFullPage: {
|
||||
if (isScreenshotMode) {
|
||||
const content = await toPng(document.body)
|
||||
return { title: document.title, content: content, url: window.location.href, isScreenshot: true }
|
||||
}
|
||||
|
||||
return { title: document.title, content: document.body.innerHTML, url: window.location.href }
|
||||
}
|
||||
case RuntimeMessageTypes.GetArticle: {
|
||||
@@ -90,7 +101,7 @@ const disableNodeSelection = () => {
|
||||
nodeOverlayElement.style.visibility = 'hidden'
|
||||
}
|
||||
|
||||
window.addEventListener('click', (event) => {
|
||||
window.addEventListener('click', async (event) => {
|
||||
if (!isSelectingNodeForClipping) {
|
||||
return
|
||||
}
|
||||
@@ -102,10 +113,10 @@ window.addEventListener('click', (event) => {
|
||||
return
|
||||
}
|
||||
const title = document.title
|
||||
const content = target.outerHTML
|
||||
const content = isScreenshotMode ? await toPng(target) : target.outerHTML
|
||||
void runtime.sendMessage({
|
||||
type: RuntimeMessageTypes.OpenPopupWithSelection,
|
||||
payload: { title, content, url: window.location.href },
|
||||
payload: { title, content, url: window.location.href, isScreenshot: isScreenshotMode },
|
||||
} as RuntimeMessage)
|
||||
})
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ export const RuntimeMessageTypes = {
|
||||
GetFullPage: 'get-full-page',
|
||||
OpenPopupWithSelection: 'open-popup-with-selection',
|
||||
StartNodeSelection: 'start-node-selection',
|
||||
ToggleScreenshotMode: 'toggle-screenshot-mode',
|
||||
} as const
|
||||
|
||||
export type RuntimeMessageType = typeof RuntimeMessageTypes[keyof typeof RuntimeMessageTypes]
|
||||
@@ -15,6 +16,7 @@ export type ClipPayload = {
|
||||
title: string
|
||||
content: string
|
||||
url: string
|
||||
isScreenshot?: boolean
|
||||
}
|
||||
|
||||
export type RuntimeMessageReturnTypes = {
|
||||
@@ -24,6 +26,7 @@ export type RuntimeMessageReturnTypes = {
|
||||
[RuntimeMessageTypes.GetFullPage]: ClipPayload
|
||||
[RuntimeMessageTypes.OpenPopupWithSelection]: void
|
||||
[RuntimeMessageTypes.StartNodeSelection]: void
|
||||
[RuntimeMessageTypes.ToggleScreenshotMode]: void
|
||||
}
|
||||
|
||||
export type RuntimeMessage =
|
||||
@@ -32,5 +35,9 @@ export type RuntimeMessage =
|
||||
payload: ClipPayload
|
||||
}
|
||||
| {
|
||||
type: Exclude<RuntimeMessageType, MessagesWithClipPayload>
|
||||
type: typeof RuntimeMessageTypes.ToggleScreenshotMode
|
||||
enabled: boolean
|
||||
}
|
||||
| {
|
||||
type: Exclude<RuntimeMessageType, MessagesWithClipPayload | typeof RuntimeMessageTypes.ToggleScreenshotMode>
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { tabs } from 'webextension-polyfill'
|
||||
import { RuntimeMessageReturnTypes, RuntimeMessageType } from '../types/message'
|
||||
import { RuntimeMessage, RuntimeMessageReturnTypes } from '../types/message'
|
||||
|
||||
export default async function sendMessageToActiveTab<T extends RuntimeMessageType>(
|
||||
type: T,
|
||||
): Promise<RuntimeMessageReturnTypes[T] | undefined> {
|
||||
export default async function sendMessageToActiveTab<T extends RuntimeMessage>(
|
||||
message: T,
|
||||
): Promise<RuntimeMessageReturnTypes[T['type']] | undefined> {
|
||||
const [activeTab] = await tabs.query({ active: true, currentWindow: true, windowType: 'normal' })
|
||||
|
||||
if (!activeTab || !activeTab.id) {
|
||||
return
|
||||
}
|
||||
|
||||
return await tabs.sendMessage(activeTab.id, { type })
|
||||
return await tabs.sendMessage(activeTab.id, message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user