diff --git a/src/main.ts b/src/main.ts index 935b616..a408ae2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,6 +26,7 @@ export default class MemodackPlugin extends Plugin { this.addCommand({ id: "translate", name: "Translate", + icon: "languages", editorCallback: (editor) => { register.registerEditor(editor); return register.getTranslateCommandService().getCallback(); diff --git a/src/practice/random.service.ts b/src/practice/random.service.ts index 0448ad8..1d02adb 100644 --- a/src/practice/random.service.ts +++ b/src/practice/random.service.ts @@ -34,9 +34,9 @@ export class RandomService implements IRandomService { } getSegment(text: string, divider: string = ";"): string { - const parts = text.split(divider).map((item) => item.trim()); - const index = Math.floor(Math.random() * parts.length); - return parts[index]; + const items = text.split(divider).map((item) => item.trim()); + const index = Math.floor(Math.random() * items.length); + return items[index]; } getNumbers(maxNumber: number, ignoreNumber: number, count: number): number[] { diff --git a/src/register.ts b/src/register.ts index 4da2290..35089a9 100644 --- a/src/register.ts +++ b/src/register.ts @@ -16,7 +16,6 @@ import { GoogleTranslationService } from "./services/google-translation.service" import { GoogleTtsService } from "./services/google-tts.service"; import { ManifestService } from "./services/manifest.service"; import { type IMppService, MppService } from "./services/mpp.service"; -import { PartsService } from "./services/parts.service"; import { PathsService } from "./services/paths.service"; import { PlayerService } from "./services/player.service"; import { type IRibbonIconService, RibbonIconService } from "./services/ribbon-icon.service"; @@ -27,6 +26,7 @@ import { type ITranslateCommandService, TranslateCommandService } from "./servic import { TranslationService } from "./services/translation.service"; import { TtsService } from "./services/tts.service"; import { VaultService } from "./services/vault.service"; +import { WordsService } from "./services/words.service"; import { WorkspaceService } from "./services/workspace.service"; import type { TMemodackPlugin } from "./types"; @@ -68,7 +68,7 @@ export class Register implements IRegister { ["IConductorService", ConductorService], ["IMppService", MppService], ["ITranslationService", TranslationService], - ["IPartsService", PartsService], + ["IWordsService", WordsService], ["IPlayerService", PlayerService], ["IAudioService", AudioService], ["ITtsService", TtsService], diff --git a/src/services/mpp.service.ts b/src/services/mpp.service.ts index 2926d2e..0aa7afe 100644 --- a/src/services/mpp.service.ts +++ b/src/services/mpp.service.ts @@ -38,9 +38,9 @@ export class MppService implements IMppService { const fragment = document.createDocumentFragment(); - const parts = node.nodeValue.split(/(\{.*?\|.*?\})/); + const words = node.nodeValue.split(/(\{.*?\|.*?\})/); - parts.forEach((part) => { + words.forEach((part) => { const match = part.match(/\{(.*?)\|(.*?)\}/); if (match) { diff --git a/src/services/ribbon-icon.service.ts b/src/services/ribbon-icon.service.ts index a9c30e5..d0cf34d 100644 --- a/src/services/ribbon-icon.service.ts +++ b/src/services/ribbon-icon.service.ts @@ -3,7 +3,7 @@ import { inject, singleton } from "tsyringe"; import type { IPracticeModalService } from "../practice/practice-modal.service"; import type { IQuestsService } from "../practice/quests.service"; import type { IWord } from "../types"; -import type { IPart, IPartsService } from "./parts.service"; +import type { IWordsService } from "./words.service"; import type { IWorkspaceService } from "./workspace.service"; export interface IRibbonIconService { @@ -22,7 +22,7 @@ export class RibbonIconService implements IRibbonIconService { constructor( @inject("IWorkspaceService") private readonly workspaceService: IWorkspaceService, - @inject("IPartsService") private readonly partsService: IPartsService, + @inject("IWordsService") private readonly wordsService: IWordsService, @inject("IPracticeModalService") private readonly practiceModalService: IPracticeModalService, @inject("IQuestsService") @@ -41,31 +41,24 @@ export class RibbonIconService implements IRibbonIconService { return; } - let parts: IPart[] = []; + let words: IWord[] = []; - parts = await this.partsService.getSelectedParts(); + words = await this.wordsService.getSelectedWords(); - if (!parts.length) { - parts = await this.partsService.getParts(); + if (!words.length) { + words = await this.wordsService.getWords(); } - if (!parts.length) { - new Notice("No parts provided."); + if (!words.length) { + new Notice("No words provided."); return; } - if (parts.length < 4) { - new Notice("At least 4 parts required."); + if (words.length < 4) { + new Notice("At least 4 words required."); return; } - const words: IWord[] = parts.map((p) => ({ - value: p.value, - translation: p.translation, - text: p?.text || null, - imageUrl: p?.imageUrl || null, - })); - this.questsService.createQuests(words); this.practiceModalService.open(); }; diff --git a/src/services/parts.service.ts b/src/services/words.service.ts similarity index 73% rename from src/services/parts.service.ts rename to src/services/words.service.ts index 5777524..8211322 100644 --- a/src/services/parts.service.ts +++ b/src/services/words.service.ts @@ -1,18 +1,12 @@ import { TFile } from "obsidian"; import { inject, singleton } from "tsyringe"; +import type { IWord } from "../types"; import type { IVaultService } from "./vault.service"; import type { IWorkspaceService } from "./workspace.service"; -export interface IPart { - value: string; - translation: string; - text?: string; - imageUrl?: string; -} - -export interface IPartsService { - getParts(): Promise; - getSelectedParts(): Promise; +export interface IWordsService { + getWords(): Promise; + getSelectedWords(): Promise; } interface IExternalLink { @@ -21,14 +15,14 @@ interface IExternalLink { } @singleton() -export class PartsService implements IPartsService { +export class WordsService implements IWordsService { constructor( @inject("IVaultService") private readonly vaultService: IVaultService, @inject("IWorkspaceService") private readonly workspaceService: IWorkspaceService, ) {} - async getParts(): Promise { + async getWords(): Promise { const activeFile = this.workspaceService.getActiveFile(); if (!activeFile) { @@ -41,16 +35,23 @@ export class PartsService implements IPartsService { return []; } - const matches = [...content.matchAll(/\{([^\\|{}]+)\|([^\\|{}]+)\}/g)]; // {value|translation} + /** + * {value|translation} + */ + const matches = [...content.matchAll(/\{([^\\|{}]+)\|([^\\|{}]+)\}/g)]; - const parts: IPart[] = []; + const words: IWord[] = []; const texts = content.split("\n"); - // Generate parts array + /** + * Generate words array + */ matches.forEach((match) => { - // Don't put duplicates to the array - if (parts.find((item) => item.value === match[1])) { + /** + * Don't put duplicates to the array + */ + if (words.find((item) => item.value === match[1])) { return; } @@ -58,16 +59,17 @@ export class PartsService implements IPartsService { let rawText = texts[textIndex].replaceAll(`{${match[1]}|${match[2]}}`, match[1]); - const anotherParts = [...rawText.matchAll(/\{([^\\|{}]+)\|([^\\|{}]+)\}/g)]; + const anotherWords = [...rawText.matchAll(/\{([^\\|{}]+)\|([^\\|{}]+)\}/g)]; - anotherParts.forEach((item) => { + anotherWords.forEach((item) => { rawText = rawText.replace(item[0], item[1]); }); - const data: IPart = { + const data: IWord = { value: match[1], translation: match[2], text: rawText, + imageUrl: null, }; /** @@ -79,13 +81,13 @@ export class PartsService implements IPartsService { data.imageUrl = imageUrl; } - parts.push(data); + words.push(data); }); - return parts; + return words; } - async getSelectedParts(): Promise { + async getSelectedWords(): Promise { const activeFile = this.workspaceService.getActiveFile(); if (!activeFile) { @@ -94,7 +96,7 @@ export class PartsService implements IPartsService { const content = await this.vaultService.read(activeFile); - const parts: IPart[] = []; + const words: IWord[] = []; const selection = window.getSelection(); @@ -102,12 +104,16 @@ export class PartsService implements IPartsService { const ranges = selection.getRangeAt(0); const spans = document.querySelectorAll(".memodack___syntax"); - // Iterate over all elements + /** + * Iterate over all elements + */ spans.forEach((span) => { const spanRange = document.createRange(); spanRange.selectNode(span); - // Check if the selection intersects with the element + /** + * Check if the selection intersects with the element + */ if (ranges.intersectsNode(span)) { const value = span.textContent; @@ -117,9 +123,11 @@ export class PartsService implements IPartsService { const translation = span.getAttribute("data-translation"); - // Format the string and add it to the array + /** + * Format the string and add it to the array + */ if (value && translation) { - const data: IPart = { value, translation }; + const data: IWord = { value, translation, text: null, imageUrl: null }; /** * Image @@ -130,15 +138,17 @@ export class PartsService implements IPartsService { data.imageUrl = imageUrl; } - parts.push(data); + words.push(data); } } }); - // Clear selection + /** + * Clear selection + */ selection.removeAllRanges(); - return parts; + return words; } return []; @@ -160,7 +170,9 @@ export class PartsService implements IPartsService { } private extractExternalLinks(content: string): IExternalLink[] { - // [text](url) + /** + * [text](url) + */ const regex = /\[([^\]]+)\]\(([^)]+)\)/g; return [...content.matchAll(regex)].map((m) => ({