mirror of
https://github.com/memodack/memodack.git
synced 2026-07-22 11:50:25 +00:00
refactor: words service
This commit is contained in:
parent
ba3d9f4baf
commit
f798ff03a8
6 changed files with 62 additions and 56 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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[] {
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<IPart[]>;
|
||||
getSelectedParts(): Promise<IPart[]>;
|
||||
export interface IWordsService {
|
||||
getWords(): Promise<IWord[]>;
|
||||
getSelectedWords(): Promise<IWord[]>;
|
||||
}
|
||||
|
||||
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<IPart[]> {
|
||||
async getWords(): Promise<IWord[]> {
|
||||
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<IPart[]> {
|
||||
async getSelectedWords(): Promise<IWord[]> {
|
||||
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 <span> elements
|
||||
/**
|
||||
* Iterate over all <span> elements
|
||||
*/
|
||||
spans.forEach((span) => {
|
||||
const spanRange = document.createRange();
|
||||
spanRange.selectNode(span);
|
||||
|
||||
// Check if the selection intersects with the <span> element
|
||||
/**
|
||||
* Check if the selection intersects with the <span> 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) => ({
|
||||
Loading…
Reference in a new issue