diff --git a/src/api/ContentApi.ts b/src/api/ContentApi.ts deleted file mode 100644 index 88b85c1b..00000000 --- a/src/api/ContentApi.ts +++ /dev/null @@ -1,73 +0,0 @@ -export const Namespace = 'TRY_WORDPRESS'; - -export enum Actions { - EnableHighlighting = 1, - DisableHighlighting, - ImportPost, -} - -export interface Message { - namespace: string; - action: number; - payload: object; -} - -export class ContentApi { - async enableHighlighting(): Promise< void > { - return this.sendMessageToContent( { - action: Actions.EnableHighlighting, - payload: {}, - } ); - } - - async disableHighlighting(): Promise< void > { - return this.sendMessageToContent( { - action: Actions.DisableHighlighting, - payload: {}, - } ); - } - - async importPost( content: string ): Promise< void > { - return this.sendMessageToApp( { - action: Actions.ImportPost, - payload: { content }, - } ); - } - - private async sendMessageToApp( - message: Omit< Message, 'namespace' > - ): Promise< void > { - const messageWithNamespace: Message = { - namespace: Namespace, - action: message.action, - payload: message.payload, - }; - await browser.runtime.sendMessage( messageWithNamespace ); - } - - private async sendMessageToContent( - message: Omit< Message, 'namespace' > - ): Promise< void > { - const currentTabId = await this.getCurrentTabId(); - if ( ! currentTabId ) { - throw Error( 'current tab not found' ); - } - const messageWithNamespace: Message = { - namespace: Namespace, - action: message.action, - payload: message.payload, - }; - await browser.tabs.sendMessage( currentTabId, messageWithNamespace ); - } - - private async getCurrentTabId(): Promise< number | undefined > { - const tabs = await browser.tabs.query( { - currentWindow: true, - active: true, - } ); - if ( tabs.length !== 1 ) { - return; - } - return tabs[ 0 ]?.id; - } -} diff --git a/src/bus/AppBus.ts b/src/bus/AppBus.ts new file mode 100644 index 00000000..68a9b91b --- /dev/null +++ b/src/bus/AppBus.ts @@ -0,0 +1,50 @@ +import { Listener, Message, Namespace } from '@/bus/Message'; + +enum Actions { + ElementClicked = 1, +} + +export const AppBus = { + namespace: `${ Namespace }_APP`, + actions: Actions, + listen, + stopListening, + elementClicked, +}; + +let listener: Listener; + +function listen( list: Listener ) { + stopListening(); + listener = ( message: Message ) => { + if ( message.namespace !== AppBus.namespace ) { + return; + } + list( message ); + }; + browser.runtime.onMessage.addListener( listener ); +} + +function stopListening() { + if ( listener ) { + browser.runtime.onMessage.removeListener( listener ); + } +} + +async function elementClicked( content: string ): Promise< void > { + return sendMessageToApp( { + action: Actions.ElementClicked, + payload: { content }, + } ); +} + +async function sendMessageToApp( + message: Omit< Message, 'namespace' > +): Promise< void > { + const messageWithNamespace: Message = { + namespace: AppBus.namespace, + action: message.action, + payload: message.payload, + }; + await browser.runtime.sendMessage( messageWithNamespace ); +} diff --git a/src/bus/ContentBus.ts b/src/bus/ContentBus.ts new file mode 100644 index 00000000..a4871928 --- /dev/null +++ b/src/bus/ContentBus.ts @@ -0,0 +1,74 @@ +import { Listener, Message, Namespace } from '@/bus/Message'; + +enum Actions { + EnableHighlighting = 1, + DisableHighlighting, +} + +export const ContentBus = { + namespace: `${ Namespace }_CONTENT`, + actions: Actions, + listen, + stopListening, + enableHighlighting, + disableHighlighting, +}; + +let listener: Listener; + +function listen( list: Listener ) { + stopListening(); + listener = ( message: Message ) => { + if ( message.namespace !== ContentBus.namespace ) { + return; + } + list( message ); + }; + browser.runtime.onMessage.addListener( listener ); +} + +function stopListening() { + if ( listener ) { + browser.runtime.onMessage.removeListener( listener ); + } +} + +async function enableHighlighting(): Promise< void > { + return sendMessageToContent( { + action: Actions.EnableHighlighting, + payload: {}, + } ); +} + +async function disableHighlighting(): Promise< void > { + return sendMessageToContent( { + action: Actions.DisableHighlighting, + payload: {}, + } ); +} + +async function sendMessageToContent( + message: Omit< Message, 'namespace' > +): Promise< void > { + const currentTabId = await getCurrentTabId(); + if ( ! currentTabId ) { + throw Error( 'current tab not found' ); + } + const messageWithNamespace: Message = { + namespace: ContentBus.namespace, + action: message.action, + payload: message.payload, + }; + await browser.tabs.sendMessage( currentTabId, messageWithNamespace ); +} + +async function getCurrentTabId(): Promise< number | undefined > { + const tabs = await browser.tabs.query( { + currentWindow: true, + active: true, + } ); + if ( tabs.length !== 1 ) { + return; + } + return tabs[ 0 ]?.id; +} diff --git a/src/bus/Message.ts b/src/bus/Message.ts new file mode 100644 index 00000000..877815a1 --- /dev/null +++ b/src/bus/Message.ts @@ -0,0 +1,9 @@ +export const Namespace = 'TRY_WORDPRESS'; + +export interface Message { + namespace: string; + action: number; + payload: object; +} + +export type Listener = ( message: Message ) => void; diff --git a/src/extension/content.ts b/src/extension/content.ts index 3bb7d52d..5ae9a498 100644 --- a/src/extension/content.ts +++ b/src/extension/content.ts @@ -1,32 +1,27 @@ -import { Actions, ContentApi, Message, Namespace } from '@/api/ContentApi'; +import { Message } from '@/bus/Message'; +import { ContentBus } from '@/bus/ContentBus'; +import { AppBus } from '@/bus/AppBus'; -const contentApi = new ContentApi(); let currentElement: HTMLElement | null = null; -browser.runtime.onMessage.addListener( - ( message: Message, sender, sendResponse ) => { - if ( message.namespace !== Namespace ) { - return; - } - - switch ( message.action ) { - case Actions.EnableHighlighting: - document.body.addEventListener( 'mouseover', onMouseOver ); - document.body.addEventListener( 'mouseout', onMouseOut ); - document.body.addEventListener( 'click', onClick ); - break; - case Actions.DisableHighlighting: - document.body.removeEventListener( 'mouseover', onMouseOver ); - document.body.removeEventListener( 'mouseout', onMouseOut ); - document.body.removeEventListener( 'click', onClick ); - removeStyle(); - break; - default: - console.error( `Unknown action: ${ message.action }` ); - break; - } +ContentBus.listen( ( message: Message ) => { + switch ( message.action ) { + case ContentBus.actions.EnableHighlighting: + document.body.addEventListener( 'mouseover', onMouseOver ); + document.body.addEventListener( 'mouseout', onMouseOut ); + document.body.addEventListener( 'click', onClick ); + break; + case ContentBus.actions.DisableHighlighting: + document.body.removeEventListener( 'mouseover', onMouseOver ); + document.body.removeEventListener( 'mouseout', onMouseOut ); + document.body.removeEventListener( 'click', onClick ); + removeStyle(); + break; + default: + console.error( `Unknown action: ${ message.action }` ); + break; } -); +} ); function onClick( event: MouseEvent ) { event.preventDefault(); @@ -35,7 +30,7 @@ function onClick( event: MouseEvent ) { return; } const content = element.outerHTML.trim(); - void contentApi.importPost( content ); + void AppBus.elementClicked( content ); } function onMouseOver( event: MouseEvent ) { diff --git a/src/ui/flows/blog-post/BlogPostFlow.tsx b/src/ui/flows/blog-post/BlogPostFlow.tsx index 0f2b23bb..762e0422 100644 --- a/src/ui/flows/blog-post/BlogPostFlow.tsx +++ b/src/ui/flows/blog-post/BlogPostFlow.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; -import { ContentApi, Message } from '@/api/ContentApi'; +import { ContentBus } from '@/bus/ContentBus'; +import { Message } from '@/bus/Message'; +import { AppBus } from '@/bus/AppBus'; enum Steps { start = 1, @@ -7,8 +9,6 @@ enum Steps { import, } -const contentApi = new ContentApi(); - export function BlogPostFlow() { const [ currentStep, setCurrentStep ] = useState( Steps.start ); @@ -42,7 +42,7 @@ function Start( props: { onExit: () => void } ) {