Skip to content

Commit

Permalink
chore: add auto defining page language and apply it to popoup tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
Rue-pro committed Apr 17, 2024
1 parent 84b94b4 commit 539d8bd
Show file tree
Hide file tree
Showing 17 changed files with 195 additions and 50 deletions.
10 changes: 5 additions & 5 deletions src/background/features/addNewWord/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { browser } from '@background/shared/browser'
import { TOnClickContextMenuInfoProps } from '@background/shared/browser/contextMenus'
import { currentPageLanguageStore } from '@background/shared/entities/language'

import {
TLanguageCode,
getLanguageCodeByPageUrl,
} from '@shared/entities/language'
import { TLanguageCode } from '@shared/entities/language'
import { $languages } from '@shared/entities/language/model/store'
import { noteStore } from '@shared/entities/note'

export const addNewWord = (parentId: string) => {
currentPageLanguageStore.$currentPageLanguage.listen(() => {})

browser.contextMenus.create({
title: browser.i18n.getMessage('CONTEXT_MENU_ADD_NEW_WORD'),
id: 'new_word',
Expand All @@ -19,7 +19,7 @@ export const addNewWord = (parentId: string) => {
const handleClick = async (info: TOnClickContextMenuInfoProps) => {
if (info.menuItemId === 'new_word') {
let finalLanguageCode: TLanguageCode = 'other'
const languageCode = getLanguageCodeByPageUrl(info.pageUrl)
const languageCode = currentPageLanguageStore.$currentPageLanguage.get()
const text = info.selectionText ?? ''

finalLanguageCode =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { atom, computed, onMount } from 'nanostores'

import { browser } from '@background/shared/browser'

import {
getLanguageFromPage,
getLanguageFromPageResult,
} from '@shared/features/note/AutoAddNewNote'

import { TLanguageCode } from '@shared/entities/language'
import { $notes } from '@shared/entities/note/model/store'
import { $activeTab } from '@shared/entities/tab'

import { PortEmitter } from '@shared/shared/browser/port'
import { TTab } from '@shared/shared/browser/tabs'

export const $currentPageLanguage = atom<TLanguageCode>('other')

onMount($currentPageLanguage, () => {
function getLanguage(activeTab: TTab) {
if (activeTab.url.includes('chrome://')) return

const port = new PortEmitter({
tabId: activeTab.id,
connectInfo: { name: 'CurrentPage' },
})

getLanguageFromPage(port)

getLanguageFromPageResult(port, (languageCode) => {
$currentPageLanguage.set(languageCode)
})
}

const activeTab = $activeTab.get()
if (activeTab) getLanguage(activeTab)

browser.tabs.onActivated.addListener((activeTab) => {
if (activeTab.data) getLanguage(activeTab.data)
})
})

export const $latestNote = computed(
[$currentPageLanguage, $notes],
(currentPageLanguage, notes) => {
return notes[currentPageLanguage][0]
},
)
1 change: 1 addition & 0 deletions src/background/shared/entities/language/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as currentPageLanguageStore from './currentPageLanguageStore'
26 changes: 26 additions & 0 deletions src/content/dictionary/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,36 @@ import {
} from '@shared/features/note/AutoAddNewNote'

import { GOOGLE_TRANSLATE } from '@shared/entities/dictionary'
import {
TLanguageCode,
getLanguageCodeByPageMetaData,
getLanguageCodeByPageUrl,
} from '@shared/entities/language'
import { $languages } from '@shared/entities/language/model/store'

import { getNotesFields } from './helpers/getNotesFields'

$languages.listen(() => {})

browser.runtime.onConnect.addListener(async function (port) {
if (port.name === 'CurrentPage') {
getLanguageFromPageHandler(port, () => {
let pageLanguage: TLanguageCode = 'other'
const isTranslatorPage = window.location.href.includes(
GOOGLE_TRANSLATE.url,
)
if (isTranslatorPage) {
pageLanguage = GOOGLE_TRANSLATE.getLanguage()
} else {
pageLanguage = getLanguageCodeByPageUrl(window.location.href)
if (pageLanguage === 'other') {
pageLanguage = getLanguageCodeByPageMetaData()
}
}
return pageLanguage
})
}

if (port.name === 'Dictionary') {
getNoteFromDictionaryPageHandler(port, (selectors) =>
getNotesFields(selectors),
Expand Down
1 change: 1 addition & 0 deletions src/popup/entities/language/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './model'
30 changes: 30 additions & 0 deletions src/popup/entities/language/model/currentPageLanguageStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { computed, task } from 'nanostores'

import {
getLanguageFromPage,
getLanguageFromPageResult,
} from '@shared/features/note/AutoAddNewNote'

import { TLanguageCode } from '@shared/entities/language'
import { $activeTab } from '@shared/entities/tab'

import { PortEmitter } from '@shared/shared/browser/port'

export const $currentPageLanguage = computed($activeTab, (activeTab) => {
return task(async (): Promise<TLanguageCode> => {
if (!activeTab?.id || activeTab.url.includes('chrome://')) return 'other'

const port = new PortEmitter({
tabId: activeTab.id,
connectInfo: { name: 'CurrentPage' },
})

getLanguageFromPage(port)

return new Promise((resolve) => {
getLanguageFromPageResult(port, (languageCode) => {
resolve(languageCode)
})
})
})
})
1 change: 1 addition & 0 deletions src/popup/entities/language/model/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as currentLanguagePageStore from './currentPageLanguageStore'
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useStore } from '@nanostores/preact'
import { NoSelectedLanguages } from '@popup/features/language/SelectLanguages'

import { DictionaryCard } from '@popup/entities/dictionary'
import { currentLanguagePageStore } from '@popup/entities/language'

import { Tab, TabPanel, Tabs, TabsList, a11yProps } from '@popup/shared/ui/Tabs'

Expand All @@ -15,12 +16,15 @@ import styles from './styles.module.scss'
export const SelectDictionaryList = () => {
const dictionaries = useStore(dictionaryStore.$dictionaries)
const languages = useStore(languageStore.$languages)
const currentPageLanguage = useStore(
currentLanguagePageStore.$currentPageLanguage,
)

return (
<>
{languages.length ? (
<>
<Tabs>
<Tabs defaultValue={currentPageLanguage}>
<TabsList arrows={true}>
{languages.map((language) => (
<Tab
Expand Down
2 changes: 1 addition & 1 deletion src/popup/features/note/FillFlashcardForm/model/store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { computed } from 'nanostores'

import { $activeTab } from '@popup/entities/tab'
import { $activeTab } from '@shared/entities/tab'

import { IPortEmitter, PortEmitter } from '@shared/shared/browser/port'

Expand Down
6 changes: 5 additions & 1 deletion src/popup/shared/ui/Tabs/ui/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ComponentChildren, createContext } from 'preact'
import { useContext, useState } from 'preact/hooks'
import { useContext, useEffect, useState } from 'preact/hooks'

import { TTabValue } from '../model/types'

Expand All @@ -21,6 +21,10 @@ interface Props {
export const Tabs = ({ children, defaultValue, value, onChange }: Props) => {
const [currentTab, setCurrentTab] = useState<TTabValue>(defaultValue ?? null)

useEffect(() => {
defaultValue && setCurrentTab(defaultValue)
}, [defaultValue])

return (
<TabsContext.Provider
value={{
Expand Down
6 changes: 5 additions & 1 deletion src/popup/widgets/note/NoteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
FillFlashcardFormNotAvailable,
} from '@popup/features/note/FillFlashcardForm'

import { currentLanguagePageStore } from '@popup/entities/language'
import { NoNotes, NoteCard } from '@popup/entities/note'

import { browser } from '@popup/shared/browser'
Expand All @@ -27,6 +28,9 @@ export const NoteList = () => {
const ankiPort = useStore($ankiPort)
const languages = useStore(languageStore.$languages)
const notes = useStore(noteStore.$notes)
const currentPageLanguage = useStore(
currentLanguagePageStore.$currentPageLanguage,
)

const [editNote, setEditNote] = useState<{
lang: TLanguageCode
Expand All @@ -39,7 +43,7 @@ export const NoteList = () => {
{!ankiPort && <FillFlashcardFormNotAvailable />}
{languages.length ? (
<>
<Tabs>
<Tabs defaultValue={currentPageLanguage}>
<TabsList arrows={true}>
{languages.map((language) => (
<Tab
Expand Down
19 changes: 19 additions & 0 deletions src/shared/entities/language/model/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getDictionaryByPageUrl } from '@shared/entities/dictionary'

import { languageStore } from '..'
import { TLanguageCode } from './types'

export const getLanguageCodeByPageUrl = (url: string): TLanguageCode => {
const dictionary = getDictionaryByPageUrl(url)
return dictionary ? dictionary.languageCode : 'other'
}

export const getLanguageCodeByPageMetaData = () => {
const pageLanguageCode = document
.getElementsByTagName('html')[0]
.getAttribute('lang') as TLanguageCode

return languageStore.$languageCodes.get().includes(pageLanguageCode)
? pageLanguageCode
: 'other'
}
28 changes: 1 addition & 27 deletions src/shared/entities/language/model/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,4 @@
import { DICTIONARIES } from '@shared/entities/dictionary'

import { TLanguageCode } from './types'

export type { TLanguageCode, ILanguage } from './types'
export { LANGUAGES, LANGUAGE_CODES } from './languages'
export * as languageStore from './store'

export const getLanguageCodeByPageUrl = (url: string): TLanguageCode => {
const languages = Object.entries(DICTIONARIES)

let languageIndex = 0
while (languageIndex < languages.length) {
const languageDictionaries = languages[languageIndex][1].dictionaries

let dictionaryIndex = 0
while (dictionaryIndex < languageDictionaries.length) {
const dictionary = languageDictionaries[dictionaryIndex]

if (url.includes(dictionary.url)) {
return languages[languageIndex][1].value
}

dictionaryIndex++
}
languageIndex++
}

return 'other'
}
export * from './helpers'
5 changes: 4 additions & 1 deletion src/shared/entities/language/model/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { atom, onMount, task } from 'nanostores'
import { atom, computed, onMount, task } from 'nanostores'

import { browser } from '@popup/shared/browser'

Expand All @@ -14,6 +14,9 @@ type StorageValue = ILanguage[]
export const LanguageStorage = getStorage<StorageValue>('languages', LANGUAGES)

export const $languages = atom<StorageValue>(LANGUAGES)
export const $languageCodes = computed($languages, (languages) => {
return languages.map((language) => language.value)
})

onMount($languages, () => {
task(async () => {
Expand Down
File renamed without changes.
52 changes: 39 additions & 13 deletions src/shared/shared/browser/tabs/chromeTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,45 @@ import { ITabs } from './types'
export const chromeTabs: ITabs = {
getActiveTab: () => {
return new Promise((resolve) => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
const tab = tabs[0]
if (tab?.id && tab?.url) {
resolve(Result.Success({ id: tab.id, url: tab.url }))
} else {
resolve(
Result.Error({
type: 'ERROR_CAN_NOT_GET_ACTIVE_TAB',
error: null,
}),
)
}
})
chrome.tabs.query(
{ active: true, currentWindow: true, status: 'complete' },
function (tabs) {
const tab = tabs[0]
if (tab?.id && tab?.url) {
resolve(Result.Success({ id: tab.id, url: tab.url }))
} else {
resolve(
Result.Error({
type: 'ERROR_CAN_NOT_GET_ACTIVE_TAB',
error: null,
}),
)
}
},
)
})
},

onActivated: {
addListener: (callback) => {
chrome.tabs.onActivated.addListener(async () => {
chrome.tabs.query(
{ active: true, currentWindow: true, status: 'complete' },
function (tabs) {
const tab = tabs[0]
if (tab?.id && tab?.url) {
callback(Result.Success({ id: tab.id, url: tab.url }))
} else {
callback(
Result.Error({
type: 'ERROR_CAN_NOT_GET_ACTIVE_TAB_ON_ACTIVATED',
error: null,
}),
)
}
},
)
})
},
},
}
4 changes: 4 additions & 0 deletions src/shared/shared/browser/tabs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { TResult } from '@shared/shared/libs/operationResult'

export interface ITabs {
getActiveTab: () => Promise<TResult<TTab>>

onActivated: {
addListener: (callback: (tab: TResult<TTab>) => void) => void
}
}

export type TTab = { id: number; url: string }

0 comments on commit 539d8bd

Please sign in to comment.