mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 11:47:54 +01:00
clipper(web): save height/width with clipped data
This commit is contained in:
@@ -27,7 +27,7 @@ import {
|
||||
Server,
|
||||
Clip,
|
||||
WEB_EXTENSION_CHANNEL_EVENTS
|
||||
} from "@notesnook/web-clipper/src/common/bridge";
|
||||
} from "@notesnook/web-clipper/dist/common/bridge";
|
||||
import { isUserPremium } from "../hooks/use-is-user-premium";
|
||||
import { store as themestore } from "../stores/theme-store";
|
||||
import { store as appstore } from "../stores/app-store";
|
||||
@@ -133,6 +133,8 @@ class WebExtensionServer implements Server {
|
||||
"data-mime": attachment.type,
|
||||
src: clip.url,
|
||||
title: clip.pageTitle || clip.title,
|
||||
width: clip.width ? `${clip.width}` : undefined,
|
||||
height: clip.height ? `${clip.height}` : undefined,
|
||||
class: "web-clip"
|
||||
}).outerHTML;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ const common = {
|
||||
"tabs",
|
||||
"storage",
|
||||
"contextMenus",
|
||||
"notifications"
|
||||
"notifications",
|
||||
"<all_urls>"
|
||||
],
|
||||
content_scripts: [
|
||||
{
|
||||
@@ -51,14 +52,14 @@ const common = {
|
||||
js: ["contentScript.bundle.js"],
|
||||
matches: ["http://*/*", "https://*/*"],
|
||||
exclude_matches: ["*://app.notesnook.com/*", "*://localhost/*"]
|
||||
},
|
||||
}
|
||||
],
|
||||
browser_specific_settings: {
|
||||
gecko: {
|
||||
strict_min_version: "105.0"
|
||||
}
|
||||
},
|
||||
icons: ICONS,
|
||||
icons: ICONS
|
||||
};
|
||||
|
||||
const v2 = {
|
||||
|
||||
3191
extensions/web-clipper/package-lock.json
generated
3191
extensions/web-clipper/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
"name": "@notesnook/web-clipper",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@hot-loader/react-dom": "^17.0.2",
|
||||
@@ -76,9 +77,9 @@
|
||||
"fs-extra": "^10.0.0",
|
||||
"html-loader": "^3.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"node-sass": "^8.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"sass-loader": "^12.4.0",
|
||||
"sass-loader": "^13.2.0",
|
||||
"source-map-loader": "^3.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"terser-webpack-plugin": "^5.3.1",
|
||||
|
||||
@@ -17,12 +17,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
WEB_EXTENSION_CHANNEL?: MessageChannel;
|
||||
}
|
||||
}
|
||||
|
||||
export type ClipArea = "full-page" | "visible" | "selection" | "article";
|
||||
|
||||
export type ClipMode = "simplified" | "screenshot" | "complete";
|
||||
@@ -59,6 +53,8 @@ export type Clip = {
|
||||
data: string;
|
||||
area: ClipArea;
|
||||
mode: ClipMode;
|
||||
width?: number;
|
||||
height?: number;
|
||||
pageTitle?: string;
|
||||
tags?: string[];
|
||||
note?: ItemReference;
|
||||
@@ -77,3 +73,9 @@ export const WEB_EXTENSION_CHANNEL_EVENTS = {
|
||||
ON_CREATED: "web-extension-channel-created",
|
||||
ON_READY: "web-extension-channel-ready"
|
||||
} as const;
|
||||
|
||||
export type ClipData = {
|
||||
height?: number;
|
||||
width?: number;
|
||||
data: string;
|
||||
};
|
||||
|
||||
@@ -75,22 +75,24 @@ export const NotePicker = (props: NotePickerProps) => {
|
||||
</Text>
|
||||
<Icon path={Icons.chevronDown} color="text" size={18} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="tool"
|
||||
onClick={() => onSelected(undefined)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={"Clear selection"}
|
||||
>
|
||||
<Icon path={Icons.close} color="text" size={16} />
|
||||
</Button>
|
||||
{selectedNote && (
|
||||
<Button
|
||||
variant="tool"
|
||||
onClick={() => onSelected(undefined)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={"Clear selection"}
|
||||
>
|
||||
<Icon path={Icons.close} color="text" size={16} />
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Picker onClose={close} isOpen={modalVisible}>
|
||||
|
||||
@@ -74,22 +74,24 @@ export const NotebookPicker = (props: NotebookPickerProps) => {
|
||||
</Text>
|
||||
<Icon path={Icons.chevronDown} color="text" size={18} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="tool"
|
||||
onClick={() => onSelected(undefined)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={"Clear selection"}
|
||||
>
|
||||
<Icon path={Icons.close} color="text" size={16} />
|
||||
</Button>
|
||||
{selectedNotebook && (
|
||||
<Button
|
||||
variant="tool"
|
||||
onClick={() => onSelected(undefined)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={"Clear selection"}
|
||||
>
|
||||
<Icon path={Icons.close} color="text" size={16} />
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Picker onClose={close} isOpen={modalVisible}>
|
||||
|
||||
@@ -26,22 +26,41 @@ import {
|
||||
} from "@notesnook/clipper";
|
||||
import { ClipArea, ClipMode } from "../common/bridge";
|
||||
|
||||
browser.runtime.onMessage.addListener((request) => {
|
||||
const message = request as {
|
||||
type?: string;
|
||||
mode?: ClipMode;
|
||||
area?: ClipArea;
|
||||
};
|
||||
type ClipMessage = {
|
||||
type: "clip";
|
||||
mode?: ClipMode;
|
||||
area?: ClipArea;
|
||||
};
|
||||
|
||||
if (message.type === "viewport") {
|
||||
return Promise.resolve({
|
||||
x: 0,
|
||||
y: 0,
|
||||
height: document.body.clientHeight,
|
||||
width: document.body.clientWidth
|
||||
});
|
||||
type ViewportMessage = {
|
||||
type: "viewport";
|
||||
};
|
||||
|
||||
browser.runtime.onMessage.addListener(async (request) => {
|
||||
const message = request as ClipMessage | ViewportMessage;
|
||||
|
||||
switch (message.type) {
|
||||
case "clip": {
|
||||
const sizeable =
|
||||
message.area === "full-page" &&
|
||||
(message.mode === "complete" || message.mode === "screenshot");
|
||||
return {
|
||||
height: sizeable ? document.body.clientHeight : 0,
|
||||
width: sizeable ? document.body.clientWidth : 0,
|
||||
data: await clip(request)
|
||||
};
|
||||
}
|
||||
case "viewport":
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
height: document.body.clientHeight,
|
||||
width: document.body.clientWidth
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function clip(message: ClipMessage) {
|
||||
try {
|
||||
const isScreenshot = message.mode === "screenshot";
|
||||
const withStyles = message.mode === "complete" || isScreenshot;
|
||||
@@ -64,4 +83,4 @@ browser.runtime.onMessage.addListener((request) => {
|
||||
} finally {
|
||||
if (message.area !== "selection") cleanup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ import {
|
||||
ItemReference,
|
||||
SelectedNotebook,
|
||||
ClipArea,
|
||||
ClipMode
|
||||
ClipMode,
|
||||
ClipData,
|
||||
} from "../common/bridge";
|
||||
import { usePersistentState } from "../hooks/use-persistent-state";
|
||||
import { deleteClip, getClip } from "../utils/storage";
|
||||
@@ -101,7 +102,7 @@ export function Main() {
|
||||
const [notebook, setNotebook] =
|
||||
usePersistentState<SelectedNotebook>("notebook");
|
||||
const [tags, setTags] = usePersistentState<string[]>("tags", []);
|
||||
const [clipData, setClipData] = useState<string>();
|
||||
const [clipData, setClipData] = useState<ClipData>();
|
||||
const pageTitle = useRef<string>();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -165,6 +166,7 @@ export function Main() {
|
||||
setClipArea(item.id);
|
||||
setClipNonce((s) => ++s);
|
||||
}}
|
||||
disabled={isClipping}
|
||||
sx={{
|
||||
display: "flex",
|
||||
borderRadius: "default",
|
||||
@@ -207,7 +209,7 @@ export function Main() {
|
||||
setClipMode(item.id);
|
||||
setClipNonce((s) => ++s);
|
||||
}}
|
||||
disabled={item.pro && !isPremium}
|
||||
disabled={isClipping || (item.pro && !isPremium)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
borderRadius: "default",
|
||||
@@ -253,7 +255,7 @@ export function Main() {
|
||||
onClick={async () => {
|
||||
if (!clipData) return;
|
||||
const winUrl = URL.createObjectURL(
|
||||
new Blob(["\ufeff", clipData], { type: "text/html" })
|
||||
new Blob(["\ufeff", clipData.data], { type: "text/html" })
|
||||
);
|
||||
await browser.windows.create({
|
||||
url: winUrl
|
||||
@@ -266,7 +268,7 @@ export function Main() {
|
||||
|
||||
{error && (
|
||||
<Text
|
||||
variant="text"
|
||||
variant="body"
|
||||
sx={{
|
||||
mt: 1,
|
||||
bg: "errorBg",
|
||||
@@ -346,17 +348,16 @@ export function Main() {
|
||||
setError("You are not connected to Notesnook.");
|
||||
return;
|
||||
}
|
||||
|
||||
await notesnook.saveClip({
|
||||
url,
|
||||
title,
|
||||
data: clipData,
|
||||
area: clipArea,
|
||||
mode: clipMode,
|
||||
tags,
|
||||
note,
|
||||
notebook,
|
||||
pageTitle: pageTitle.current
|
||||
pageTitle: pageTitle.current,
|
||||
...clipData
|
||||
});
|
||||
|
||||
setClipData(undefined);
|
||||
@@ -386,11 +387,11 @@ export function Main() {
|
||||
export async function clip(
|
||||
area: ClipArea,
|
||||
mode: ClipMode
|
||||
): Promise<string | undefined> {
|
||||
): Promise<ClipData | undefined> {
|
||||
const clipData = await getClip();
|
||||
if (area === "selection" && typeof clipData === "string") {
|
||||
await deleteClip();
|
||||
return clipData;
|
||||
return { data: clipData };
|
||||
}
|
||||
|
||||
const [tab] = await browser.tabs.query({ active: true });
|
||||
@@ -403,8 +404,11 @@ export async function clip(
|
||||
format: "jpeg",
|
||||
quality: 100
|
||||
});
|
||||
return `<img src="${result}" width="${tab.width}px" height="${tab.height}px"/>`;
|
||||
|
||||
return {
|
||||
data: `<img src="${result}" width="${tab.width}px" height="${tab.height}px"/>`
|
||||
};
|
||||
}
|
||||
|
||||
return await browser.tabs.sendMessage(tab.id, { mode, area });
|
||||
return await browser.tabs.sendMessage(tab.id, { type: "clip", mode, area });
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
"maxNodeModuleJsDepth": 5,
|
||||
"declaration": false
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["src", "global.d.ts"]
|
||||
}
|
||||
|
||||
@@ -133,7 +133,10 @@ var options = {
|
||||
.concat([".js", ".jsx", ".ts", ".tsx", ".css"])
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin({ verbose: false }),
|
||||
new CleanWebpackPlugin({
|
||||
verbose: false,
|
||||
dangerouslyAllowCleanPatternsOutsideProject: true
|
||||
}),
|
||||
new webpack.ProgressPlugin(),
|
||||
// expose and write the allowed env vars on the compiled bundle
|
||||
new webpack.EnvironmentPlugin(["NODE_ENV"]),
|
||||
|
||||
Reference in New Issue
Block a user