mirror of
https://github.com/mts7/obsidian-word-frequency.git
synced 2026-07-22 05:43:07 +00:00
add prettier
This commit is contained in:
parent
820e71b119
commit
ee94db5e83
27 changed files with 476 additions and 239 deletions
11
.github/workflows/main.yaml
vendored
11
.github/workflows/main.yaml
vendored
|
|
@ -3,10 +3,10 @@ name: Word Frequency Pipeline
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build_test:
|
||||
|
|
@ -19,11 +19,14 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '23'
|
||||
node-version: "23"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run Prettier
|
||||
run: npx prettier --check
|
||||
|
||||
- name: Lint code
|
||||
run: npm run lint
|
||||
|
||||
|
|
@ -54,7 +57,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '23'
|
||||
node-version: "23"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
|
|
|||
3
.prettierignore
Normal file
3
.prettierignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Ignore artifacts:
|
||||
build
|
||||
coverage
|
||||
7
.prettierrc
Normal file
7
.prettierrc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"bracketSameLine": true,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
# obsidian-word-frequency
|
||||
|
||||
Count word frequency in current note within Obsidian
|
||||
|
|
|
|||
|
|
@ -1,55 +1,55 @@
|
|||
class MockMarkdownView {
|
||||
editor = {
|
||||
getValue: jest.fn(),
|
||||
};
|
||||
containerEl = {
|
||||
addEventListener: jest.fn(),
|
||||
};
|
||||
getViewType = jest.fn();
|
||||
getViewData = jest.fn();
|
||||
onunload = jest.fn();
|
||||
getDisplayText = jest.fn();
|
||||
constructor() { }
|
||||
editor = {
|
||||
getValue: jest.fn(),
|
||||
};
|
||||
containerEl = {
|
||||
addEventListener: jest.fn(),
|
||||
};
|
||||
getViewType = jest.fn();
|
||||
getViewData = jest.fn();
|
||||
onunload = jest.fn();
|
||||
getDisplayText = jest.fn();
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setIcon: jest.fn(),
|
||||
App: jest.fn(),
|
||||
Plugin: jest.fn(),
|
||||
MarkdownView: MockMarkdownView,
|
||||
WorkspaceLeaf: jest.fn(),
|
||||
Editor: jest.fn(),
|
||||
PluginSettingTab: jest.fn(),
|
||||
ItemView: jest.fn(),
|
||||
CustomEvent: jest.fn(),
|
||||
Setting: jest.fn().mockImplementation((containerEl: HTMLElement) => {
|
||||
const settingEl = document.createElement('div');
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.classList.add('word-frequency-setting-blacklist');
|
||||
settingEl.appendChild(textArea);
|
||||
containerEl.appendChild(settingEl);
|
||||
setIcon: jest.fn(),
|
||||
App: jest.fn(),
|
||||
Plugin: jest.fn(),
|
||||
MarkdownView: MockMarkdownView,
|
||||
WorkspaceLeaf: jest.fn(),
|
||||
Editor: jest.fn(),
|
||||
PluginSettingTab: jest.fn(),
|
||||
ItemView: jest.fn(),
|
||||
CustomEvent: jest.fn(),
|
||||
Setting: jest.fn().mockImplementation((containerEl: HTMLElement) => {
|
||||
const settingEl = document.createElement("div");
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.classList.add("word-frequency-setting-blacklist");
|
||||
settingEl.appendChild(textArea);
|
||||
containerEl.appendChild(settingEl);
|
||||
|
||||
return {
|
||||
setName: jest.fn().mockReturnThis(),
|
||||
setDesc: jest.fn().mockReturnThis(),
|
||||
addTextArea: jest.fn().mockImplementation((callback) => {
|
||||
callback({
|
||||
setValue: function (value: string) {
|
||||
textArea.value = value;
|
||||
return this;
|
||||
},
|
||||
onChange: function (handler: (value: string) => void) {
|
||||
textArea.addEventListener("change", (event) => {
|
||||
handler((event.target as HTMLTextAreaElement).value);
|
||||
});
|
||||
return this;
|
||||
},
|
||||
inputEl: textArea,
|
||||
});
|
||||
return {
|
||||
setName: jest.fn().mockReturnThis(),
|
||||
setDesc: jest.fn().mockReturnThis(),
|
||||
addTextArea: jest.fn().mockImplementation((callback) => {
|
||||
callback({
|
||||
setValue: function (value: string) {
|
||||
textArea.value = value;
|
||||
return this;
|
||||
},
|
||||
onChange: function (handler: (value: string) => void) {
|
||||
textArea.addEventListener('change', (event) => {
|
||||
handler((event.target as HTMLTextAreaElement).value);
|
||||
});
|
||||
return this;
|
||||
},
|
||||
inputEl: textArea,
|
||||
});
|
||||
return {
|
||||
inputEl: textArea,
|
||||
};
|
||||
}),
|
||||
inputEl: textArea,
|
||||
};
|
||||
}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export const debounce = jest.fn((func) => {
|
||||
return jest.fn(func);
|
||||
});
|
||||
return jest.fn(func);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,31 +1,28 @@
|
|||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import pluginJs from '@eslint/js';
|
||||
import prettierConfig from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs,ts}']
|
||||
files: ['**/*.{js,mjs,cjs,ts}'],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node
|
||||
...globals.node,
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
}
|
||||
}
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: [
|
||||
'__mocks__/**',
|
||||
'coverage/**',
|
||||
'dist/**',
|
||||
'node_modules/**',
|
||||
],
|
||||
},
|
||||
pluginJs.configs.recommended,
|
||||
{
|
||||
ignores: ['__mocks__/**', 'coverage/**', 'dist/**', 'node_modules/**'],
|
||||
},
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
prettierConfig,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'jsdom',
|
||||
modulePathIgnorePatterns: ['<rootDir>/dist/'],
|
||||
testMatch: ['<rootDir>/src/__tests__/**/*.test.ts'],
|
||||
coverageDirectory: 'coverage',
|
||||
coverageReporters: ['cobertura', 'html', 'text', 'text-summary'],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{js,jsx,ts,tsx}',
|
||||
'!src/**/*.d.ts',
|
||||
],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 90,
|
||||
functions: 70,
|
||||
lines: 90,
|
||||
statements: 90,
|
||||
},
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "jsdom",
|
||||
modulePathIgnorePatterns: ["<rootDir>/dist/"],
|
||||
testMatch: ["<rootDir>/src/__tests__/**/*.test.ts"],
|
||||
coverageDirectory: "coverage",
|
||||
coverageReporters: ["cobertura", "html", "text", "text-summary"],
|
||||
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 90,
|
||||
functions: 70,
|
||||
lines: 90,
|
||||
statements: 90,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
42
package-lock.json
generated
42
package-lock.json
generated
|
|
@ -20,6 +20,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "^28.11.0",
|
||||
"globals": "^16.0.0",
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"obsidian": "^1.8.7",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
"ts-jest": "^29.2.6",
|
||||
|
|
@ -3471,6 +3473,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz",
|
||||
"integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||
|
|
@ -6616,6 +6630,21 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
|
|
@ -10534,6 +10563,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz",
|
||||
"integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||
|
|
@ -12791,6 +12827,12 @@
|
|||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
"build": "rollup -c",
|
||||
"dev": "npm run build && obsidian --dev",
|
||||
"watch": "rollup -c --watch",
|
||||
"pretty-fix": "npx prettier src --write",
|
||||
"lint": "eslint . --ext .js,.ts",
|
||||
"lint-fix": "eslint . --ext .js,.ts --fix",
|
||||
"test": "jest",
|
||||
"coverage": "npx jest --coverage"
|
||||
},
|
||||
|
|
@ -38,6 +40,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jest": "^28.11.0",
|
||||
"globals": "^16.0.0",
|
||||
|
|
@ -45,6 +48,7 @@
|
|||
"jest-environment-jsdom": "^29.7.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"obsidian": "^1.8.7",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
"ts-jest": "^29.2.6",
|
||||
|
|
|
|||
|
|
@ -1,19 +1,14 @@
|
|||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import json from '@rollup/plugin-json';
|
||||
import resolve from "@rollup/plugin-node-resolve";
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import json from "@rollup/plugin-json";
|
||||
|
||||
export default {
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
file: 'dist/main.js',
|
||||
format: 'cjs',
|
||||
},
|
||||
plugins: [
|
||||
commonjs(),
|
||||
json(),
|
||||
resolve(),
|
||||
typescript()
|
||||
],
|
||||
external: ['obsidian'],
|
||||
input: "src/main.ts",
|
||||
output: {
|
||||
file: "dist/main.js",
|
||||
format: "cjs",
|
||||
},
|
||||
plugins: [commonjs(), json(), resolve(), typescript()],
|
||||
external: ["obsidian"],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ export class ViewManager {
|
|||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
getOrCreateLeaf(workspace: Workspace, viewType: string): WorkspaceLeaf | null {
|
||||
getOrCreateLeaf(
|
||||
workspace: Workspace,
|
||||
viewType: string
|
||||
): WorkspaceLeaf | null {
|
||||
const leaves = workspace.getLeavesOfType(viewType);
|
||||
if (leaves.length > 0) {
|
||||
return leaves[0];
|
||||
|
|
@ -20,12 +23,13 @@ export class ViewManager {
|
|||
async setViewState(leaf: WorkspaceLeaf, viewType: string): Promise<void> {
|
||||
await leaf.setViewState({
|
||||
type: viewType,
|
||||
active: true
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
|
||||
updateContent(): void {
|
||||
const editor = this.plugin.app.workspace.getActiveViewOfType(MarkdownView)?.editor;
|
||||
const editor =
|
||||
this.plugin.app.workspace.getActiveViewOfType(MarkdownView)?.editor;
|
||||
this.plugin.frequencyCounter.triggerUpdateContent(editor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ export class WordFrequencyCounter {
|
|||
return Array.from(wordCounts.entries()).sort((a, b) => b[1] - a[1]);
|
||||
}
|
||||
|
||||
handleActiveLeafChange(leaf: WorkspaceLeaf | null, workspace: Workspace): void {
|
||||
handleActiveLeafChange(
|
||||
leaf: WorkspaceLeaf | null,
|
||||
workspace: Workspace
|
||||
): void {
|
||||
if (leaf === null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -64,7 +67,9 @@ export class WordFrequencyCounter {
|
|||
}
|
||||
try {
|
||||
const wordCounts = this.calculateWordFrequencies(editor.getValue());
|
||||
window.document.dispatchEvent(new CustomEvent(EVENT_UPDATE, { detail: { wordCounts } }));
|
||||
window.document.dispatchEvent(
|
||||
new CustomEvent(EVENT_UPDATE, { detail: { wordCounts } })
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('error in triggerUpdateContent', error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,18 +12,27 @@ export class WordFrequencyDisplay {
|
|||
this.view = view;
|
||||
}
|
||||
|
||||
addWordToSidebar(blacklist: Set<string>, word: string, count: number, contentContainer: HTMLDivElement) {
|
||||
addWordToSidebar(
|
||||
blacklist: Set<string>,
|
||||
word: string,
|
||||
count: number,
|
||||
contentContainer: HTMLDivElement
|
||||
) {
|
||||
if (blacklist.has(word) || count < this.plugin.settings.threshold) {
|
||||
return;
|
||||
}
|
||||
|
||||
const row = contentContainer.createEl('div', { cls: 'word-row' });
|
||||
|
||||
const wordCountContainer = row.createEl('div', { cls: 'word-count-container' });
|
||||
const wordCountContainer = row.createEl('div', {
|
||||
cls: 'word-count-container',
|
||||
});
|
||||
wordCountContainer.createEl('span', { text: word });
|
||||
wordCountContainer.createEl('span', { text: count.toString() });
|
||||
|
||||
const buttonContainer = row.createEl('div', { cls: 'button-container' });
|
||||
const buttonContainer = row.createEl('div', {
|
||||
cls: 'button-container',
|
||||
});
|
||||
const button = buttonContainer.createEl('button');
|
||||
setIcon(button, 'trash-2');
|
||||
button.addEventListener('click', () => {
|
||||
|
|
@ -38,9 +47,16 @@ export class WordFrequencyDisplay {
|
|||
}
|
||||
|
||||
createThresholdDisplay(contentEl: HTMLElement) {
|
||||
const thresholdDisplay = contentEl.createEl('div', { cls: 'threshold-display' });
|
||||
thresholdDisplay.setText(`Current Frequency Threshold is ${this.plugin.settings.threshold}.`);
|
||||
thresholdDisplay.setAttr('title', 'Configure settings for this plugin to update the frequency threshold.');
|
||||
const thresholdDisplay = contentEl.createEl('div', {
|
||||
cls: 'threshold-display',
|
||||
});
|
||||
thresholdDisplay.setText(
|
||||
`Current Frequency Threshold is ${this.plugin.settings.threshold}.`
|
||||
);
|
||||
thresholdDisplay.setAttr(
|
||||
'title',
|
||||
'Configure settings for this plugin to update the frequency threshold.'
|
||||
);
|
||||
}
|
||||
|
||||
saveWordToBlacklist(word: string) {
|
||||
|
|
|
|||
|
|
@ -20,26 +20,24 @@ export class WordFrequencySettingTab extends PluginSettingTab {
|
|||
.setName('Blacklist')
|
||||
.setDesc('Comma-separated list of words to exclude.')
|
||||
.addTextArea((text) => {
|
||||
text
|
||||
.setValue(this.plugin.settings.blacklist)
|
||||
text.setValue(this.plugin.settings.blacklist)
|
||||
.onChange(async (value) => {
|
||||
await this.saveBlacklistValue(value);
|
||||
})
|
||||
.inputEl.classList.add('word-frequency-setting-blacklist')
|
||||
}
|
||||
);
|
||||
.inputEl.classList.add('word-frequency-setting-blacklist');
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Word Frequency Threshold')
|
||||
.setDesc('Only show words that appear at least this many times.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('3')
|
||||
.setValue(this.plugin.settings.threshold.toString())
|
||||
.onChange(async (value) => {
|
||||
await this.updateThreshold(value);
|
||||
}
|
||||
)
|
||||
);
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder('3')
|
||||
.setValue(this.plugin.settings.threshold.toString())
|
||||
.onChange(async (value) => {
|
||||
await this.updateThreshold(value);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async saveBlacklistValue(value: string) {
|
||||
|
|
@ -55,7 +53,7 @@ export class WordFrequencySettingTab extends PluginSettingTab {
|
|||
|
||||
this.plugin.settings.threshold = num;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.app.workspace.getLeavesOfType(VIEW_TYPE).forEach(leaf => {
|
||||
this.plugin.app.workspace.getLeavesOfType(VIEW_TYPE).forEach((leaf) => {
|
||||
(leaf.view as WordFrequencyView).updateContent();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,24 @@
|
|||
import { ItemView, WorkspaceLeaf } from 'obsidian';
|
||||
import { EVENT_UPDATE, FREQUENCY_ICON, PLUGIN_NAME, VIEW_TYPE } from './constants';
|
||||
import {
|
||||
EVENT_UPDATE,
|
||||
FREQUENCY_ICON,
|
||||
PLUGIN_NAME,
|
||||
VIEW_TYPE,
|
||||
} from './constants';
|
||||
import WordFrequencyPlugin from './main';
|
||||
import { WordFrequencyDisplay } from './WordFrequencyDisplay';
|
||||
|
||||
export class WordFrequencyView extends ItemView {
|
||||
private display: WordFrequencyDisplay;
|
||||
private eventListener: (event: CustomEvent) => void = () => {
|
||||
};
|
||||
private eventListener: (event: CustomEvent) => void = () => {};
|
||||
private readonly plugin: WordFrequencyPlugin;
|
||||
private wordCountList: [string, number][] = [];
|
||||
|
||||
constructor(leaf: WorkspaceLeaf, plugin: WordFrequencyPlugin, display?: WordFrequencyDisplay) {
|
||||
constructor(
|
||||
leaf: WorkspaceLeaf,
|
||||
plugin: WordFrequencyPlugin,
|
||||
display?: WordFrequencyDisplay
|
||||
) {
|
||||
super(leaf);
|
||||
this.plugin = plugin;
|
||||
this.display = display ?? new WordFrequencyDisplay(plugin, this);
|
||||
|
|
@ -39,23 +47,36 @@ export class WordFrequencyView extends ItemView {
|
|||
this.updateContent();
|
||||
}
|
||||
};
|
||||
window.document.addEventListener(EVENT_UPDATE, this.eventListener as EventListener);
|
||||
window.document.addEventListener(
|
||||
EVENT_UPDATE,
|
||||
this.eventListener as EventListener
|
||||
);
|
||||
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
window.document.removeEventListener(EVENT_UPDATE, this.eventListener as EventListener);
|
||||
window.document.removeEventListener(
|
||||
EVENT_UPDATE,
|
||||
this.eventListener as EventListener
|
||||
);
|
||||
}
|
||||
|
||||
updateContent() {
|
||||
this.contentEl.empty();
|
||||
this.display.createHeader(this.contentEl);
|
||||
const contentContainer = this.contentEl.createEl('div');
|
||||
const blacklist = new Set(this.plugin.settings.blacklist.split(',').map(word => word.trim()));
|
||||
const blacklist = new Set(
|
||||
this.plugin.settings.blacklist.split(',').map((word) => word.trim())
|
||||
);
|
||||
|
||||
this.wordCountList.forEach(([word, count]) => {
|
||||
this.display.addWordToSidebar(blacklist, word, count, contentContainer);
|
||||
this.display.addWordToSidebar(
|
||||
blacklist,
|
||||
word,
|
||||
count,
|
||||
contentContainer
|
||||
);
|
||||
});
|
||||
this.display.createThresholdDisplay(this.contentEl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ describe('ViewManager', () => {
|
|||
it('should get or create a leaf', () => {
|
||||
const mockLeaf = {} as WorkspaceLeaf;
|
||||
|
||||
(workspace.getLeavesOfType as jest.Mock).mockReturnValueOnce([mockLeaf]);
|
||||
(workspace.getLeavesOfType as jest.Mock).mockReturnValueOnce([
|
||||
mockLeaf,
|
||||
]);
|
||||
const leaf = viewManager.getOrCreateLeaf(workspace, VIEW_TYPE);
|
||||
|
||||
expect(leaf).toBe(mockLeaf);
|
||||
|
|
@ -62,6 +64,8 @@ describe('ViewManager', () => {
|
|||
|
||||
viewManager.updateContent();
|
||||
|
||||
expect(plugin.frequencyCounter.triggerUpdateContent).toHaveBeenCalledWith(mockEditor);
|
||||
expect(
|
||||
plugin.frequencyCounter.triggerUpdateContent
|
||||
).toHaveBeenCalledWith(mockEditor);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ describe('WordFrequencyCounter tests', () => {
|
|||
|
||||
const result = counter.calculateWordFrequencies(content);
|
||||
|
||||
expect(result).toEqual([['hello', 2], ['world', 1]]);
|
||||
expect(result).toEqual([
|
||||
['hello', 2],
|
||||
['world', 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should calculate word frequencies with punctuation and mixed case', () => {
|
||||
|
|
@ -23,7 +26,10 @@ describe('WordFrequencyCounter tests', () => {
|
|||
|
||||
const result = counter.calculateWordFrequencies(content);
|
||||
|
||||
expect(result).toEqual([['hello', 2], ['world', 2]]);
|
||||
expect(result).toEqual([
|
||||
['hello', 2],
|
||||
['world', 2],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should calculate word frequencies with numbers and special characters', () => {
|
||||
|
|
@ -31,7 +37,12 @@ describe('WordFrequencyCounter tests', () => {
|
|||
|
||||
const result = counter.calculateWordFrequencies(content);
|
||||
|
||||
expect(result).toEqual([['word1', 2], ['hello', 2], ['word2', 1], ['123', 1]]);
|
||||
expect(result).toEqual([
|
||||
['word1', 2],
|
||||
['hello', 2],
|
||||
['word2', 1],
|
||||
['123', 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should calculate word frequencies with periods, colons, and slashes', () => {
|
||||
|
|
@ -69,7 +80,7 @@ describe('WordFrequencyCounter tests', () => {
|
|||
};
|
||||
const workspace: Workspace = {} as unknown as Workspace;
|
||||
const leafMock = {
|
||||
view: null
|
||||
view: null,
|
||||
} as unknown as WorkspaceLeaf;
|
||||
|
||||
counterMock.handleActiveLeafChange(leafMock, workspace);
|
||||
|
|
@ -96,7 +107,10 @@ describe('WordFrequencyCounter tests', () => {
|
|||
|
||||
counter.handleActiveLeafChange(leafMock, workspace);
|
||||
|
||||
expect(containerElMock.addEventListener).toHaveBeenCalledWith('keyup', expect.any(Function));
|
||||
expect(containerElMock.addEventListener).toHaveBeenCalledWith(
|
||||
'keyup',
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it('should set lastActiveEditor with a valid MarkdownView', () => {
|
||||
|
|
@ -108,7 +122,9 @@ describe('WordFrequencyCounter tests', () => {
|
|||
containerEl: containerElMock,
|
||||
} as unknown as MarkdownView;
|
||||
const workspace: Workspace = {
|
||||
getActiveViewOfType: jest.fn().mockReturnValue(markdownViewMock),
|
||||
getActiveViewOfType: jest
|
||||
.fn()
|
||||
.mockReturnValue(markdownViewMock),
|
||||
getLeavesOfType: jest.fn().mockReturnValue([]),
|
||||
} as unknown as Workspace;
|
||||
const leafMock = {
|
||||
|
|
@ -212,7 +228,10 @@ describe('WordFrequencyCounter tests', () => {
|
|||
it('should not dispatch an event or calculate word frequencies', () => {
|
||||
const editor = undefined;
|
||||
const counterMock = jest.spyOn(counter, 'calculateWordFrequencies');
|
||||
const dispatchEventMock = jest.spyOn(window.document, 'dispatchEvent');
|
||||
const dispatchEventMock = jest.spyOn(
|
||||
window.document,
|
||||
'dispatchEvent'
|
||||
);
|
||||
|
||||
counter.triggerUpdateContent(editor);
|
||||
|
||||
|
|
@ -225,12 +244,17 @@ describe('WordFrequencyCounter tests', () => {
|
|||
|
||||
it('should dispatch an event after calculating word frequencies', () => {
|
||||
const counterMock = jest.spyOn(counter, 'calculateWordFrequencies');
|
||||
const dispatchEventMock = jest.spyOn(window.document, 'dispatchEvent');
|
||||
const expectedValue = 'hello world hello';
|
||||
const expectedEvent = new CustomEvent(
|
||||
EVENT_UPDATE,
|
||||
{ detail: [['hello', 2], ['world', 1]] }
|
||||
const dispatchEventMock = jest.spyOn(
|
||||
window.document,
|
||||
'dispatchEvent'
|
||||
);
|
||||
const expectedValue = 'hello world hello';
|
||||
const expectedEvent = new CustomEvent(EVENT_UPDATE, {
|
||||
detail: [
|
||||
['hello', 2],
|
||||
['world', 1],
|
||||
],
|
||||
});
|
||||
const editor: Editor = {
|
||||
getValue: jest.fn().mockReturnValue(expectedValue),
|
||||
} as unknown as Editor;
|
||||
|
|
@ -256,23 +280,33 @@ describe('WordFrequencyCounter tests', () => {
|
|||
const editor: Editor = {
|
||||
getValue: jest.fn().mockReturnValue(expectedValue),
|
||||
} as unknown as Editor;
|
||||
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const consoleErrorSpy = jest
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
counterMock.triggerUpdateContent(editor);
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('error in triggerUpdateContent', expectedError);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'error in triggerUpdateContent',
|
||||
expectedError
|
||||
);
|
||||
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should dispatch an event with last active editor when editor is undefined', () => {
|
||||
const counterMock = jest.spyOn(counter, 'calculateWordFrequencies');
|
||||
const dispatchEventMock = jest.spyOn(window.document, 'dispatchEvent');
|
||||
const expectedValue = 'hello world hello';
|
||||
const expectedEvent = new CustomEvent(
|
||||
EVENT_UPDATE,
|
||||
{ detail: [['hello', 2], ['world', 1]] }
|
||||
const dispatchEventMock = jest.spyOn(
|
||||
window.document,
|
||||
'dispatchEvent'
|
||||
);
|
||||
const expectedValue = 'hello world hello';
|
||||
const expectedEvent = new CustomEvent(EVENT_UPDATE, {
|
||||
detail: [
|
||||
['hello', 2],
|
||||
['world', 1],
|
||||
],
|
||||
});
|
||||
const editor: Editor = {
|
||||
getValue: jest.fn().mockReturnValue(expectedValue),
|
||||
} as unknown as Editor;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ describe('WordFrequencyDisplay', () => {
|
|||
setText: jest.fn(),
|
||||
}),
|
||||
} as unknown as HTMLElement;
|
||||
blacklist = new Set(mockPlugin.settings.blacklist.split(',').map(word => word.trim()));
|
||||
blacklist = new Set(
|
||||
mockPlugin.settings.blacklist.split(',').map((word) => word.trim())
|
||||
);
|
||||
|
||||
display = new WordFrequencyDisplay(mockPlugin, mockView);
|
||||
});
|
||||
|
|
@ -77,7 +79,8 @@ describe('WordFrequencyDisplay', () => {
|
|||
addEventListener: jest.fn(),
|
||||
} as unknown as HTMLButtonElement;
|
||||
const innerElement = {
|
||||
createEl: jest.fn()
|
||||
createEl: jest
|
||||
.fn()
|
||||
.mockReturnValueOnce(spanElement)
|
||||
.mockReturnValueOnce(spanElement)
|
||||
.mockReturnValueOnce(buttonElement),
|
||||
|
|
@ -93,8 +96,12 @@ describe('WordFrequencyDisplay', () => {
|
|||
|
||||
display.addWordToSidebar(blacklist, word, count, contentContainer);
|
||||
|
||||
expect(innerElement.createEl).toHaveBeenNthCalledWith(1, 'span', { text: word });
|
||||
expect(innerElement.createEl).toHaveBeenNthCalledWith(2, 'span', { text: count.toString() });
|
||||
expect(innerElement.createEl).toHaveBeenNthCalledWith(1, 'span', {
|
||||
text: word,
|
||||
});
|
||||
expect(innerElement.createEl).toHaveBeenNthCalledWith(2, 'span', {
|
||||
text: count.toString(),
|
||||
});
|
||||
expect(innerElement.createEl).toHaveBeenNthCalledWith(3, 'button');
|
||||
});
|
||||
|
||||
|
|
@ -104,8 +111,12 @@ describe('WordFrequencyDisplay', () => {
|
|||
|
||||
display.saveWordToBlacklist(word);
|
||||
|
||||
expect(mockPlugin.settings.blacklist).toBe(`${originalBlacklist},${word}`);
|
||||
expect(mockPlugin.saveData).toHaveBeenCalledWith(mockPlugin.settings);
|
||||
expect(mockPlugin.settings.blacklist).toBe(
|
||||
`${originalBlacklist},${word}`
|
||||
);
|
||||
expect(mockPlugin.saveData).toHaveBeenCalledWith(
|
||||
mockPlugin.settings
|
||||
);
|
||||
expect(mockView.updateContent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
@ -129,11 +140,20 @@ describe('WordFrequencyDisplay', () => {
|
|||
it('should set text and attribute in the content', () => {
|
||||
display.createThresholdDisplay(contentEl);
|
||||
|
||||
const thresholdDisplay = contentEl.createEl('div', { cls: 'threshold-display' });
|
||||
const thresholdDisplay = contentEl.createEl('div', {
|
||||
cls: 'threshold-display',
|
||||
});
|
||||
|
||||
expect(contentEl.createEl).toHaveBeenCalledWith('div', { cls: 'threshold-display' });
|
||||
expect(thresholdDisplay.setText).toHaveBeenCalledWith(`Current Frequency Threshold is ${mockPlugin.settings.threshold}.`);
|
||||
expect(thresholdDisplay.setAttr).toHaveBeenCalledWith('title', 'Configure settings for this plugin to update the frequency threshold.');
|
||||
expect(contentEl.createEl).toHaveBeenCalledWith('div', {
|
||||
cls: 'threshold-display',
|
||||
});
|
||||
expect(thresholdDisplay.setText).toHaveBeenCalledWith(
|
||||
`Current Frequency Threshold is ${mockPlugin.settings.threshold}.`
|
||||
);
|
||||
expect(thresholdDisplay.setAttr).toHaveBeenCalledWith(
|
||||
'title',
|
||||
'Configure settings for this plugin to update the frequency threshold.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,14 +23,18 @@ describe('WordFrequencySettingTab', () => {
|
|||
plugin = {
|
||||
settings: {
|
||||
blacklist: '',
|
||||
threshold: 0
|
||||
threshold: 0,
|
||||
},
|
||||
saveSettings: jest.fn().mockResolvedValue(undefined),
|
||||
app: {
|
||||
workspace: {
|
||||
getLeavesOfType: jest.fn().mockReturnValue([{ view: { updateContent: jest.fn() } }])
|
||||
}
|
||||
}
|
||||
getLeavesOfType: jest
|
||||
.fn()
|
||||
.mockReturnValue([
|
||||
{ view: { updateContent: jest.fn() } },
|
||||
]),
|
||||
},
|
||||
},
|
||||
} as unknown as WordFrequencyPlugin;
|
||||
|
||||
containerEl = createMockContainerEl();
|
||||
|
|
@ -58,13 +62,17 @@ describe('WordFrequencySettingTab', () => {
|
|||
|
||||
await settingTab.updateThreshold(value);
|
||||
|
||||
const view = plugin.app.workspace.getLeavesOfType(VIEW_TYPE)[0] as unknown as {
|
||||
view: WordFrequencyView
|
||||
const view = plugin.app.workspace.getLeavesOfType(
|
||||
VIEW_TYPE
|
||||
)[0] as unknown as {
|
||||
view: WordFrequencyView;
|
||||
};
|
||||
|
||||
expect(plugin.settings.threshold).toBe(5);
|
||||
expect(plugin.saveSettings).toHaveBeenCalled();
|
||||
expect(plugin.app.workspace.getLeavesOfType).toHaveBeenCalledWith(VIEW_TYPE);
|
||||
expect(plugin.app.workspace.getLeavesOfType).toHaveBeenCalledWith(
|
||||
VIEW_TYPE
|
||||
);
|
||||
expect(view.view.updateContent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { WorkspaceLeaf } from 'obsidian';
|
||||
import { EVENT_UPDATE, FREQUENCY_ICON, PLUGIN_NAME, VIEW_TYPE } from '../constants';
|
||||
import {
|
||||
EVENT_UPDATE,
|
||||
FREQUENCY_ICON,
|
||||
PLUGIN_NAME,
|
||||
VIEW_TYPE,
|
||||
} from '../constants';
|
||||
import WordFrequencyPlugin from '../main';
|
||||
import { WordFrequencyDisplay } from '../WordFrequencyDisplay';
|
||||
import { WordFrequencyView } from '../WordFrequencyView';
|
||||
|
|
@ -37,7 +42,11 @@ describe('WordFrequencyView', () => {
|
|||
});
|
||||
|
||||
it('should use the provided WordFrequencyDisplay instance if passed', async () => {
|
||||
const view = new WordFrequencyView(mockLeaf, mockPlugin, mockDisplay);
|
||||
const view = new WordFrequencyView(
|
||||
mockLeaf,
|
||||
mockPlugin,
|
||||
mockDisplay
|
||||
);
|
||||
|
||||
const viewMock = {
|
||||
onOpen: view.onOpen,
|
||||
|
|
@ -81,11 +90,17 @@ describe('WordFrequencyView', () => {
|
|||
|
||||
describe('onOpen', () => {
|
||||
it('should add an event listener for EVENT_UPDATE', async () => {
|
||||
const addEventListenerSpy = jest.spyOn(window.document, 'addEventListener');
|
||||
const addEventListenerSpy = jest.spyOn(
|
||||
window.document,
|
||||
'addEventListener'
|
||||
);
|
||||
|
||||
await view.onOpen();
|
||||
|
||||
expect(addEventListenerSpy).toHaveBeenCalledWith(EVENT_UPDATE, expect.any(Function));
|
||||
expect(addEventListenerSpy).toHaveBeenCalledWith(
|
||||
EVENT_UPDATE,
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call updateContent on open', async () => {
|
||||
|
|
@ -104,8 +119,13 @@ describe('WordFrequencyView', () => {
|
|||
|
||||
await view.onOpen();
|
||||
|
||||
const wordCounts = [['apple', 5], ['banana', 3]];
|
||||
const event = new CustomEvent(EVENT_UPDATE, { detail: { wordCounts } });
|
||||
const wordCounts = [
|
||||
['apple', 5],
|
||||
['banana', 3],
|
||||
];
|
||||
const event = new CustomEvent(EVENT_UPDATE, {
|
||||
detail: { wordCounts },
|
||||
});
|
||||
window.document.dispatchEvent(event);
|
||||
|
||||
expect(updateContentSpy).toHaveBeenCalled();
|
||||
|
|
@ -117,20 +137,34 @@ describe('WordFrequencyView', () => {
|
|||
describe('onClose', () => {
|
||||
it('should remove the event listener for EVENT_UPDATE', async () => {
|
||||
await view.onOpen();
|
||||
const removeEventListenerSpy = jest.spyOn(window.document, 'removeEventListener');
|
||||
const removeEventListenerSpy = jest.spyOn(
|
||||
window.document,
|
||||
'removeEventListener'
|
||||
);
|
||||
|
||||
await view.onClose();
|
||||
|
||||
expect(removeEventListenerSpy).toHaveBeenCalledWith(EVENT_UPDATE, expect.any(Function));
|
||||
expect(removeEventListenerSpy).toHaveBeenCalledWith(
|
||||
EVENT_UPDATE,
|
||||
expect.any(Function)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateContent', () => {
|
||||
it('should add words to sidebar for each word', async () => {
|
||||
await view.onOpen();
|
||||
const wordCounts = [['apple', 5], ['banana', 3]];
|
||||
const event = new CustomEvent(EVENT_UPDATE, { detail: { wordCounts } });
|
||||
const addWordToSidebarSpy = jest.spyOn(mockDisplay, 'addWordToSidebar');
|
||||
const wordCounts = [
|
||||
['apple', 5],
|
||||
['banana', 3],
|
||||
];
|
||||
const event = new CustomEvent(EVENT_UPDATE, {
|
||||
detail: { wordCounts },
|
||||
});
|
||||
const addWordToSidebarSpy = jest.spyOn(
|
||||
mockDisplay,
|
||||
'addWordToSidebar'
|
||||
);
|
||||
|
||||
window.document.dispatchEvent(event);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { App, WorkspaceLeaf, PluginManifest, Workspace } from 'obsidian';
|
||||
import { DEFAULT_SETTINGS, FREQUENCY_ICON, PLUGIN_NAME, VIEW_TYPE } from '../constants';
|
||||
import {
|
||||
DEFAULT_SETTINGS,
|
||||
FREQUENCY_ICON,
|
||||
PLUGIN_NAME,
|
||||
VIEW_TYPE,
|
||||
} from '../constants';
|
||||
import WordFrequencyPlugin from '../main';
|
||||
import { ViewManager } from '../ViewManager';
|
||||
import { WordFrequencySettingTab } from '../WordFrequencySettingTab';
|
||||
|
|
@ -48,7 +53,11 @@ describe('WordFrequencyPlugin', () => {
|
|||
updateContent: jest.fn(),
|
||||
} as unknown as ViewManager;
|
||||
|
||||
plugin = new WordFrequencyPlugin(mockApp, mockManifest, mockViewManager);
|
||||
plugin = new WordFrequencyPlugin(
|
||||
mockApp,
|
||||
mockManifest,
|
||||
mockViewManager
|
||||
);
|
||||
plugin['app'] = mockApp;
|
||||
plugin['loadData'] = jest.fn().mockResolvedValue(DEFAULT_SETTINGS);
|
||||
plugin['saveData'] = jest.fn().mockResolvedValue(undefined);
|
||||
|
|
@ -68,40 +77,61 @@ describe('WordFrequencyPlugin', () => {
|
|||
|
||||
await plugin.onload();
|
||||
|
||||
expect(plugin.registerView).toHaveBeenCalledWith(VIEW_TYPE, expect.any(Function));
|
||||
expect(plugin.registerView).toHaveBeenCalledWith(
|
||||
VIEW_TYPE,
|
||||
expect.any(Function)
|
||||
);
|
||||
expect(plugin.addRibbonIcon).toHaveBeenCalledWith(
|
||||
FREQUENCY_ICON,
|
||||
`Show ${PLUGIN_NAME} Sidebar`,
|
||||
expect.any(Function)
|
||||
);
|
||||
expect(plugin.app.workspace.on).toHaveBeenCalledWith('active-leaf-change', expect.any(Function));
|
||||
expect(plugin.app.workspace.on).toHaveBeenCalledWith(
|
||||
'active-leaf-change',
|
||||
expect.any(Function)
|
||||
);
|
||||
expect(plugin.addSettingTab).toHaveBeenCalledWith(settingTab);
|
||||
});
|
||||
});
|
||||
|
||||
describe('activateView', () => {
|
||||
it('should set the view state and show the leaf with content', async() => {
|
||||
it('should set the view state and show the leaf with content', async () => {
|
||||
const mockLeaf = jest.fn() as unknown as WorkspaceLeaf;
|
||||
mockViewManager = {
|
||||
getOrCreateLeaf: jest.fn().mockReturnValue(mockLeaf),
|
||||
setViewState: jest.fn(),
|
||||
updateContent: jest.fn(),
|
||||
} as unknown as ViewManager;
|
||||
plugin = new WordFrequencyPlugin(mockApp, mockManifest, mockViewManager);
|
||||
plugin = new WordFrequencyPlugin(
|
||||
mockApp,
|
||||
mockManifest,
|
||||
mockViewManager
|
||||
);
|
||||
plugin['app'] = mockApp;
|
||||
|
||||
await plugin.activateView();
|
||||
|
||||
expect(mockViewManager.getOrCreateLeaf).toHaveBeenCalledWith(plugin.app.workspace, VIEW_TYPE);
|
||||
expect(mockViewManager.setViewState).toHaveBeenCalledWith(mockLeaf, VIEW_TYPE);
|
||||
expect(plugin.app.workspace.revealLeaf).toHaveBeenCalledWith(mockLeaf);
|
||||
expect(mockViewManager.getOrCreateLeaf).toHaveBeenCalledWith(
|
||||
plugin.app.workspace,
|
||||
VIEW_TYPE
|
||||
);
|
||||
expect(mockViewManager.setViewState).toHaveBeenCalledWith(
|
||||
mockLeaf,
|
||||
VIEW_TYPE
|
||||
);
|
||||
expect(plugin.app.workspace.revealLeaf).toHaveBeenCalledWith(
|
||||
mockLeaf
|
||||
);
|
||||
expect(mockViewManager.updateContent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not set view state or reveal leaf when there is no leaf', async() => {
|
||||
it('should not set view state or reveal leaf when there is no leaf', async () => {
|
||||
await plugin.activateView();
|
||||
|
||||
expect(mockViewManager.getOrCreateLeaf).toHaveBeenCalledWith(plugin.app.workspace, VIEW_TYPE);
|
||||
expect(mockViewManager.getOrCreateLeaf).toHaveBeenCalledWith(
|
||||
plugin.app.workspace,
|
||||
VIEW_TYPE
|
||||
);
|
||||
expect(mockViewManager.setViewState).not.toHaveBeenCalled();
|
||||
expect(plugin.app.workspace.revealLeaf).not.toHaveBeenCalled();
|
||||
expect(mockViewManager.updateContent).not.toHaveBeenCalled();
|
||||
|
|
|
|||
|
|
@ -108,4 +108,4 @@ describe('debounce', () => {
|
|||
expect(mockFunc).toHaveBeenCalledTimes(1);
|
||||
expect(mockFunc).toHaveReturnedWith('testValue');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
40
src/main.ts
40
src/main.ts
|
|
@ -1,5 +1,11 @@
|
|||
import { App, Plugin, PluginManifest, WorkspaceLeaf } from 'obsidian';
|
||||
import { WordFrequencySettings, DEFAULT_SETTINGS, PLUGIN_NAME, VIEW_TYPE, FREQUENCY_ICON } from './constants';
|
||||
import {
|
||||
WordFrequencySettings,
|
||||
DEFAULT_SETTINGS,
|
||||
PLUGIN_NAME,
|
||||
VIEW_TYPE,
|
||||
FREQUENCY_ICON,
|
||||
} from './constants';
|
||||
import { ViewManager } from './ViewManager';
|
||||
import { WordFrequencyCounter } from './WordFrequencyCounter';
|
||||
import { WordFrequencySettingTab } from './WordFrequencySettingTab';
|
||||
|
|
@ -11,7 +17,12 @@ export default class WordFrequencyPlugin extends Plugin {
|
|||
settingTab: WordFrequencySettingTab;
|
||||
viewManager: ViewManager;
|
||||
|
||||
constructor(app: App, manifest: PluginManifest, viewManager?: ViewManager, settingTab?: WordFrequencySettingTab) {
|
||||
constructor(
|
||||
app: App,
|
||||
manifest: PluginManifest,
|
||||
viewManager?: ViewManager,
|
||||
settingTab?: WordFrequencySettingTab
|
||||
) {
|
||||
super(app, manifest);
|
||||
this.settingTab = settingTab ?? new WordFrequencySettingTab(this);
|
||||
this.viewManager = viewManager ?? new ViewManager(this);
|
||||
|
|
@ -26,24 +37,27 @@ export default class WordFrequencyPlugin extends Plugin {
|
|||
(leaf: WorkspaceLeaf) => new WordFrequencyView(leaf, this)
|
||||
);
|
||||
|
||||
this.addRibbonIcon(FREQUENCY_ICON, `Show ${PLUGIN_NAME} Sidebar`, () => {
|
||||
this.activateView();
|
||||
});
|
||||
this.addRibbonIcon(
|
||||
FREQUENCY_ICON,
|
||||
`Show ${PLUGIN_NAME} Sidebar`,
|
||||
() => {
|
||||
this.activateView();
|
||||
}
|
||||
);
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on(
|
||||
'active-leaf-change',
|
||||
(leaf) => {
|
||||
this.frequencyCounter.handleActiveLeafChange(leaf, this.app.workspace);
|
||||
}
|
||||
)
|
||||
this.app.workspace.on('active-leaf-change', (leaf) => {
|
||||
this.frequencyCounter.handleActiveLeafChange(
|
||||
leaf,
|
||||
this.app.workspace
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
this.addSettingTab(this.settingTab);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
}
|
||||
onunload() {}
|
||||
|
||||
async activateView() {
|
||||
const { workspace } = this.app;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
export function debounce<T extends (...args: Parameters<T>) => void>(func: T, delay: number): (...args: Parameters<T>) => void {
|
||||
export function debounce<T extends (...args: Parameters<T>) => void>(
|
||||
func: T,
|
||||
delay: number
|
||||
): (...args: Parameters<T>) => void {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
return (...args: Parameters<T>): void => {
|
||||
clearTimeout(timeoutId);
|
||||
|
|
|
|||
42
styles.css
42
styles.css
|
|
@ -1,41 +1,41 @@
|
|||
.setting-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.setting-item-info {
|
||||
flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.word-frequency-setting-blacklist {
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.word-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.word-count-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.word-count-container span {
|
||||
flex-shrink: 1;
|
||||
max-width: 80%;
|
||||
overflow: hidden;
|
||||
padding-right: 10px;
|
||||
flex-shrink: 1;
|
||||
max-width: 80%;
|
||||
overflow: hidden;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin-left: 10px;
|
||||
margin-top: 0;
|
||||
margin-left: 10px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"baseUrl": ".",
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react",
|
||||
"lib": ["ESNext", "dom"],
|
||||
"lib": ["ESNext", "dom"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"outDir": "./dist",
|
||||
|
|
@ -13,10 +13,7 @@
|
|||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"types": ["obsidian", "node", "jest"],
|
||||
"types": ["obsidian", "node", "jest"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"node_modules/@types/jest/index.d.ts",
|
||||
]
|
||||
"include": ["src/**/*", "node_modules/@types/jest/index.d.ts"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue