remove utils, update configs, only update word list, add class string constants

This commit is contained in:
Mike Rodarte 2025-04-07 17:03:46 -04:00
parent 5e19563dc7
commit b71a98e492
No known key found for this signature in database
GPG key ID: 32DCD8C789A592CC
9 changed files with 80 additions and 35 deletions

View file

@ -1,3 +0,0 @@
export const debounce = jest.fn((func) => {
return jest.fn(func);
});

View file

@ -1,5 +1,4 @@
import pluginJs from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
import globals from 'globals';
import tseslint from 'typescript-eslint';
@ -24,5 +23,9 @@ export default [
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
prettierConfig,
{
rules: {
curly: ['error', 'all'],
},
},
];

View file

@ -1,7 +1,7 @@
{
"id": "word-frequency",
"name": "Word Frequency",
"version": "1.2.10",
"version": "1.3.0",
"minAppVersion": "1.0.0",
"description": "Counts the most frequently used words in a note and displays them in the sidebar.",
"author": "Mike Rodarte",

View file

@ -1,6 +1,6 @@
{
"name": "word-frequency",
"version": "1.2.10",
"version": "1.3.0",
"type": "module",
"description": "Count word frequency in current note within Obsidian",
"main": "main.js",
@ -12,11 +12,12 @@
"dev": "npm run build && obsidian --dev",
"watch": "rollup -c --watch",
"prettier": "npx prettier --check \"src/**/*.{js,ts,jsx,tsx}\"",
"pretty-fix": "npx prettier src --write",
"lint": "eslint . --ext \"src/**/*.{js,ts,jsx,tsx}\"",
"format": "npx prettier src --write",
"lint": "eslint . --ext \"**/*.{js,ts,jsx,tsx}\"",
"lint-fix": "eslint . --ext .js,.ts --fix",
"test": "jest",
"coverage": "npx jest --coverage"
"coverage": "npx jest --coverage",
"all": "npm run lint-fix && npm run format && npm run build && npm run coverage"
},
"repository": {
"type": "git",

View file

@ -1,9 +1,10 @@
import { setIcon } from 'obsidian';
import { PLUGIN_NAME } from './constants';
import { debounce, setIcon } from 'obsidian';
import { ELEMENT_CLASSES, PLUGIN_NAME } from './constants';
import WordFrequencyPlugin from './main';
import { WordFrequencyView } from './WordFrequencyView';
export class WordFrequencyDisplay {
private filter: string = '';
private plugin: WordFrequencyPlugin;
private view: WordFrequencyView;
@ -18,22 +19,27 @@ export class WordFrequencyDisplay {
count: number,
contentContainer: HTMLDivElement
) {
if (blacklist.has(word) || count < this.plugin.settings.threshold) {
if (
blacklist.has(word) ||
count < this.plugin.settings.threshold ||
(this.filter !== '' &&
!word.toLowerCase().contains(this.filter.toLowerCase()))
) {
return;
}
const row = contentContainer.createEl('div', {
cls: 'word-frequency-row',
cls: ELEMENT_CLASSES.containerRow,
});
const wordCountContainer = row.createEl('div', {
cls: 'word-frequency-count-container',
cls: ELEMENT_CLASSES.containerCount,
});
wordCountContainer.createEl('span', { text: word });
wordCountContainer.createEl('span', { text: count.toString() });
const buttonContainer = row.createEl('div', {
cls: 'word-frequency-button-container',
cls: ELEMENT_CLASSES.containerButton,
});
const button = buttonContainer.createEl('button');
setIcon(button, 'trash-2');
@ -42,6 +48,25 @@ export class WordFrequencyDisplay {
});
}
createFilter(contentEl: HTMLElement) {
const filterContainer = contentEl.createEl('div');
const filterInput = filterContainer.createEl('input');
filterInput.setAttr('type', 'text');
filterInput.addClass(ELEMENT_CLASSES.filter);
filterInput.setAttr('placeholder', 'Type to filter results');
const debouncedMethod = debounce((event: Event) => {
const target = event.target as HTMLInputElement;
this.filter = target.value;
this.view.updateContent();
}, 500);
this.plugin.registerDomEvent(filterInput, 'input', (event) =>
debouncedMethod(event)
);
}
createHeader(contentEl: HTMLElement) {
const headerContainer = contentEl.createEl('div');
const headerElement = headerContainer.createEl('h4');
@ -50,7 +75,7 @@ export class WordFrequencyDisplay {
createThresholdDisplay(contentEl: HTMLElement) {
const thresholdDisplay = contentEl.createEl('div', {
cls: 'threshold-display',
cls: ELEMENT_CLASSES.containerThreshold,
});
thresholdDisplay.setText(
`Current frequency threshold is ${this.plugin.settings.threshold}.`

View file

@ -1,5 +1,6 @@
import { ItemView, WorkspaceLeaf } from 'obsidian';
import {
ELEMENT_CLASSES,
EVENT_UPDATE,
FREQUENCY_ICON,
PLUGIN_NAME,
@ -13,6 +14,7 @@ export class WordFrequencyView extends ItemView {
private eventListener: (event: CustomEvent) => void = () => {};
private readonly plugin: WordFrequencyPlugin;
private wordCountList: [string, number][] = [];
private wordListContainer: HTMLDivElement;
constructor(
leaf: WorkspaceLeaf,
@ -22,6 +24,9 @@ export class WordFrequencyView extends ItemView {
super(leaf);
this.plugin = plugin;
this.display = display ?? new WordFrequencyDisplay(plugin, this);
this.wordListContainer = createDiv({
cls: ELEMENT_CLASSES.containerWordList,
});
}
getDisplayText(): string {
@ -52,6 +57,15 @@ export class WordFrequencyView extends ItemView {
this.eventListener as EventListener
);
this.contentEl.empty();
const contentContainer = this.contentEl.createDiv({
cls: ELEMENT_CLASSES.containerContent,
});
this.display.createHeader(contentContainer);
this.display.createFilter(contentContainer);
contentContainer.appendChild(this.wordListContainer);
this.display.createThresholdDisplay(contentContainer);
this.updateContent();
}
@ -63,9 +77,7 @@ export class WordFrequencyView extends ItemView {
}
updateContent() {
this.contentEl.empty();
this.display.createHeader(this.contentEl);
const contentContainer = this.contentEl.createEl('div');
this.wordListContainer.empty();
const blacklist = new Set(
this.plugin.settings.blacklist.split(',').map((word) => word.trim())
);
@ -75,9 +87,8 @@ export class WordFrequencyView extends ItemView {
blacklist,
word,
count,
contentContainer
this.wordListContainer
);
});
this.display.createThresholdDisplay(this.contentEl);
}
}

View file

@ -1,4 +1,4 @@
import { PLUGIN_NAME } from '../constants';
import { ELEMENT_CLASSES, PLUGIN_NAME } from '../constants';
import WordFrequencyPlugin from '../main';
import { WordFrequencyDisplay } from '../WordFrequencyDisplay';
import { WordFrequencyView } from '../WordFrequencyView';
@ -141,20 +141,17 @@ describe('WordFrequencyDisplay', () => {
it('should set text and attribute in the content', () => {
display.createThresholdDisplay(contentEl);
const thresholdDisplay = contentEl.createEl('div', {
cls: 'threshold-display',
});
expect(contentEl.createEl).toHaveBeenCalledWith('div', {
cls: 'threshold-display',
cls: ELEMENT_CLASSES.containerThreshold,
});
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.'
);
// TODO: determine how to test the element from contentEl was called properly
// 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.'
// );
});
});
});

View file

@ -19,6 +19,7 @@ describe('WordFrequencyView', () => {
mockLeaf = new WorkspaceLeaf();
mockDisplay = {
addWordToSidebar: jest.fn(),
createFilter: jest.fn(),
createHeader: jest.fn(),
createThresholdDisplay: jest.fn(),
} as unknown as WordFrequencyDisplay;

View file

@ -8,6 +8,16 @@ export const DEFAULT_SETTINGS: WordFrequencySettings = {
threshold: 3,
};
export const ELEMENT_CLASSES = {
containerButton: 'word-frequency-button-container',
containerContent: 'word-frequency-sidebar-content',
containerCount: 'word-frequency-count-container',
containerRow: 'word-frequency-row',
containerThreshold: 'word-frequency-threshold-display',
containerWordList: 'word-frequency-word-list',
filter: 'word-frequency-filter',
};
export const EVENT_UPDATE = 'word-frequency-update';
export const FREQUENCY_ICON = 'file-chart-column-increasing';
export const PLUGIN_NAME = 'Word frequency';