add suggestions for regExp flags, mark selected flags, make regExp field looks pretty
This commit is contained in:
parent
470dd8176d
commit
7ddd6525c6
54
main.ts
54
main.ts
|
@ -17,6 +17,13 @@ import {
|
||||||
getObsidianFilesWithTagName,
|
getObsidianFilesWithTagName,
|
||||||
} from './src/services/obsidian.service';
|
} from './src/services/obsidian.service';
|
||||||
import { renderPreviewFiles } from './src/components/RenderPreviewFiles';
|
import { renderPreviewFiles } from './src/components/RenderPreviewFiles';
|
||||||
|
import { createBackslash } from './src/components/RegExpBackslash';
|
||||||
|
import {
|
||||||
|
REGEXP_FLAGS,
|
||||||
|
RegExpFlag,
|
||||||
|
RegExpFlags,
|
||||||
|
} from './src/constants/RegExpFlags';
|
||||||
|
import { RegExpFlagsSuggest } from './src/suggestions/RegExpFlagsSuggest';
|
||||||
|
|
||||||
interface BulkRenamePluginSettings {
|
interface BulkRenamePluginSettings {
|
||||||
folderName: string;
|
folderName: string;
|
||||||
|
@ -25,6 +32,10 @@ interface BulkRenamePluginSettings {
|
||||||
replacePattern: string;
|
replacePattern: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
userRegExp: string;
|
userRegExp: string;
|
||||||
|
regExpState: {
|
||||||
|
regExp: string;
|
||||||
|
flags: RegExpFlag[];
|
||||||
|
};
|
||||||
viewType: 'tags' | 'folder' | 'regexp';
|
viewType: 'tags' | 'folder' | 'regexp';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +45,10 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = {
|
||||||
existingSymbol: '',
|
existingSymbol: '',
|
||||||
replacePattern: '',
|
replacePattern: '',
|
||||||
userRegExp: '',
|
userRegExp: '',
|
||||||
|
regExpState: {
|
||||||
|
regExp: '',
|
||||||
|
flags: [],
|
||||||
|
},
|
||||||
tags: [],
|
tags: [],
|
||||||
viewType: 'folder',
|
viewType: 'folder',
|
||||||
};
|
};
|
||||||
|
@ -158,7 +173,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
||||||
.setName('Folder location')
|
.setName('Folder location')
|
||||||
.setDesc('Find files within the folder')
|
.setDesc('Find files within the folder')
|
||||||
.addSearch((cb) => {
|
.addSearch((cb) => {
|
||||||
new FolderSuggest(this.app, cb.inputEl);
|
new FolderSuggest(this.app, cb.inputEl, this.plugin);
|
||||||
cb.setPlaceholder('Example: folder1/')
|
cb.setPlaceholder('Example: folder1/')
|
||||||
.setValue(this.plugin.settings.folderName)
|
.setValue(this.plugin.settings.folderName)
|
||||||
.onChange((newFolder) => {
|
.onChange((newFolder) => {
|
||||||
|
@ -212,7 +227,9 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
||||||
new Setting(this.containerEl)
|
new Setting(this.containerEl)
|
||||||
.setName('RegExp')
|
.setName('RegExp')
|
||||||
.setDesc('all files by titles will be found')
|
.setDesc('all files by titles will be found')
|
||||||
.addSearch((cb) => {
|
.addText((cb) => {
|
||||||
|
const backslash = createBackslash('/');
|
||||||
|
cb.inputEl.insertAdjacentElement('beforebegin', backslash);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
cb.inputEl.addEventListener('keydown', (event) => {
|
cb.inputEl.addEventListener('keydown', (event) => {
|
||||||
if (event.key !== 'Enter') {
|
if (event.key !== 'Enter') {
|
||||||
|
@ -220,21 +237,40 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
||||||
}
|
}
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
|
|
||||||
this.plugin.settings.userRegExp = target.value;
|
this.plugin.settings.regExpState.regExp = target.value;
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
cb.setPlaceholder('Example: #tag, #tag2')
|
cb.setPlaceholder('Put your RegExp here')
|
||||||
.setValue(this.plugin.settings.userRegExp)
|
.setValue(this.plugin.settings.regExpState.regExp)
|
||||||
.onChange((newFolder) => {
|
.onChange((newFolder) => {
|
||||||
this.plugin.settings.userRegExp = newFolder;
|
this.plugin.settings.regExpState.regExp = newFolder;
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
this.getFilesByRegExp();
|
this.getFilesByRegExp();
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
cb.containerEl.addClass('bulk_regexp');
|
cb.inputEl.addClass('bulk_regexp');
|
||||||
cb.inputEl.addClass('bulk_input');
|
|
||||||
cb.inputEl.onblur = this.reRenderPreview;
|
cb.inputEl.onblur = this.reRenderPreview;
|
||||||
});
|
})
|
||||||
|
.addText((cb) => {
|
||||||
|
new RegExpFlagsSuggest(this.app, cb.inputEl, this.plugin);
|
||||||
|
const backslash = createBackslash('/');
|
||||||
|
cb.inputEl.insertAdjacentElement('beforebegin', backslash);
|
||||||
|
cb.inputEl.addEventListener('keydown', (event) => {
|
||||||
|
// @ts-ignore
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
cb.setPlaceholder('flags here')
|
||||||
|
// .setDisabled(true)
|
||||||
|
.setValue(this.plugin.settings.regExpState.flags.join(''))
|
||||||
|
.onChange((flag: RegExpFlag) => {
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
this.getFilesByRegExp();
|
||||||
|
});
|
||||||
|
cb.inputEl.addClass('bulk_regexp_flags');
|
||||||
|
})
|
||||||
|
.controlEl.addClass('bulk_regexp_control');
|
||||||
}
|
}
|
||||||
|
|
||||||
renderReplaceSymbol() {
|
renderReplaceSymbol() {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export const createBackslash = (textContent = '=> => => =>') => {
|
||||||
|
const previewLabel = window.document.createElement('div');
|
||||||
|
previewLabel.className = 'bulk_regexp_slash';
|
||||||
|
previewLabel.textContent = textContent;
|
||||||
|
return previewLabel;
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
export type RegExpFlag =
|
||||||
|
| 'g'
|
||||||
|
| 'm'
|
||||||
|
| 'i'
|
||||||
|
| 'x'
|
||||||
|
| 's'
|
||||||
|
| 'u'
|
||||||
|
| 'U'
|
||||||
|
| 'A'
|
||||||
|
| 'J'
|
||||||
|
| 'D';
|
||||||
|
|
||||||
|
export const REGEXP_FLAGS = [
|
||||||
|
'g',
|
||||||
|
'm',
|
||||||
|
'i',
|
||||||
|
'x',
|
||||||
|
's',
|
||||||
|
'u',
|
||||||
|
'U',
|
||||||
|
'A',
|
||||||
|
'J',
|
||||||
|
'D',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type RegExpFlags = typeof REGEXP_FLAGS;
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
||||||
|
|
||||||
|
import { TextInputSuggest } from './suggest';
|
||||||
|
import { REGEXP_FLAGS, RegExpFlag } from '../constants/RegExpFlags';
|
||||||
|
|
||||||
|
export class RegExpFlagsSuggest extends TextInputSuggest<RegExpFlag> {
|
||||||
|
// @ts-ignore TODO refactor types types
|
||||||
|
getSuggestions() {
|
||||||
|
return REGEXP_FLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion = (flag: RegExpFlag, el: HTMLElement) => {
|
||||||
|
const { regExpState } = this.plugin.settings;
|
||||||
|
const hasFlag = regExpState.flags.includes(flag);
|
||||||
|
if (hasFlag) {
|
||||||
|
el.addClass('bulk-flag-selected');
|
||||||
|
} else {
|
||||||
|
el.removeClass('bulk-flag-selected');
|
||||||
|
}
|
||||||
|
el.setText(flag);
|
||||||
|
};
|
||||||
|
|
||||||
|
selectSuggestion = (flag: RegExpFlag, event: MouseEvent | KeyboardEvent) => {
|
||||||
|
const { regExpState } = this.plugin.settings;
|
||||||
|
const target = event.target as HTMLDivElement;
|
||||||
|
|
||||||
|
const hasFlag = regExpState.flags.includes(flag);
|
||||||
|
if (hasFlag) {
|
||||||
|
regExpState.flags = regExpState.flags.filter((existingFlag) => {
|
||||||
|
return existingFlag !== flag;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
regExpState.flags = [...regExpState.flags, flag];
|
||||||
|
}
|
||||||
|
target.classList.toggle('bulk-flag-selected');
|
||||||
|
this.inputEl.value = regExpState.flags.join('');
|
||||||
|
// this.inputEl.trigger('input');
|
||||||
|
// this.settings.plugin.settings.regExpState.flags.push(file);
|
||||||
|
// this.inputEl.trigger('input');
|
||||||
|
// this.close();
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { App, ISuggestOwner, Scope } from 'obsidian';
|
import { App, ISuggestOwner, Scope } from 'obsidian';
|
||||||
import { createPopper, Instance as PopperInstance } from '@popperjs/core';
|
import { createPopper, Instance as PopperInstance } from '@popperjs/core';
|
||||||
|
import BulkRenamePlugin from '../../main';
|
||||||
|
|
||||||
const wrapAround = (value: number, size: number): number => {
|
const wrapAround = (value: number, size: number): number => {
|
||||||
return ((value % size) + size) % size;
|
return ((value % size) + size) % size;
|
||||||
|
@ -104,6 +105,7 @@ class Suggest<T> {
|
||||||
|
|
||||||
export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
||||||
protected app: App;
|
protected app: App;
|
||||||
|
protected plugin: BulkRenamePlugin;
|
||||||
protected inputEl: HTMLInputElement | HTMLTextAreaElement;
|
protected inputEl: HTMLInputElement | HTMLTextAreaElement;
|
||||||
|
|
||||||
private popper: PopperInstance;
|
private popper: PopperInstance;
|
||||||
|
@ -111,7 +113,12 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
||||||
private suggestEl: HTMLElement;
|
private suggestEl: HTMLElement;
|
||||||
private suggest: Suggest<T>;
|
private suggest: Suggest<T>;
|
||||||
|
|
||||||
constructor(app: App, inputEl: HTMLInputElement | HTMLTextAreaElement) {
|
constructor(
|
||||||
|
app: App,
|
||||||
|
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||||
|
plugin: BulkRenamePlugin,
|
||||||
|
) {
|
||||||
|
this.plugin = plugin;
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.inputEl = inputEl;
|
this.inputEl = inputEl;
|
||||||
this.scope = new Scope();
|
this.scope = new Scope();
|
||||||
|
@ -191,7 +198,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
||||||
this.suggestEl.detach();
|
this.suggestEl.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract getSuggestions(inputStr: string): T[];
|
abstract getSuggestions(inputStr?: string): T[];
|
||||||
abstract renderSuggestion(item: T, el: HTMLElement): void;
|
abstract renderSuggestion(item: T, el: HTMLElement): void;
|
||||||
abstract selectSuggestion(item: T): void;
|
abstract selectSuggestion(item: T, evt: MouseEvent | KeyboardEvent): void;
|
||||||
}
|
}
|
||||||
|
|
41
styles.css
41
styles.css
|
@ -24,35 +24,28 @@
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk_regexp {
|
.bulk_regexp_control {
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk_regexp_control > input {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk_regexp,
|
||||||
|
.bulk_regexp_flags {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk_regexp > input {
|
.bulk_regexp_flags {
|
||||||
color: green;
|
caret-color: transparent;
|
||||||
padding: 0 28px 0 14px;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk_regexp:before {
|
.bulk_regexp_slash {
|
||||||
content: '/';
|
font-size: 1.5em;
|
||||||
top: 2px;
|
opacity: 0.5;
|
||||||
left: -15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk_regexp:after {
|
.bulk-flag-selected {
|
||||||
content: '/';
|
background-color: lavender !important;
|
||||||
bottom: 5px;
|
|
||||||
right: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bulk_regexp:before,
|
|
||||||
.bulk_regexp:after {
|
|
||||||
color: #000080;
|
|
||||||
font-size: 30px;
|
|
||||||
/*background-color: #cccccc;*/
|
|
||||||
display: block;
|
|
||||||
/*text-align: center;*/
|
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue