feat: save pdf poc

This commit is contained in:
Michal Szczepanski 2023-06-15 21:55:08 +02:00
parent 1bcfdc0613
commit 9135c951f2
34 changed files with 1138 additions and 128 deletions

957
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,7 @@
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.3",
"@mui/x-date-pickers": "^6.1.0",
"@pinmenote/browser-api": "^0.0.2",
"@pinmenote/browser-api": "^0.0.4",
"@pinmenote/fetch-service": "^0.0.3",
"@pinmenote/page-compute": "^0.0.9",
"@pinmenote/tiny-dispatcher": "^0.0.2",
@ -75,6 +75,7 @@
"nanoid": "^4.0.0",
"openpgp": "^5.5.0",
"parse5": "^7.1.2",
"pdfjs-dist": "^3.7.107",
"prosemirror-commands": "^1.3.1",
"prosemirror-dropcursor": "^1.6.1",
"prosemirror-gapcursor": "^1.3.1",

View File

@ -27,10 +27,10 @@ export class ScreenshotFactory {
static takeScreenshot = async (doc: PinDocument, rect?: ObjRectangleDto, url?: ObjUrlDto): Promise<string> => {
return new Promise((resolve, reject) => {
// Crop screenshot function
TinyDispatcher.addListener<string>(
TinyDispatcher.getInstance().addListener<string>(
BusMessageType.CONTENT_TAKE_SCREENSHOT,
async (event: string, key: string, screenshot: string) => {
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().removeListener(event, key);
if (rect) screenshot = await ImageResizeFactory.resize(doc, rect, screenshot);
resolve(screenshot);
}

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ObjUrlDto } from '../model/obj/obj.dto';
import { fnConsoleLog } from '../fn/fn-console';
interface QueryParam {
key: string;
@ -71,6 +72,7 @@ export class UrlFactory {
resolve(this.result as string);
};
reader.onerror = function () {
fnConsoleLog('UrlFactory->toDataUri->error', value, this.error);
reject(this.error);
};
reader.readAsDataURL(value);

View File

@ -53,6 +53,7 @@ export enum BusMessageType {
CONTENT_PIN_REMOVE = 'content.pin.remove',
CONTENT_STOP_LISTENERS = 'content.stop.listeners',
CONTENT_TAKE_SCREENSHOT = 'content.take.screenshot',
CONTENT_FETCH_PDF = 'content.fetch.pdf',
CONTENT_THEME = 'content.theme',
// Iframe content script
IFRAME_INDEX = 'iframe.index',

View File

@ -42,9 +42,8 @@ export interface FetchCssRequest {
url: string;
}
export interface FetchImageRequest {
url: string;
}
export type FetchImageRequest = FetchCssRequest;
export type FetchPDFRequest = FetchCssRequest;
export interface ExtensionPopupInitData {
isAdding: boolean;

View File

@ -0,0 +1,34 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2023 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ObjCommentListDto } from './obj-comment.dto';
import { ObjUrlDto } from './obj.dto';
export type ObjBinaryType = 'PDF' | 'IMAGE';
export interface ObjBinaryDataDto {
type: ObjBinaryType;
hash: string;
data: string;
}
export interface ObjBinaryDto {
hash: string;
url?: ObjUrlDto;
words?: string[];
hashtags?: string[];
comments?: ObjCommentListDto;
}

View File

@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ObjBinaryDto } from './obj-binary.dto';
import { ObjNoteDto } from './obj-note.dto';
import { ObjPageDto } from './obj-page.dto';
import { ObjPinDto } from './obj-pin.dto';
@ -41,10 +42,11 @@ export enum ObjTypeDto {
Note = 'Note',
PageAlter = 'PAGE_ALTER',
PageTask = 'PAGE_TASK',
PageEvent = 'PAGE_EVENT'
Pdf = 'PDF',
Image = 'IMAGE'
}
export type ObjDataDto = ObjPageDto | ObjNoteDto | ObjPinDto;
export type ObjDataDto = ObjPageDto | ObjNoteDto | ObjPinDto | ObjBinaryDto;
export type ObjPageDataDto = ObjPinDto | ObjPageDto | ObjNoteDto | ObjTaskDto;
export interface ObjDto<T = ObjDataDto> {

View File

@ -24,7 +24,7 @@ export class LogManager {
static log = (value: string): void => {
this.logValue = '<span>' + value + '</span><br />' + this.logValue;
fnConsoleLog(value);
TinyDispatcher.dispatch(BusMessageType.POP_CONSOLE_LOG, this.logValue);
TinyDispatcher.getInstance().dispatch(BusMessageType.POP_CONSOLE_LOG, this.logValue);
};
static get logs(): string {
@ -33,6 +33,6 @@ export class LogManager {
static clear(): void {
this.logValue = '';
TinyDispatcher.dispatch(BusMessageType.POP_CONSOLE_LOG, this.logValue);
TinyDispatcher.getInstance().dispatch(BusMessageType.POP_CONSOLE_LOG, this.logValue);
}
}

View File

@ -20,6 +20,7 @@ import { ICommand } from '../../../common/model/shared/common.dto';
import { IFrameFetchMessage } from '../../../common/model/iframe-message.model';
import { IFrameStore } from '../../store/iframe.store';
import { PageSegmentAddCommand } from '../../../common/command/snapshot/segment/page-segment-add.command';
import { TinyDispatcher } from '@pinmenote/tiny-dispatcher';
import { fnConsoleLog } from '../../../common/fn/fn-console';
import { fnIframeIndex } from '../../../common/fn/fn-iframe-index';
@ -37,8 +38,13 @@ export class ContentFetchIframeCommand implements ICommand<Promise<void>> {
'children',
document.body.children.length
);
const snapshot = await PageCompute.compute(document.body, this.contentCallback, IFrameStore.getInstance(), []);
const snapshot = await PageCompute.compute(
document.body,
this.contentCallback,
IFrameStore.getInstance(),
[],
TinyDispatcher.getInstance()
);
const dto: SegmentPage = {
html: snapshot.content.html,

View File

@ -20,6 +20,7 @@ import { HtmlConstraints } from '../../factory/html/html.constraints';
import { ICommand } from '../../../common/model/shared/common.dto';
import { IFrameStore } from '../../store/iframe.store';
import { PageSegmentAddCommand } from '../../../common/command/snapshot/segment/page-segment-add.command';
import { TinyDispatcher } from '@pinmenote/tiny-dispatcher';
import { fnConsoleLog } from '../../../common/fn/fn-console';
interface SnapshotResult {
@ -40,7 +41,8 @@ export class ContentPageSegmentSaveCommand implements ICommand<Promise<SnapshotR
this.element,
this.contentCallback,
IFrameStore.getInstance(),
skipAttributes
skipAttributes,
TinyDispatcher.getInstance()
);
await this.contentCallback(snapshot);
const words = AutoTagMediator.computeTags(this.element);

View File

@ -18,6 +18,7 @@ import { ObjTypeDto, ObjUrlDto } from '../../../common/model/obj/obj.dto';
import { BrowserApi } from '@pinmenote/browser-api';
import { BusMessageType } from '../../../common/model/bus.model';
import { ContentPageSnapshotCreateCommand } from './content-page-snapshot-create.command';
import { ContentPdfSaveCommand } from './content-pdf-save.command';
import { ICommand } from '../../../common/model/shared/common.dto';
import { PageSnapshotAddCommand } from '../../../common/command/snapshot/page-snapshot-add.command';
import { PinStore } from '../../store/pin.store';
@ -27,16 +28,21 @@ export class ContentPageSnapshotAddCommand implements ICommand<Promise<void>> {
constructor(private settings: SettingsConfig, private url: ObjUrlDto) {}
async execute(): Promise<void> {
const pageSnapshot = await new ContentPageSnapshotCreateCommand(
this.settings,
this.url,
document.body,
[],
undefined
).execute();
await new PageSnapshotAddCommand(pageSnapshot, ObjTypeDto.PageSnapshot).execute();
if (this.url.href.endsWith('.pdf')) {
await new ContentPdfSaveCommand(this.url).execute();
await BrowserApi.sendRuntimeMessage({ type: BusMessageType.POPUP_PAGE_SNAPSHOT_ADD });
} else {
const pageSnapshot = await new ContentPageSnapshotCreateCommand(
this.settings,
this.url,
document.body,
[],
undefined
).execute();
await new PageSnapshotAddCommand(pageSnapshot, ObjTypeDto.PageSnapshot).execute();
await BrowserApi.sendRuntimeMessage({ type: BusMessageType.POPUP_PAGE_SNAPSHOT_ADD });
PinStore.each((v) => v.show());
await BrowserApi.sendRuntimeMessage({ type: BusMessageType.POPUP_PAGE_SNAPSHOT_ADD });
PinStore.each((v) => v.show());
}
}
}

View File

@ -0,0 +1,25 @@
import { BrowserApi } from '@pinmenote/browser-api';
import { BusMessageType } from '../../../common/model/bus.model';
import { FetchPDFRequest } from '../../../common/model/obj-request.model';
import { FetchResponse } from '@pinmenote/fetch-service';
import { ICommand } from '../../../common/model/shared/common.dto';
import { ObjUrlDto } from '../../../common/model/obj/obj.dto';
import { TinyDispatcher } from '@pinmenote/tiny-dispatcher';
import { fnConsoleLog } from '../../../common/fn/fn-console';
export class ContentPdfSaveCommand implements ICommand<Promise<void>> {
constructor(private url: ObjUrlDto) {}
async execute(): Promise<void> {
const data: FetchPDFRequest = { url: this.url.href };
TinyDispatcher.getInstance().addListener<FetchResponse<string>>(
BusMessageType.CONTENT_FETCH_PDF,
(event, key, value) => {
if (value.url === this.url.href) {
TinyDispatcher.getInstance().removeListener(event, key);
fnConsoleLog('GOT PDF BUT MAYBE JUST SAVE IT INSIDE SERVICE WORKER!!!', value);
}
}
);
await BrowserApi.sendRuntimeMessage({ type: BusMessageType.CONTENT_FETCH_PDF, data });
}
}

View File

@ -40,7 +40,7 @@ export class ContentMessageHandler {
this.iframe = iframe;
this.uid = uid;
BrowserApi.runtime.onMessage.addListener(this.handleMessage);
TinyDispatcher.addListener(BusMessageType.POPUP_OPEN, this.handlePopupOpen);
TinyDispatcher.getInstance().addListener(BusMessageType.POPUP_OPEN, this.handlePopupOpen);
}
static updateHref(href: string): void {
@ -60,7 +60,7 @@ export class ContentMessageHandler {
runtime: BrowserGlobalSender,
sendResponse: (response: BusMessage<undefined>) => void
): Promise<void> => {
// fnConsoleLog('ContentMessageHandler->handleMessage', this.href, msg);
fnConsoleLog('ContentMessageHandler->handleMessage', this.href, msg, this.iframe);
sendResponse({
type: BusMessageType.CONTENT_ACK
});
@ -69,7 +69,6 @@ export class ContentMessageHandler {
case BusMessageType.IFRAME_INDEX_REGISTER:
case BusMessageType.IFRAME_PIN_SEND:
case BusMessageType.IFRAME_PIN_SHOW:
case PageComputeMessage.IFRAME_PING:
case BusMessageType.IFRAME_START_LISTENERS:
case BusMessageType.IFRAME_START_LISTENERS_RESULT:
case BusMessageType.IFRAME_STOP_LISTENERS:
@ -106,7 +105,7 @@ export class ContentMessageHandler {
new PinVisibleCommand(msg.data).execute();
break;
default:
TinyDispatcher.dispatch(msg.type, msg.data);
TinyDispatcher.getInstance().dispatch(msg.type, msg.data);
break;
}
};

View File

@ -47,12 +47,12 @@ class PinMeScript {
document.addEventListener('visibilitychange', this.handleVisibilityChange);
TinyDispatcher.addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings);
TinyDispatcher.dispatch(BusMessageType.CNT_SETTINGS, {});
TinyDispatcher.getInstance().addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings);
TinyDispatcher.getInstance().dispatch(BusMessageType.CNT_SETTINGS, {});
}
private handlePinSettings = async (event: string, key: string): Promise<void> => {
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().removeListener(event, key);
await ContentSettingsStore.initSettings();
@ -106,7 +106,7 @@ class PinMeScript {
private cleanup(): void {
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
TinyDispatcher.cleanup();
TinyDispatcher.getInstance().cleanup();
DocumentMediator.stopListeners();
PinStore.clear();
ContentMessageHandler.cleanup();

View File

@ -47,7 +47,7 @@ export class IFrameMessageHandler {
if (iframe && msg.data.uid === uid && href) {
await new ContentFetchIframeCommand(href, uid, msg.data.depth).execute();
} else {
TinyDispatcher.dispatch(msg.type, msg.data);
TinyDispatcher.getInstance().dispatch(msg.type, msg.data);
}
break;
}
@ -66,12 +66,6 @@ export class IFrameMessageHandler {
IFrameStore.resumeListeners(msg.data);
break;
}
case PageComputeMessage.IFRAME_PING: {
if (iframe && msg.data.uid === uid) {
await BrowserApi.sendRuntimeMessage({ type: PageComputeMessage.IFRAME_PING_RESULT, data: msg.data });
}
break;
}
case BusMessageType.IFRAME_PIN_SEND: {
const index = fnIframeIndex();
if (msg.data.data.data.iframe && index === msg.data.data.data.iframe.index) {
@ -86,7 +80,7 @@ export class IFrameMessageHandler {
break;
}
default:
TinyDispatcher.dispatch(msg.type, msg.data);
TinyDispatcher.getInstance().dispatch(msg.type, msg.data);
break;
}
};

View File

@ -75,13 +75,13 @@ export class DocumentMediator {
}
fnConsoleLog('DocumentMediator->startIframeListeners', msg, this.baseUrl, this.iframe);
const key = TinyDispatcher.addListener<IFrameIndexMessage>(
const key = TinyDispatcher.getInstance().addListener<IFrameIndexMessage>(
BusMessageType.IFRAME_START_LISTENERS_RESULT,
(event, key, value) => {
if (msg.uid === value.uid) {
fnConsoleLog('DocumentMediator->startIframeListeners->IFRAME_START_LISTENERS_RESULT');
clearTimeout(timeout);
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().removeListener(event, key);
this.stopListeners(false);
this.startingIframeListeners = false;
IFrameStore.passListeners(msg);
@ -102,7 +102,7 @@ export class DocumentMediator {
const timeout = setTimeout(() => {
fnConsoleLog('DocumentMediator->startIframeListeners->timeout');
this.startingIframeListeners = false;
TinyDispatcher.removeListener(BusMessageType.IFRAME_START_LISTENERS_RESULT, key);
TinyDispatcher.getInstance().removeListener(BusMessageType.IFRAME_START_LISTENERS_RESULT, key);
}, 1000);
}

View File

@ -41,17 +41,17 @@ export const AccountDetailsComponent: FunctionComponent<AccountDetailsComponentP
if (PopupTokenStore.token) {
setTokenData(jwtDecode<TokenDataDto>(PopupTokenStore.token.access_token));
}
const loginSuccessKey = TinyDispatcher.addListener(
const loginSuccessKey = TinyDispatcher.getInstance().addListener(
BusMessageType.POPUP_LOGIN_SUCCESS,
async (event, key, value) => {
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().removeListener(event, key);
await PopupTokenStore.init();
if (PopupTokenStore.token) setTokenData(jwtDecode<TokenDataDto>(PopupTokenStore.token.access_token));
// TODO upload keys ???
LogManager.log(`${JSON.stringify(value)}`);
}
);
const logoutKey = TinyDispatcher.addListener<FetchResponse<BoolDto | ServerErrorDto>>(
const logoutKey = TinyDispatcher.getInstance().addListener<FetchResponse<BoolDto | ServerErrorDto>>(
BusMessageType.POPUP_LOGOUT,
(event, key, value) => {
LogManager.log('POPUP_LOGOUT_RESPONSE');
@ -63,8 +63,8 @@ export const AccountDetailsComponent: FunctionComponent<AccountDetailsComponentP
}
);
return () => {
TinyDispatcher.removeListener(BusMessageType.POPUP_LOGIN_SUCCESS, loginSuccessKey);
TinyDispatcher.removeListener(BusMessageType.POPUP_LOGOUT, logoutKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POPUP_LOGIN_SUCCESS, loginSuccessKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POPUP_LOGOUT, logoutKey);
};
}, []);

View File

@ -51,7 +51,7 @@ export const LoginComponent: FunctionComponent<LoginComponentProps> = ({ loginSu
const [responseError, setResponseError] = useState<ServerErrorDto | undefined>(undefined);
useEffect(() => {
const loginKey = TinyDispatcher.addListener<FetchResponse<AccessTokenDto>>(
const loginKey = TinyDispatcher.getInstance().addListener<FetchResponse<AccessTokenDto>>(
BusMessageType.POPUP_LOGIN,
(event, key, value) => {
LogManager.log(`POPUP_LOGIN: ${JSON.stringify(value)}`);
@ -63,7 +63,7 @@ export const LoginComponent: FunctionComponent<LoginComponentProps> = ({ loginSu
}
);
return () => {
TinyDispatcher.removeListener(BusMessageType.POPUP_LOGIN, loginKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POPUP_LOGIN, loginKey);
};
}, []);

View File

@ -51,7 +51,7 @@ export const Verify2faComponent: FunctionComponent<Verify2faComponentProps> = ({
const [responseError, setResponseError] = useState<ServerErrorDto | undefined>(undefined);
useEffect(() => {
const loginKey = TinyDispatcher.addListener<FetchResponse<AccessTokenDto>>(
const loginKey = TinyDispatcher.getInstance().addListener<FetchResponse<AccessTokenDto>>(
BusMessageType.POPUP_VERIFY_2FA,
(event, key, value) => {
LogManager.log(`POPUP_LOGIN: ${JSON.stringify(value)}`);
@ -63,7 +63,7 @@ export const Verify2faComponent: FunctionComponent<Verify2faComponentProps> = ({
}
);
return () => {
TinyDispatcher.removeListener(BusMessageType.POPUP_VERIFY_2FA, loginKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POPUP_VERIFY_2FA, loginKey);
};
}, []);

View File

@ -37,11 +37,14 @@ export const MainHeaderComponent: FunctionComponent<CreateComponentProps> = (pro
const [isAdding, setIsAdding] = useState<boolean>(PopupActiveTabStore.isAdding);
useEffect(() => {
const addKey = TinyDispatcher.addListener<boolean>(BusMessageType.POP_IS_ADDING, (event, key, value) => {
setIsAdding(value);
});
const addKey = TinyDispatcher.getInstance().addListener<boolean>(
BusMessageType.POP_IS_ADDING,
(event, key, value) => {
setIsAdding(value);
}
);
return () => {
TinyDispatcher.removeListener(BusMessageType.POP_IS_ADDING, addKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POP_IS_ADDING, addKey);
};
}, []);
const handleNewPin = async () => {

View File

@ -57,13 +57,13 @@ export const MainMenuListComponent: FunctionComponent<CreateListProps> = (props)
const [isLoading, setIsLoading] = useState<IsLoadingType>(IsLoadingType.None);
const handleSavePageClick = async () => {
TinyDispatcher.addListener<string>(BusMessageType.POPUP_PAGE_SNAPSHOT_ADD, (event, key) => {
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().addListener<string>(BusMessageType.POPUP_PAGE_SNAPSHOT_ADD, (event, key) => {
TinyDispatcher.getInstance().removeListener(event, key);
setIsLoading(IsLoadingType.None);
setTimeout(() => props.closeListCallback(MainViewEnum.PAGE_OBJECTS), 100);
});
await BrowserApi.sendTabMessage({ type: BusMessageType.POPUP_PAGE_SNAPSHOT_ADD, data: PopupActiveTabStore.url });
setIsLoading(IsLoadingType.PageSave);
await BrowserApi.sendTabMessage({ type: BusMessageType.POPUP_PAGE_SNAPSHOT_ADD, data: PopupActiveTabStore.url });
};
const handleSaveElementClick = async (): Promise<void> => {

View File

@ -38,11 +38,11 @@ export const ObjViewComponent: FunctionComponent<ObjViewComponent> = (props) =>
(async () => {
await initUrl();
})();
const urlKey = TinyDispatcher.addListener(BusMessageType.POP_UPDATE_URL, async () => {
const urlKey = TinyDispatcher.getInstance().addListener(BusMessageType.POP_UPDATE_URL, async () => {
await initUrl();
});
return () => {
TinyDispatcher.removeListener(BusMessageType.POP_UPDATE_URL, urlKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POP_UPDATE_URL, urlKey);
};
}, []);

View File

@ -53,6 +53,16 @@ export const SnapshotListElement: FunctionComponent<SnapshotListElementProps> =
setIsExpanded(!isExpanded);
};
const handleOpenPage = (data: ObjDto<ObjPageDto>): void => {
if (BrowserApi.isChrome) {
BrowserApi.openOptionsPage(`#obj/${data.id}`);
} else {
// TODO change to BrowserApi 0.0.5
window.open(`${browser.runtime.getManifest().options_ui?.page || ''}#obj/${data.id}`);
window.close();
}
};
const expandIcon = isExpanded ? (
<ExpandMoreIcon sx={{ fontSize: '12px' }} />
) : (
@ -93,11 +103,7 @@ export const SnapshotListElement: FunctionComponent<SnapshotListElementProps> =
justifyContent: 'flex-end'
}}
>
<IconButton
title="Show on pin board"
size="small"
onClick={() => BrowserApi.openOptionsPage(`#obj/${props.obj.id}`)}
>
<IconButton title="Show on pin board" size="small" onClick={() => handleOpenPage(props.obj)}>
<PushPinIcon sx={{ fontSize: '12px' }} />
</IconButton>
<IconButton title="Go to page" size="small" onClick={() => handleNavigate(props.obj)}>

View File

@ -28,11 +28,14 @@ export const LogsTabComponent: FunctionComponent = () => {
useEffect(() => {
if (ref.current) ref.current.innerHTML = LogManager.logs;
const key = TinyDispatcher.addListener<string>(BusMessageType.POP_CONSOLE_LOG, (event, key, value) => {
if (ref.current) ref.current.innerHTML = value;
});
const key = TinyDispatcher.getInstance().addListener<string>(
BusMessageType.POP_CONSOLE_LOG,
(event, key, value) => {
if (ref.current) ref.current.innerHTML = value;
}
);
return () => {
TinyDispatcher.removeListener(BusMessageType.POP_CONSOLE_LOG, key);
TinyDispatcher.getInstance().removeListener(BusMessageType.POP_CONSOLE_LOG, key);
};
}, []);

View File

@ -25,11 +25,11 @@ export const MainTabComponent: FunctionComponent = () => {
const [isError, setIsError] = useState<boolean>(PopupActiveTabStore.showErrorText);
useEffect(() => {
const urlKey = TinyDispatcher.addListener(BusMessageType.POP_UPDATE_URL, () => {
const urlKey = TinyDispatcher.getInstance().addListener(BusMessageType.POP_UPDATE_URL, () => {
setIsError(PopupActiveTabStore.showErrorText);
});
return () => {
TinyDispatcher.removeListener(BusMessageType.POP_UPDATE_URL, urlKey);
TinyDispatcher.getInstance().removeListener(BusMessageType.POP_UPDATE_URL, urlKey);
};
}, []);

View File

@ -34,7 +34,7 @@ export class PopupMessageHandler {
}
private static popupInitListener(): void {
TinyDispatcher.addListener<ExtensionPopupInitData>(BusMessageType.POPUP_INIT, (event, key, value) => {
TinyDispatcher.getInstance().addListener<ExtensionPopupInitData>(BusMessageType.POPUP_INIT, (event, key, value) => {
PopupActiveTabStore.updateState(value);
});
}
@ -50,6 +50,6 @@ export class PopupMessageHandler {
// Skip not owned messages
if (runtime.id !== BrowserApi.runtime.id) return;
TinyDispatcher.dispatch(msg.type, msg.data);
TinyDispatcher.getInstance().dispatch(msg.type, msg.data);
};
}

View File

@ -69,7 +69,7 @@ export class PopupActiveTabStore {
} else if (this.urlValue?.href.startsWith(BrowserApi.disabledUrl)) {
this.isError = true;
}
TinyDispatcher.dispatch<void>(BusMessageType.POP_UPDATE_URL);
TinyDispatcher.getInstance().dispatch<void>(BusMessageType.POP_UPDATE_URL);
}
};
@ -77,7 +77,7 @@ export class PopupActiveTabStore {
LogManager.log(`PopupActiveTabStore->INIT - ${JSON.stringify(initData || {})}`);
if (initData?.isAdding) {
this.isAddingValue = true;
TinyDispatcher.dispatch<boolean>(BusMessageType.POP_IS_ADDING, this.isAddingValue);
TinyDispatcher.getInstance().dispatch<boolean>(BusMessageType.POP_IS_ADDING, this.isAddingValue);
}
};
}

View File

@ -46,12 +46,12 @@ export class IframeScript {
document.addEventListener('visibilitychange', this.handleVisibilityChange);
document.addEventListener('mouseout', this.handleMouseOut);
TinyDispatcher.addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings);
TinyDispatcher.dispatch(BusMessageType.CNT_SETTINGS, {});
TinyDispatcher.getInstance().addListener<number[]>(BusMessageType.CNT_SETTINGS, this.handlePinSettings);
TinyDispatcher.getInstance().dispatch(BusMessageType.CNT_SETTINGS, {});
}
private handlePinSettings = async (event: string, key: string): Promise<void> => {
TinyDispatcher.removeListener(event, key);
TinyDispatcher.getInstance().removeListener(event, key);
await ContentSettingsStore.initSettings();
};
@ -91,7 +91,7 @@ export class IframeScript {
private cleanup(): void {
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
document.removeEventListener('mouseout', this.handleMouseOut);
TinyDispatcher.cleanup();
TinyDispatcher.getInstance().cleanup();
DocumentMediator.stopListeners();
ContentMessageHandler.cleanup();
clearTimeout(this.timeoutId);

View File

@ -23,7 +23,7 @@ import { fnConsoleLog } from '../common/fn/fn-console';
export class OptionsMessageHandler {
static init(): void {
BrowserApi.runtime.onMessage.addListener(this.handleRemoteMessage);
TinyDispatcher.addListener(BusMessageType.POPUP_OPEN, this.handlePopupOpen);
TinyDispatcher.getInstance().addListener(BusMessageType.POPUP_OPEN, this.handlePopupOpen);
}
private static handleRemoteMessage = (
@ -35,7 +35,7 @@ export class OptionsMessageHandler {
sendResponse({
type: BusMessageType.CONTENT_ACK
});
TinyDispatcher.dispatch(msg.type, msg.data);
TinyDispatcher.getInstance().dispatch(msg.type, msg.data);
};
private static handlePopupOpen = async (): Promise<void> => {

View File

@ -26,7 +26,7 @@ export class ContentFetchImageCommand implements ICommand<Promise<void>> {
constructor(private req: FetchImageRequest) {}
async execute(): Promise<void> {
try {
// fnConsoleLog('ContentFetchImageCommand->execute', this.req.url);
fnConsoleLog('ContentFetchImageCommand->execute', this.req.url);
const req = await FetchService.fetch<Blob>(this.req.url, {
type: 'BLOB'
});

View File

@ -0,0 +1,54 @@
/*
* This file is part of the pinmenote-extension distribution (https://github.com/pinmenote/pinmenote-extension).
* Copyright (c) 2023 Michal Szczepanski.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { FetchResponse, FetchService } from '@pinmenote/fetch-service';
import { BrowserApi } from '@pinmenote/browser-api';
import { BusMessageType } from '../../../common/model/bus.model';
import { FetchPDFRequest } from '../../../common/model/obj-request.model';
import { ICommand } from '../../../common/model/shared/common.dto';
import { UrlFactory } from '../../../common/factory/url.factory';
import { fnConsoleLog } from '../../../common/fn/fn-console';
export class ContentFetchPDFCommand implements ICommand<Promise<void>> {
constructor(private req: FetchPDFRequest) {}
async execute(): Promise<void> {
try {
// fnConsoleLog('ContentFetchImageCommand->execute', this.req.url);
const req = await FetchService.fetch<Blob>(this.req.url, {
type: 'BLOB'
});
const data = await UrlFactory.toDataUri(req.data);
const ok = req.ok;
fnConsoleLog('ContentFetchImageCommand->result', this.req.url, data);
await BrowserApi.sendTabMessage<FetchResponse<string>>({
type: BusMessageType.CONTENT_FETCH_PDF,
data: { data, ok, url: req.url, status: req.status, type: req.type }
});
} catch (e) {
fnConsoleLog('ContentFetchImageCommand->ERROR', e, this.req.url);
await BrowserApi.sendTabMessage<FetchResponse<string>>({
type: BusMessageType.CONTENT_FETCH_PDF,
data: {
url: this.req.url,
ok: false,
status: 500,
type: 'BLOB',
data: ''
}
});
}
}
}

View File

@ -19,6 +19,7 @@ import { BusMessageType } from '../common/model/bus.model';
import { ContentDownloadDataCommand } from './command/content/content-download-data.command';
import { ContentFetchCssCommand } from './command/content/content-fetch-css.command';
import { ContentFetchImageCommand } from './command/content/content-fetch-image.command';
import { ContentFetchPDFCommand } from './command/content/content-fetch-pdf.command';
import { ContentInvalidateCommand } from './command/content/content-invalidate.command';
import { ContentPinStopCommand } from './command/content/content-pin-stop.command';
import { ContentTakeScreenshotCommand } from './command/content/content-take-screenshot.command';
@ -69,6 +70,9 @@ const handleMessage = async (
case PageComputeMessage.CONTENT_FETCH_IMAGE:
await new ContentFetchImageCommand(msg.data).execute();
break;
case BusMessageType.CONTENT_FETCH_PDF:
await new ContentFetchPDFCommand(msg.data).execute();
break;
case BusMessageType.POPUP_LOGIN:
await new PopupLoginCommand(msg.data).execute();
break;
@ -92,8 +96,6 @@ const handleMessage = async (
case BusMessageType.IFRAME_MOUSE_OUT:
case BusMessageType.IFRAME_PIN_SEND:
case BusMessageType.IFRAME_PIN_SHOW:
case PageComputeMessage.IFRAME_PING:
case PageComputeMessage.IFRAME_PING_RESULT:
case PageComputeMessage.IFRAME_FETCH:
case PageComputeMessage.IFRAME_FETCH_RESULT: {
await new IframePassMessageCommand(msg).execute();

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2015",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,