obsidian#PluginSettingTab TypeScript Examples
The following examples show how to use
obsidian#PluginSettingTab.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: main.ts From luhman-obsidian-plugin with GNU General Public License v3.0 | 5 votes |
class LuhmanSettingTab extends PluginSettingTab {
plugin: NewZettel;
constructor(app: App, plugin: NewZettel) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let {containerEl} = this;
const {matchRule, separator, addTitle} = this.plugin.settings;
containerEl.empty();
containerEl.createEl('p', {text: 'The ID is a block of letters and numbers at the beginning of the filename'});
new Setting(containerEl)
.setName('ID matching rule')
.setDesc(
'Strict means filenames consist of only an ID. ' +
'Separator means the ID must be followed by the separator. ' +
'Fuzzy treats the first non-alphanumeric character as the end of the ID.')
.addDropdown(setting => setting
.addOption('strict', 'Strict')
.addOption('separator', 'Separator')
.addOption('fuzzy', 'Fuzzy')
.setValue(matchRule)
.onChange(async (value) => {
this.plugin.settings.matchRule = value;
await this.plugin.saveSettings()
this.display()
}));
if (matchRule !== 'strict'){
new Setting(containerEl)
.setName('Add titles automatically')
.setDesc('Add the separator and the title of the note when creating filenames')
.setDisabled(matchRule !== 'strict')
.addToggle(setting => setting
.setValue(addTitle)
.onChange(async (value) => {
this.plugin.settings.addTitle = value;
await this.plugin.saveSettings()
this.display()
}));
}
const useSeparator =
matchRule !== 'strict' &&
(addTitle || matchRule === 'separator')
if (useSeparator) {
new Setting(containerEl)
.setName('ID Separator')
.setDesc('Used between id and title, include whitespace padding if needed')
.setDisabled(useSeparator)
.addText(text => text
.setPlaceholder('Enter your separator')
.setValue(separator)
.onChange(async (value) => {
this.plugin.settings.separator = value;
await this.plugin.saveSettings();
}));
}
}
}
Example #2
Source File: settingsTabSection.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 5 votes |
constructor(
protected app: App,
protected mainSettingsTab: PluginSettingTab,
protected config: SwitcherPlusSettings,
) {}
Example #3
Source File: settings.ts From obsidian-emoji-shortcodes with MIT License | 5 votes |
export class EmojiPluginSettingTab extends PluginSettingTab {
plugin: EmojiShortcodesPlugin;
constructor(app: App, plugin: EmojiShortcodesPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Emoji Shortcodes Plugin' });
new Setting(containerEl)
.setName('Immediate Emoji Replace')
.setDesc('If this is turned on, Emoji shortcodes will be immediately replaced after typing. Otherwise they are still stored as a shortcode and you only see the Emoji in Preview Mode.')
.addToggle(cb => {
cb.setValue(this.plugin.settings.immediateReplace)
.onChange(async value => {
this.plugin.settings.immediateReplace = value;
await this.plugin.saveSettings();
})
});
new Setting(containerEl)
.setName('Emoji Suggester')
.setDesc('If this is turned on, a Suggester will appear everytime you type : followed by a letter. This will help you insert Emojis. (Doesn\'t work on mobile)')
.addToggle(cb => {
cb.setValue(this.plugin.settings.suggester)
.onChange(async value => {
this.plugin.settings.suggester = value;
await this.plugin.saveSettings();
})
});
new Setting(containerEl)
.setName('Donate')
.setDesc('If you like this Plugin, consider donating to support continued development:')
.addButton((bt) => {
bt.buttonEl.outerHTML = `<a href="https://www.buymeacoffee.com/phibr0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=phibr0&button_colour=5F7FFF&font_colour=ffffff&font_family=Inter&outline_colour=000000&coffee_colour=FFDD00"></a>`;
});
}
}
Example #4
Source File: relatedItemsSettingsTabSection.test.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 5 votes |
describe('relatedItemsSettingsTabSection', () => {
let mockApp: MockProxy<App>;
let mockPluginSettingTab: MockProxy<PluginSettingTab>;
let config: SwitcherPlusSettings;
let mockContainerEl: MockProxy<HTMLElement>;
let sut: RelatedItemsSettingsTabSection;
beforeAll(() => {
mockApp = mock<App>();
mockContainerEl = mock<HTMLElement>();
mockPluginSettingTab = mock<PluginSettingTab>({ containerEl: mockContainerEl });
config = new SwitcherPlusSettings(null);
sut = new RelatedItemsSettingsTabSection(mockApp, mockPluginSettingTab, config);
});
it('should display a header for the section', () => {
const addSectionTitleSpy = jest.spyOn(
SettingsTabSection.prototype,
'addSectionTitle',
);
sut.display(mockContainerEl);
expect(addSectionTitleSpy).toHaveBeenCalledWith(
mockContainerEl,
'Related Items List Mode Settings',
);
addSectionTitleSpy.mockRestore();
});
it('should show the mode trigger setting', () => {
const addTextSettingSpy = jest.spyOn(SettingsTabSection.prototype, 'addTextSetting');
sut.display(mockContainerEl);
expect(addTextSettingSpy).toBeCalledWith(
mockContainerEl,
'Related Items list mode trigger',
expect.any(String),
config.relatedItemsListCommand,
'relatedItemsListCommand',
config.relatedItemsListPlaceholderText,
);
addTextSettingSpy.mockRestore();
});
it('should show the excludeOpenRelatedFiles setting', () => {
const addToggleSettingSpy = jest.spyOn(
SettingsTabSection.prototype,
'addToggleSetting',
);
sut.display(mockContainerEl);
expect(addToggleSettingSpy).toBeCalledWith(
mockContainerEl,
'Exclude open files',
expect.any(String),
config.excludeOpenRelatedFiles,
'excludeOpenRelatedFiles',
);
addToggleSettingSpy.mockRestore();
});
});
Example #5
Source File: quickAddSettingsTab.ts From quickadd with MIT License | 5 votes |
export class QuickAddSettingsTab extends PluginSettingTab {
public plugin: QuickAdd;
private choiceView: ChoiceView;
constructor(app: App, plugin: QuickAdd) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let {containerEl} = this;
containerEl.empty();
containerEl.createEl('h2', {text: 'QuickAdd Settings'});
this.addChoicesSetting();
new Setting(this.containerEl)
.setName('Use Multi-line Input Prompt')
.setDesc('Use multi-line input prompt instead of single-line input prompt')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.inputPrompt === "multi-line")
.setTooltip("Use multi-line input prompt")
.onChange(value => {
if (value) {
this.plugin.settings.inputPrompt = "multi-line";
} else {
this.plugin.settings.inputPrompt = "single-line";
}
this.plugin.saveSettings();
})
)
}
hide(): any {
if (this.choiceView)
this.choiceView.$destroy();
}
private addChoicesSetting(): void {
const setting = new Setting(this.containerEl);
setting.infoEl.remove();
setting.settingEl.style.display = "block";
this.choiceView = new ChoiceView({
target: setting.settingEl,
props: {
app: this.app,
plugin: this.plugin,
choices: this.plugin.settings.choices,
saveChoices: async (choices: IChoice[]) => {
this.plugin.settings.choices = choices;
await this.plugin.saveSettings();
},
macros: this.plugin.settings.macros,
saveMacros: async (macros: IMacro[]) => {
this.plugin.settings.macros = macros;
await this.plugin.saveSettings();
}
}
});
}
}
Example #6
Source File: settings.ts From obsidian-tracker with MIT License | 5 votes |
export class TrackerSettingTab extends PluginSettingTab {
plugin: Tracker;
constructor(app: App, plugin: Tracker) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
new Setting(containerEl)
.setName("Default folder location")
.setDesc(
"Files in this folder will be parsed and used as input data of the tracker plugin.\nYou can also override it using 'folder' argument in the tracker codeblock."
)
.addText((text) =>
text
.setPlaceholder("Folder Path")
.setValue(this.plugin.settings.folder)
.onChange(async (value) => {
this.plugin.settings.folder = value;
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName("Default date format")
.setDesc(
"This format is used to parse the date in your diary title.\nYou can also override it using 'dateFormat' argument in the tracker codeblock."
)
.addText((text) =>
text
.setPlaceholder("YYYY-MM-DD")
.setValue(this.plugin.settings.dateFormat)
.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
})
);
}
}
Example #7
Source File: SettingsTab.ts From obsidian-rss with GNU General Public License v3.0 | 4 votes |
export class RSSReaderSettingsTab extends PluginSettingTab {
plugin: RssReaderPlugin;
constructor(app: App, plugin: RssReaderPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.createEl('h2', {text: t("RSS_Reader") + " " + t("settings")});
containerEl.createEl('h3', {text: t("file_creation")});
const templateDesc = new DocumentFragment();
templateDesc.createDiv().innerHTML = t("template_new_help") + "<br>" + t("available_variables") + `<br>` +
`<strong>{{title}}</strong> → ${t("article_title")}<br>` +
`<strong>{{link}}</strong> → ${t("article_link")}<br>` +
`<strong>{{author}}</strong> → ${t("article_author")}<br>` +
`<strong>{{published}}</strong> → ${t("article_published")}<br>` +
`<strong>{{created}}</strong> → ${t("note_created")}<br>` +
`<strong>{{description}}</strong> → ${t("article_description")}<br>` +
`<strong>{{content}}</strong> → ${t("article_content")}<br>` +
`<strong>{{folder}}</strong> → ${t("feed_folder")}<br>` +
`<strong>{{feed}}</strong> → ${t("feed_title")}<br>` +
`<strong>{{filename}}</strong> → ${t("filename")}<br>` +
`<strong>{{tags}}</strong> → ${t("article_tags")}<br>` +
`<strong>{{media}}</strong> → ${t("article_media")}<br>` +
`<strong>{{highlights}}</strong> → ${t("highlights")}`;
new Setting(containerEl)
.setName(t("template_new"))
.setDesc(templateDesc)
.addTextArea((textArea: TextAreaComponent) => {
textArea
.setValue(this.plugin.settings.template)
.setPlaceholder(DEFAULT_SETTINGS.template)
.onChange(async (value) => {
await this.plugin.writeSettings(() => ({
template: value
}));
});
textArea.inputEl.setAttr("rows", 15);
textArea.inputEl.setAttr("cols", 50);
});
const pasteTemplateDesc = new DocumentFragment();
pasteTemplateDesc.createDiv().innerHTML = t("template_new_help") + "<br>" + t("available_variables") + `<br>` +
`<strong>{{title}}</strong> → ${t("article_title")}<br>` +
`<strong>{{link}}</strong> → ${t("article_link")}<br>` +
`<strong>{{author}}</strong> → ${t("article_author")}<br>` +
`<strong>{{published}}</strong> → ${t("article_published")}<br>` +
`<strong>{{created}}</strong> → ${t("note_created")}<br>` +
`<strong>{{description}}</strong> → ${t("article_description")}<br>` +
`<strong>{{content}}</strong> → ${t("article_content")}<br>` +
`<strong>{{folder}}</strong> → ${t("feed_folder")}<br>` +
`<strong>{{feed}}</strong> → ${t("feed_title")}<br>` +
`<strong>{{tags}}</strong> → ${t("article_tags")}<br>` +
`<strong>{{media}}</strong> → ${t("article_media")}<br>` +
`<strong>{{highlights}}</strong> → ${t("highlights")}`;
new Setting(containerEl)
.setName(t("template_paste"))
.setDesc(pasteTemplateDesc)
.addTextArea((textArea: TextAreaComponent) => {
textArea
.setValue(this.plugin.settings.pasteTemplate)
.setPlaceholder(DEFAULT_SETTINGS.pasteTemplate)
.onChange(async (value) => {
await this.plugin.writeSettings(() => ({
pasteTemplate: value
}));
});
textArea.inputEl.setAttr("rows", 15);
textArea.inputEl.setAttr("cols", 50);
});
new Setting(containerEl)
.setName(t("file_location"))
.setDesc(t("file_location_help"))
.addDropdown(async (dropdown: DropdownComponent) => {
dropdown
.addOption("default", t("file_location_default"))
.addOption("custom", t("file_location_custom"))
.setValue(this.plugin.settings.saveLocation)
.onChange(async (value: string) => {
await this.plugin.writeSettings(() => (
{saveLocation: value}
));
this.display();
});
});
if (this.plugin.settings.saveLocation == "custom") {
new Setting(containerEl)
.setName(t("file_location_folder"))
.setDesc(t("file_location_folder_help"))
.addSearch(async (search: SearchComponent) => {
new FolderSuggest(this.app, search.inputEl);
search
.setValue(this.plugin.settings.saveLocationFolder)
.setPlaceholder(DEFAULT_SETTINGS.saveLocationFolder)
.onChange(async (value: string) => {
await this.plugin.writeSettings(() => (
{saveLocationFolder: value}
));
});
});
}
let dateFormatSampleEl: MomentFormatComponent;
const dateFormat = new Setting(containerEl)
.setName(t("date_format"))
.addMomentFormat((format: MomentFormatComponent) => {
dateFormatSampleEl = format
.setDefaultFormat(DEFAULT_SETTINGS.dateFormat)
.setPlaceholder(DEFAULT_SETTINGS.dateFormat)
.setValue(this.plugin.settings.dateFormat)
.onChange(async (value) => {
await this.plugin.writeSettings(() => (
{dateFormat: value}
));
});
});
const referenceLink = dateFormat.descEl.createEl("a");
referenceLink.setAttr("href", "https://momentjs.com/docs/#/displaying/format/");
referenceLink.setText(t("syntax_reference"));
const text = dateFormat.descEl.createDiv("text");
text.setText(t("syntax_looks"));
const sampleEl = text.createSpan("sample");
dateFormatSampleEl.setSampleEl(sampleEl);
dateFormat.addExtraButton((button) => {
button
.setIcon('reset')
.setTooltip(t("reset"))
.onClick(async () => {
await this.plugin.writeSettings(() => ({
dateFormat: DEFAULT_SETTINGS.dateFormat
}));
this.display();
});
});
new Setting(containerEl)
.setName(t("ask_filename"))
.setDesc(t("ask_filename_help"))
.addToggle((toggle: ToggleComponent) => {
toggle
.setValue(this.plugin.settings.askForFilename)
.onChange(async (value) => {
await this.plugin.writeSettings(() => ({
askForFilename: value
}));
});
});
new Setting(containerEl)
.setName(t("default_filename"))
.setDesc(t("default_filename_help"))
.addText((text) => {
text
.setPlaceholder(DEFAULT_SETTINGS.defaultFilename)
.setValue(this.plugin.settings.defaultFilename)
.onChange(async (value) => {
if (value.length > 0) {
await this.plugin.writeSettings(() => ({
defaultFilename: value
}));
} else {
new Notice(t("fix_errors"));
}
});
});
containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});
containerEl.createEl("h3", {text: "Misc"});
const refresh = new Setting(containerEl)
.setName(t("refresh_time"))
.setDesc(t("refresh_time_help"))
.addText((text: TextComponent) => {
text
.setPlaceholder(String(DEFAULT_SETTINGS.updateTime))
.setValue(String(this.plugin.settings.updateTime))
.onChange(async (value) => {
if (value.length === 0) {
new Notice(t("specify_positive_number"));
return;
}
if (Number(value) < 0) {
new Notice(t("specify_positive_number"));
return;
}
await this.plugin.writeSettings(() => (
{updateTime: Number(value)}
));
});
text.inputEl.setAttr("type", "number");
text.inputEl.setAttr("min", "1");
//we don't want decimal numbers.
text.inputEl.setAttr("onkeypress", "return event.charCode >= 48 && event.charCode <= 57");
});
refresh.addExtraButton((button) => {
button
.setIcon('reset')
.setTooltip('restore default')
.onClick(async () => {
await this.plugin.writeSettings(() => ({
updateTime: DEFAULT_SETTINGS.updateTime
}));
this.display();
});
});
new Setting(containerEl)
.setName(t("multi_device_usage"))
.setDesc(t("multi_device_usage_help"))
.addToggle((toggle: ToggleComponent) => {
return toggle
.setValue(this.plugin.settings.autoSync)
.onChange(async (value) => {
await this.plugin.writeSettings(() => ({
autoSync: value
}));
});
});
new Setting(containerEl)
.setName(t("display_style"))
.addDropdown(dropdown => {
return dropdown
.addOption("list", t("list"))
.addOption("cards", t("cards"))
.setValue(this.plugin.settings.displayStyle)
.onChange(async (value) => {
await this.plugin.writeSettings(() => ({
displayStyle: value
}));
});
});
containerEl.createEl("h2", {text: t("content")});
const filterContainer = containerEl.createDiv("filter-container");
displayFilterSettings(this.plugin, filterContainer);
const feedsContainer = containerEl.createDiv(
"feed-container"
);
displayFeedSettings(this.plugin, feedsContainer);
containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});
const hotkeyContainer = containerEl.createDiv("hotkey-container");
displayHotkeys(this.plugin, hotkeyContainer);
containerEl.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});
const details = containerEl.createEl("details");
const summary = details.createEl("summary");
summary.setText(t("advanced"));
const advanced = details.createDiv("advanced");
advanced.createEl("h3", {text: t("customize_terms")});
advanced.createSpan({text: "Change a few selected terms here. You can help translating the plugin "});
advanced.createEl("a", {text: "here", href: "https://github.com/joethei/obsidian-rss/tree/master/src/l10n"});
new Setting(advanced)
.setName(t("folders"))
.addText(text => {
text
.setPlaceholder(t("folders"))
.setValue(this.plugin.settings.renamedText.folders)
.onChange(async value => {
await this.plugin.writeSettings(() => ({
renamedText: {
...this.plugin.settings.renamedText,
folders: value
}
}));
});
});
new Setting(advanced)
.setName(t("filtered_folders"))
.addText(text => {
text
.setPlaceholder(t("filtered_folders"))
.setValue(this.plugin.settings.renamedText.filtered_folders)
.onChange(async value => {
await this.plugin.writeSettings(() => ({
renamedText: {
...this.plugin.settings.renamedText,
filtered_folders: value
}
}));
});
});
new Setting(advanced)
.setName(t("no_folder"))
.addText(text => {
text
.setPlaceholder(t("no_folder"))
.setValue(this.plugin.settings.renamedText.no_folder)
.onChange(async value => {
await this.plugin.writeSettings(() => ({
renamedText: {
...this.plugin.settings.renamedText,
no_folder: value
}
}));
});
});
advanced.createEl("hr", {attr: {style: "border-top: 5px solid var(--background-modifier-border);"}});
new Setting(advanced)
.setName(t("display_media"))
.addToggle(toggle => {
toggle
.setValue(this.plugin.settings.displayMedia)
.onChange(async value => {
await this.plugin.writeSettings(() => ({
displayMedia: value
}));
});
});
}
}
Example #8
Source File: main.ts From obsidian-linter with MIT License | 4 votes |
class SettingTab extends PluginSettingTab {
plugin: LinterPlugin;
constructor(app: App, plugin: LinterPlugin) {
super(app, plugin);
this.plugin = plugin;
// Inject display functions. Necessary because the Settings object cannot be used in tests.
BooleanOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
new Setting(containerEl)
.setName(this.name)
.setDesc(this.description)
.addToggle((toggle) => {
toggle.setValue(settings.ruleConfigs[this.ruleName][this.name]);
toggle.onChange((value) => {
this.setOption(value, settings);
plugin.settings = settings;
plugin.saveData(plugin.settings);
});
});
};
TextOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
new Setting(containerEl)
.setName(this.name)
.setDesc(this.description)
.addText((textbox) => {
textbox.setValue(settings.ruleConfigs[this.ruleName][this.name]);
textbox.onChange((value) => {
this.setOption(value, settings);
plugin.settings = settings;
plugin.saveData(plugin.settings);
});
});
};
TextAreaOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
new Setting(containerEl)
.setName(this.name)
.setDesc(this.description)
.addTextArea((textbox) => {
textbox.setValue(settings.ruleConfigs[this.ruleName][this.name]);
textbox.onChange((value) => {
this.setOption(value, settings);
plugin.settings = settings;
plugin.saveData(plugin.settings);
});
});
};
MomentFormatOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
new Setting(containerEl)
.setName(this.name)
.setDesc(this.description)
.addMomentFormat((format) => {
format.setValue(settings.ruleConfigs[this.ruleName][this.name]);
format.setPlaceholder('dddd, MMMM Do YYYY, h:mm:ss a');
format.onChange((value) => {
this.setOption(value, settings);
plugin.settings = settings;
plugin.saveData(plugin.settings);
});
});
};
DropdownOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
new Setting(containerEl)
.setName(this.name)
.setDesc(this.description)
.addDropdown((dropdown) => {
dropdown.setValue(settings.ruleConfigs[this.ruleName][this.name]);
for (const option of this.options) {
dropdown.addOption(option.value, option.value);
}
dropdown.onChange((value) => {
this.setOption(value, settings);
plugin.settings = settings;
plugin.saveData(plugin.settings);
});
});
};
}
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.createEl('h2', {text: 'General Settings'});
new Setting(containerEl)
.setName('Lint on save')
.setDesc('Lint the file on manual save (when `Ctrl + S` is pressed)')
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.lintOnSave)
.onChange(async (value) => {
this.plugin.settings.lintOnSave = value;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName('Display message on lint')
.setDesc('Display the number of characters changed after linting')
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.displayChanged)
.onChange(async (value) => {
this.plugin.settings.displayChanged = value;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName('Folders to ignore')
.setDesc('Folders to ignore when linting all files or linting on save. Enter folder paths separated by newlines')
.addTextArea((textArea) => {
textArea
.setValue(this.plugin.settings.foldersToIgnore.join('\n'))
.onChange(async (value) => {
this.plugin.settings.foldersToIgnore = value.split('\n');
await this.plugin.saveSettings();
});
});
let prevSection = '';
for (const rule of rules) {
if (rule.type !== prevSection) {
containerEl.createEl('h2', {text: rule.type});
prevSection = rule.type;
}
containerEl.createEl('h3', {}, (el) =>{
el.innerHTML = `<a href="${rule.getURL()}">${rule.name}</a>`;
});
for (const option of rule.options) {
option.display(containerEl, this.plugin.settings, this.plugin);
}
}
}
}
Example #9
Source File: main.ts From quick_latex_obsidian with MIT License | 4 votes |
class QuickLatexSettingTab extends PluginSettingTab {
plugin: QuickLatexPlugin;
constructor(app: App, plugin: QuickLatexPlugin) {
super(app, plugin);
this.plugin = plugin;
}
public display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Quick Latex for Obsidian - Settings' });
new Setting(containerEl)
.setName('Autoclose $$ symbols')
.setDesc('Typing one $ symbol will automatically lose with another $ symbol '+
'(best used with "Move cursor between $$ symbols" function')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoCloseMath_toggle)
.onChange(async (value) => {
this.plugin.settings.autoCloseMath_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Move cursor between $$ symbols')
.setDesc('Typing two consecutive $ symbols will automatically shift the cursor in between the $$ symbols')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.moveIntoMath_toggle)
.onChange(async (value) => {
this.plugin.settings.moveIntoMath_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Enclose selected expression with math symbol $$')
.setDesc('Select an expression and press "$" key will automatically ' +
'enclose the expression with the math symbols.')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.encloseSelection_toggle)
.onChange(async (value) => {
this.plugin.settings.encloseSelection_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Autoclose {} curly brackets')
.setDesc('Typing "{" will automatically close with "}"')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoCloseCurly_toggle)
.onChange(async (value) => {
this.plugin.settings.autoCloseCurly_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Autoclose [] square brackets')
.setDesc('Typing "[" will automatically close with "]"')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoCloseSquare_toggle)
.onChange(async (value) => {
this.plugin.settings.autoCloseSquare_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Autoclose () round brackets')
.setDesc('Typing "(" will automatically close with ")"')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoCloseRound_toggle)
.onChange(async (value) => {
this.plugin.settings.autoCloseRound_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Auto append "\\limits" after "\\sum"')
.setDesc('Typing "\\sum" will automatically append "\\limits" to shorten the syntax' +
' for proper display of the limits for summation symbol.')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoSumLimit_toggle)
.onChange(async (value) => {
this.plugin.settings.autoSumLimit_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Auto enlarge brackets that contains \\sum, \\int or \\frac')
.setDesc('Place cursor right after a () or [] bracketed expression that contains either ' +
'\\sum, \\int or \\frac and press the space key, the outermost brackets will be' +
' appended with \\left and \\right in order to display larger brackets to enclose these big expressions.')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoLargeBracket_toggle)
.onChange(async (value) => {
this.plugin.settings.autoLargeBracket_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Auto enclose expression after superscipt with {}')
.setDesc('Typing expression after superscript "^" symbol follow by a "space" key ' +
'will automatically surround the expression with "{}"')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoEncloseSup_toggle)
.onChange(async (value) => {
this.plugin.settings.autoEncloseSup_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Auto enclose expression after subscript with {}')
.setDesc('Typing expression after subscript "_" symbol follow by a "space" key ' +
'will automatically surround the expression with "{}". ' +
'Note: expression more than 10 characters long will be ignored.')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoEncloseSub_toggle)
.onChange(async (value) => {
this.plugin.settings.autoEncloseSub_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Type "/" instead of \\frac{}{}')
.setDesc('Use "/" symbol for quickly typing fractions. eg. type "1/2" followed by a "space" key' +
' to transform to \\frac{1}{2}')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.autoFraction_toggle)
.onChange(async (value) => {
this.plugin.settings.autoFraction_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Shortcut for Align Block')
.setDesc('Use shortcut key to quickly insert \\begin{align*} \\end{align*} block. ' +
'Default: "Alt+Shift+A" (Mac: "Option+Shift+A")')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.addAlignBlock_toggle)
.onChange(async (value) => {
this.plugin.settings.addAlignBlock_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Align Block Parameter')
.setDesc('Set the text parameter in \\begin{parameter} and \\end{parameter}.')
.addText((text) => text
.setPlaceholder('default: align*')
.setValue(this.plugin.settings.addAlignBlock_parameter)
.onChange(async (value) => {
this.plugin.settings.addAlignBlock_parameter = value;
await this.plugin.saveData(this.plugin.settings);
}));
new Setting(containerEl)
.setName('Shortcut for Matrix Block')
.setDesc('Use shortcut key to quickly insert \\begin{pmatrix} \\end{pmatrix} block. ' +
'Default: "Alt+Shift+M" (Mac: "Option+Shift+M")')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.addMatrixBlock_toggle)
.onChange(async (value) => {
this.plugin.settings.addMatrixBlock_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Matrix Block Parameter')
.setDesc('Set the text parameter in \\begin{parameter} and \\end{parameter}.')
.addText((text) => text
.setPlaceholder('default: pmatrix')
.setValue(this.plugin.settings.addMatrixBlock_parameter)
.onChange(async (value) => {
this.plugin.settings.addMatrixBlock_parameter = value;
await this.plugin.saveData(this.plugin.settings);
}));
new Setting(containerEl)
.setName('Shortcut for Cases Block')
.setDesc('Use shortcut key to quickly insert \\begin{cases} \\end{cases} block. ' +
'Default: "Alt+Shift+C" (Mac: "Option+Shift+C")')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.addCasesBlock_toggle)
.onChange(async (value) => {
this.plugin.settings.addCasesBlock_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('Custom Shorthand')
.setDesc('Use custom shorthand (can be multiple letters) for common latex strings. '+
'Eg, typing "al" followed by "space" key will replace with "\\alpha"')
.addToggle((toggle) => toggle
.setValue(this.plugin.settings.customShorthand_toggle)
.onChange(async (value) => {
this.plugin.settings.customShorthand_toggle = value;
await this.plugin.saveData(this.plugin.settings);
this.display();
}));
new Setting(containerEl)
.setName('【updated!】Custom Shorthand Parameter')
.setDesc('Separate the multi-letters shorthand and the snippet with ":" and '+
'end each set of shorthand snippet pair by ";" and a newline. '+
'For expressions that end with "{}", the cursor will automatically be placed within the bracket. '+
'Alternatively, you can type "#cursor" within the snippet to set the cursor location after replacement. '+
'You can also include "#tab" within the snippet for use cases such as multiple {}s (e.g. \\binom{#cursor}{#tab}). '+
'Pressing tab key in such cases will jump the cursor to the next "#tab" keyword.'+
'Shorthands now support multiline snippets too! '+
'(try uninstall then reinstalling the plugin to see the new set of shorthands.)')
.setClass("text-snippets-class")
.addTextArea((text) => text
.setValue(this.plugin.settings.customShorthand_parameter)
.onChange(async (value) => {
this.plugin.settings.customShorthand_parameter = value;
while(value.slice(-1)=="\n"){
value = value.slice(0,-1)
}
if(value.slice(-1)==";"){
value = value.slice(0,-1)
}
if(value.lastIndexOf(";\n")==-1){
this.plugin.shorthand_array = value.split(",").map(item=>item.split(":").map(item=>item.trim()));
} else {
this.plugin.shorthand_array = value.split(";\n").map(item=>item.split(":"));
}
await this.plugin.saveData(this.plugin.settings);
}));
};
}
Example #10
Source File: settings.ts From obsidian-calendar-plugin with MIT License | 4 votes |
export class CalendarSettingsTab extends PluginSettingTab {
private plugin: CalendarPlugin;
constructor(app: App, plugin: CalendarPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
this.containerEl.empty();
if (!appHasDailyNotesPluginLoaded()) {
this.containerEl.createDiv("settings-banner", (banner) => {
banner.createEl("h3", {
text: "⚠️ Daily Notes plugin not enabled",
});
banner.createEl("p", {
cls: "setting-item-description",
text:
"The calendar is best used in conjunction with either the Daily Notes plugin or the Periodic Notes plugin (available in the Community Plugins catalog).",
});
});
}
this.containerEl.createEl("h3", {
text: "General Settings",
});
this.addDotThresholdSetting();
this.addWeekStartSetting();
this.addConfirmCreateSetting();
this.addShowWeeklyNoteSetting();
if (
this.plugin.options.showWeeklyNote &&
!appHasPeriodicNotesPluginLoaded()
) {
this.containerEl.createEl("h3", {
text: "Weekly Note Settings",
});
this.containerEl.createEl("p", {
cls: "setting-item-description",
text:
"Note: Weekly Note settings are moving. You are encouraged to install the 'Periodic Notes' plugin to keep the functionality in the future.",
});
this.addWeeklyNoteFormatSetting();
this.addWeeklyNoteTemplateSetting();
this.addWeeklyNoteFolderSetting();
}
this.containerEl.createEl("h3", {
text: "Advanced Settings",
});
this.addLocaleOverrideSetting();
}
addDotThresholdSetting(): void {
new Setting(this.containerEl)
.setName("Words per dot")
.setDesc("How many words should be represented by a single dot?")
.addText((textfield) => {
textfield.setPlaceholder(String(DEFAULT_WORDS_PER_DOT));
textfield.inputEl.type = "number";
textfield.setValue(String(this.plugin.options.wordsPerDot));
textfield.onChange(async (value) => {
this.plugin.writeOptions(() => ({
wordsPerDot: value !== "" ? Number(value) : undefined,
}));
});
});
}
addWeekStartSetting(): void {
const { moment } = window;
const localizedWeekdays = moment.weekdays();
const localeWeekStartNum = window._bundledLocaleWeekSpec.dow;
const localeWeekStart = moment.weekdays()[localeWeekStartNum];
new Setting(this.containerEl)
.setName("Start week on:")
.setDesc(
"Choose what day of the week to start. Select 'Locale default' to use the default specified by moment.js"
)
.addDropdown((dropdown) => {
dropdown.addOption("locale", `Locale default (${localeWeekStart})`);
localizedWeekdays.forEach((day, i) => {
dropdown.addOption(weekdays[i], day);
});
dropdown.setValue(this.plugin.options.weekStart);
dropdown.onChange(async (value) => {
this.plugin.writeOptions(() => ({
weekStart: value as IWeekStartOption,
}));
});
});
}
addConfirmCreateSetting(): void {
new Setting(this.containerEl)
.setName("Confirm before creating new note")
.setDesc("Show a confirmation modal before creating a new note")
.addToggle((toggle) => {
toggle.setValue(this.plugin.options.shouldConfirmBeforeCreate);
toggle.onChange(async (value) => {
this.plugin.writeOptions(() => ({
shouldConfirmBeforeCreate: value,
}));
});
});
}
addShowWeeklyNoteSetting(): void {
new Setting(this.containerEl)
.setName("Show week number")
.setDesc("Enable this to add a column with the week number")
.addToggle((toggle) => {
toggle.setValue(this.plugin.options.showWeeklyNote);
toggle.onChange(async (value) => {
this.plugin.writeOptions(() => ({ showWeeklyNote: value }));
this.display(); // show/hide weekly settings
});
});
}
addWeeklyNoteFormatSetting(): void {
new Setting(this.containerEl)
.setName("Weekly note format")
.setDesc("For more syntax help, refer to format reference")
.addText((textfield) => {
textfield.setValue(this.plugin.options.weeklyNoteFormat);
textfield.setPlaceholder(DEFAULT_WEEK_FORMAT);
textfield.onChange(async (value) => {
this.plugin.writeOptions(() => ({ weeklyNoteFormat: value }));
});
});
}
addWeeklyNoteTemplateSetting(): void {
new Setting(this.containerEl)
.setName("Weekly note template")
.setDesc(
"Choose the file you want to use as the template for your weekly notes"
)
.addText((textfield) => {
textfield.setValue(this.plugin.options.weeklyNoteTemplate);
textfield.onChange(async (value) => {
this.plugin.writeOptions(() => ({ weeklyNoteTemplate: value }));
});
});
}
addWeeklyNoteFolderSetting(): void {
new Setting(this.containerEl)
.setName("Weekly note folder")
.setDesc("New weekly notes will be placed here")
.addText((textfield) => {
textfield.setValue(this.plugin.options.weeklyNoteFolder);
textfield.onChange(async (value) => {
this.plugin.writeOptions(() => ({ weeklyNoteFolder: value }));
});
});
}
addLocaleOverrideSetting(): void {
const { moment } = window;
const sysLocale = navigator.language?.toLowerCase();
new Setting(this.containerEl)
.setName("Override locale:")
.setDesc(
"Set this if you want to use a locale different from the default"
)
.addDropdown((dropdown) => {
dropdown.addOption("system-default", `Same as system (${sysLocale})`);
moment.locales().forEach((locale) => {
dropdown.addOption(locale, locale);
});
dropdown.setValue(this.plugin.options.localeOverride);
dropdown.onChange(async (value) => {
this.plugin.writeOptions(() => ({
localeOverride: value as ILocaleOverride,
}));
});
});
}
}
Example #11
Source File: settings-tab.ts From better-word-count with MIT License | 4 votes |
export class BetterWordCountSettingsTab extends PluginSettingTab {
private disableTextAreas: boolean;
constructor(app: App, private plugin: BetterWordCount) {
super(app, plugin);
this.disableTextAreas =
this.plugin.settings.preset.name === "custom" ? false : true;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "Better Word Count Settings" });
// General Settings
containerEl.createEl("h3", { text: "General Settings" });
new Setting(containerEl)
.setName("Collect Statistics")
.setDesc(
"Reload Required for change to take effect. Turn on to start collecting daily statistics of your writing. Stored in the .vault-stats file in the root of your vault. This is required for counts of the day."
)
.addToggle((cb: ToggleComponent) => {
cb.setValue(this.plugin.settings.collectStats);
cb.onChange(async (value: boolean) => {
this.plugin.settings.collectStats = value;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Don't Count Comments")
.setDesc("Turn on if you don't want markdown comments to be counted.")
.addToggle((cb: ToggleComponent) => {
cb.setValue(this.plugin.settings.countComments);
cb.onChange(async (value: boolean) => {
this.plugin.settings.countComments = value;
await this.plugin.saveSettings();
});
});
// Status Bar Settings
containerEl.createEl("h3", { text: "Status Bar Settings" });
new Setting(containerEl)
.setName("Select a Preset")
.setDesc(
"Presets are premade status bar expressions. Overides status bar settings."
)
.addDropdown((cb: DropdownComponent) => {
PRESETS.forEach((preset: PresetOption) => {
cb.addOption(preset.name, preset.name);
});
cb.setValue(this.plugin.settings.preset.name);
cb.onChange(async (value: string) => {
let newPreset = PRESETS.find((preset) => preset.name === value);
this.plugin.settings.preset = newPreset;
this.plugin.settings.statusBarQuery = newPreset.statusBarQuery;
this.plugin.settings.statusBarAltQuery = newPreset.statusBarAltQuery;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Status Bar Text")
.setDesc("Customize the Status Bar text with this.")
.addTextArea((cb: TextAreaComponent) => {
cb.setPlaceholder("Enter an expression...");
cb.setValue(this.plugin.settings.statusBarQuery);
cb.onChange((value: string) => {
let newPreset = PRESETS.find((preset) => preset.name === "custom");
this.plugin.settings.preset = newPreset;
this.plugin.settings.statusBarQuery = value;
this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Alternative Status Bar Text")
.setDesc("Customize the Alternative Status Bar text with this.")
.addTextArea((cb: TextAreaComponent) => {
cb.setPlaceholder("Enter an expression...");
cb.setValue(this.plugin.settings.statusBarAltQuery);
cb.onChange((value: string) => {
let newPreset = PRESETS.find((preset) => preset.name === "custom");
this.plugin.settings.preset = newPreset;
this.plugin.settings.statusBarAltQuery = value;
this.plugin.saveSettings();
});
});
this.containerEl.createEl("h3", {
text: "Syntax for the status bars works like this: ",
});
this.containerEl.createEl("li", {
text: "To get a stat input the name of the stat in between `{}` eg. `{word_count}`.",
});
this.containerEl.createEl("li", {
text: "All other words remain.",
});
this.containerEl.createEl("br");
this.containerEl.createEl("h4", {
text: "Available Stats:",
});
this.containerEl.createEl("p", {
text:
"word_count, " +
"character_count, " +
"sentence_count, " +
"total_word_count, " +
"total_character_count, " +
"total_sentence_count, " +
"file_count, " +
"words_today, " +
"characters_today, " +
"sentences_today, ",
});
}
}
Example #12
Source File: SuperchargedLinksSettingTab.ts From obsidian_supercharged_links with MIT License | 4 votes |
export default class SuperchargedLinksSettingTab extends PluginSettingTab {
plugin: SuperchargedLinks;
debouncedGenerate: Function;
constructor(app: App, plugin: SuperchargedLinks) {
super(app, plugin);
this.plugin = plugin;
this.debouncedGenerate = debounce(this._generateSnippet, 1000, true);
}
display(): void {
let {containerEl} = this;
containerEl.empty();
/* Managing extra attirbutes for a.internal-link */
new Setting(containerEl)
.setName('Target Attributes for styling')
.setDesc('Frontmatter attributes to target, comma separated')
.addTextArea((text) => {text
.setPlaceholder('Enter attributes as string, comma separated')
.setValue(this.plugin.settings.targetAttributes.join(', '))
.onChange(async (value) => {
this.plugin.settings.targetAttributes = value.replace(/\s/g,'').split(',');
if (this.plugin.settings.targetAttributes.length === 1 && !this.plugin.settings.targetAttributes[0]) {
this.plugin.settings.targetAttributes = [];
}
await this.plugin.saveSettings();
})
text.inputEl.rows = 6;
text.inputEl.cols = 25;
});
containerEl.createEl('h4', {text: 'Styling'});
const styleSettingDescription = containerEl.createDiv();
styleSettingDescription.innerHTML = `
Styling can be done using the Style Settings plugin.
<ol>
<li>Create selectors down below.</li>
<li>Go to the Style Settings tab and style your links!</li>
</ol>`
const selectorDiv = containerEl.createDiv();
this.drawSelectors(selectorDiv);
containerEl.createEl('h4', {text: 'Settings'});
new Setting(containerEl)
.setName('Enable in Editor')
.setDesc('If true, this will also supercharge internal links in the editor view of a note.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.enableEditor)
toggle.onChange(value => {
this.plugin.settings.enableEditor = value
this.plugin.saveSettings()
})
})
new Setting(containerEl)
.setName('Enable in File Browser')
.setDesc('If true, this will also supercharge the file browser.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.enableFileList)
toggle.onChange(value => {
this.plugin.settings.enableFileList = value
this.plugin.saveSettings()
})
})
new Setting(containerEl)
.setName('Enable in Plugins')
.setDesc('If true, this will also supercharge plugins like the backlinks and forward links panels.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.enableBacklinks)
toggle.onChange(value => {
this.plugin.settings.enableBacklinks = value
this.plugin.saveSettings()
});
});
new Setting(containerEl)
.setName('Enable in Quick Switcher')
.setDesc('If true, this will also supercharge the quick switcher.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.enableQuickSwitcher)
toggle.onChange(value => {
this.plugin.settings.enableQuickSwitcher = value
this.plugin.saveSettings()
});
});
new Setting(containerEl)
.setName('Enable in Link Autocompleter')
.setDesc('If true, this will also supercharge the link autocompleter.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.enableSuggestor)
toggle.onChange(value => {
this.plugin.settings.enableSuggestor = value
this.plugin.saveSettings()
});
});
containerEl.createEl('h4', {text: 'Advanced'});
// Managing choice wether you want to parse tags both from normal tags and in the frontmatter
new Setting(containerEl)
.setName('Parse all tags in the file')
.setDesc('Sets the `data-link-tags`-attribute to look for tags both in the frontmatter and in the file as #tag-name')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.targetTags)
toggle.onChange(async value => {
this.plugin.settings.targetTags = value
await this.plugin.saveSettings();
})
})
// Managing choice wether you get attributes from inline fields and frontmatter or only frontmater
new Setting(containerEl)
.setName('Search for attribute in Inline fields like <field::>')
.setDesc('Sets the `data-link-<field>`-attribute to the value of inline fields')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.getFromInlineField)
toggle.onChange(async value => {
this.plugin.settings.getFromInlineField = value
await this.plugin.saveSettings()
});
});
// Managing choice wether you get attributes from inline fields and frontmatter or only frontmater
new Setting(containerEl)
.setName('Automatically activate snippet')
.setDesc('If true, this will automatically activate the generated CSS snippet "supercharged-links-gen.css". ' +
'Turn this off if you don\'t want this to happen.')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.activateSnippet)
toggle.onChange(async value => {
this.plugin.settings.activateSnippet = value
await this.plugin.saveSettings()
});
});
/* Managing predefined values for properties */
/* Manage menu options display*/
new Setting(containerEl)
.setName("Display field options in context menu")
.setDesc("Choose to show or hide fields options in the context menu of a link or a file")
.addToggle((toggle: ToggleComponent) => {
toggle.setValue(this.plugin.settings.displayFieldsInContextMenu)
toggle.onChange(async value => {
this.plugin.settings.displayFieldsInContextMenu = value
await this.plugin.saveSettings()
})
})
/* Exclude Fields from context menu*/
new Setting(containerEl)
.setName('Ignored fields')
.setDesc('Fields to be ignored by the plugin when adding options to the context menu')
.addTextArea((text) => {text
.setPlaceholder('Enter fields as string, comma separated')
.setValue(this.plugin.settings.globallyIgnoredFields.join(', '))
.onChange(async (value) => {
this.plugin.settings.globallyIgnoredFields = value.replace(/\s/g,'').split(',');
await this.plugin.saveSettings();
})
text.inputEl.rows = 6;
text.inputEl.cols = 25;
});
/* Set classFiles Path*/
new Setting(containerEl)
.setName('class Files path')
.setDesc('Path to the files containing the authorized fields for a type of note')
.addText((text) => {text
.setPlaceholder('Path/')
.setValue(this.plugin.settings.classFilesPath)
.onChange(async (value) => {
this.plugin.settings.classFilesPath = value
await this.plugin.saveSettings();
})
});
/* Add new property for which we want to preset values*/
new Setting(containerEl)
.setName("Add New Property Manager")
.setDesc("Add a new Frontmatter property for which you want preset values.")
.addButton((button: ButtonComponent): ButtonComponent => {
return button
.setTooltip("Add New Property Manager")
.setButtonText("+")
.onClick(async () => {
let modal = new FieldSettingsModal(this.app, this.plugin, containerEl);
modal.open();
});
});
/* Managed properties that currently have preset values */
this.plugin.initialProperties.forEach(prop => {
const property = new Field()
Object.assign(property, prop)
new FieldSetting(containerEl, property, this.app, this.plugin)
})
}
generateSnippet() {
this.debouncedGenerate();
}
async _generateSnippet() {
await buildCSS(this.plugin.settings.selectors, this.plugin);
// new Notice("Generated supercharged-links-gen.css");
}
drawSelectors(div: HTMLElement) {
div.empty();
this.generateSnippet();
const selectors = this.plugin.settings.selectors;
selectors.forEach((selector, i) => {
const s = new Setting(div)
.addButton(button => {
button.onClick(() => {
const oldSelector = selectors[i+1];
selectors[i+1] = selector;
selectors[i] = oldSelector;
this.drawSelectors(div);
});
button.setIcon("down-arrow-with-tail");
button.setTooltip("Move selector down");
if (i === selectors.length - 1) {
button.setDisabled(true);
}
})
.addButton(button => {
button.onClick(() => {
const oldSelector = selectors[i-1];
selectors[i-1] = selector;
selectors[i] = oldSelector;
this.drawSelectors(div);
});
button.setIcon("up-arrow-with-tail");
button.setTooltip("Move selector up");
if (i === 0) {
button.setDisabled(true);
}
})
.addButton(button => {
button.onClick(() =>{
const formModal = new CSSBuilderModal(this.plugin, (newSelector) => {
this.plugin.settings.selectors[i] = newSelector;
this.plugin.saveSettings();
updateDisplay(s.nameEl, selector, this.plugin.settings);
this.generateSnippet();
}, selector);
formModal.open();
});
button.setIcon("pencil");
button.setTooltip("Edit selector")
})
.addButton(button => {
button.onClick(() => {
this.plugin.settings.selectors.remove(selector);
this.plugin.saveSettings();
this.drawSelectors(div);
});
button.setIcon("cross");
button.setTooltip("Remove selector");
});
updateDisplay(s.nameEl, selector, this.plugin.settings);
});
new Setting(div)
.setName("New selector")
.setDesc("Create a new selector to style with Style Settings.")
.addButton(button => {
button.onClick(() => {
const formModal = new CSSBuilderModal(this.plugin, (newSelector) => {
this.plugin.settings.selectors.push(newSelector);
this.plugin.saveSettings();
this.drawSelectors(div);
// TODO: Force redraw somehow?
});
formModal.open();
});
button.setButtonText("New");
});
}
}
Example #13
Source File: ICSSettingsTab.ts From obsidian-ics with MIT License | 4 votes |
export default class ICSSettingsTab extends PluginSettingTab {
plugin: ICSPlugin;
constructor(app: App, plugin: ICSPlugin) {
super(app, plugin);
this.plugin = plugin;
}
async display(): Promise < void > {
let {
containerEl
} = this;
containerEl.empty();
containerEl.addClass("ics-settings")
containerEl.createEl("h2", {
text: "ICS Settings"
});
const calendarContainer = containerEl.createDiv(
"ics-setting-calendar"
);
new Setting(calendarContainer)
.setName("Add New")
.setDesc("Add a new Calendar.")
.addButton((button: ButtonComponent): ButtonComponent => {
let b = button
.setTooltip("Add Additional")
.setButtonText("+")
.onClick(async () => {
let modal = new SettingsModal(this.app);
modal.onClose = async () => {
if (modal.saved) {
this.plugin.addCalendar({
icsName: modal.icsName,
icsUrl: modal.icsUrl
});
this.display();
}
};
modal.open();
});
return b;
});
const additional = calendarContainer.createDiv("calendar");
for (let a in this.plugin.data.calendars) {
const calendar = this.plugin.data.calendars[a];
let setting = new Setting(additional);
let calEl = await getCalendarElement(
calendar.icsName,
calendar.icsUrl
);
setting.infoEl.replaceWith(calEl);
setting
.addExtraButton((b) => {
b.setIcon("pencil")
.setTooltip("Edit")
.onClick(() => {
let modal = new SettingsModal(this.app, calendar);
modal.onClose = async () => {
if (modal.saved) {
this.plugin.removeCalendar(calendar);
this.plugin.addCalendar({
icsName: modal.icsName,
icsUrl: modal.icsUrl
});
this.display();
}
};
modal.open();
});
})
.addExtraButton((b) => {
b.setIcon("trash")
.setTooltip("Delete")
.onClick(() => {
this.plugin.removeCalendar(calendar);
this.display();
});
});
}
}
}
Example #14
Source File: Settings.ts From obsidian-banners with MIT License | 4 votes |
export default class SettingsTab extends PluginSettingTab {
plugin: BannersPlugin;
constructor(plugin: BannersPlugin) {
super(plugin.app, plugin);
this.plugin = plugin;
this.containerEl.addClass('banner-settings');
}
async saveSettings(changed: PartialSettings, options: ISaveOptions = {}) {
this.plugin.settings = { ...this.plugin.settings, ...changed };
await this.plugin.saveData(this.plugin.settings);
this.plugin.loadStyles();
const { refreshViews, reloadSettings } = options;
if (reloadSettings) { this.display() }
if (refreshViews) { this.plugin.refreshViews() }
}
display() {
const { containerEl } = this;
const {
height,
style,
showInInternalEmbed,
internalEmbedHeight,
showInPreviewEmbed,
previewEmbedHeight,
frontmatterField,
bannerDragModifier,
iconHorizontalAlignment,
iconHorizontalTransform,
iconVerticalAlignment,
iconVerticalTransform,
useTwemoji,
showPreviewInLocalModal,
localSuggestionsLimit,
bannersFolder,
allowMobileDrag
} = this.plugin.settings;
containerEl.empty();
this.createHeader(
"Banners",
"A nice, lil' thing to add some flair to your notes"
);
// Banner height
new Setting(containerEl)
.setName('Banner height')
.setDesc('Set how big the banner should be in pixels')
.addText(text => {
text.inputEl.type = 'number';
text.setValue(`${height}`);
text.setPlaceholder(`${DEFAULT_VALUES.height}`);
text.onChange(async (val) => this.saveSettings({ height: val ? parseInt(val) : null }));
});
// Banner style
new Setting(containerEl)
.setName('Banner style')
.setDesc('Set a style for all of your banners')
.addDropdown(dropdown => dropdown
.addOptions(STYLE_OPTIONS)
.setValue(style)
.onChange(async (val: StyleOption) => this.saveSettings({ style: val }, { refreshViews: true })));
// Show banner in internal embed
new Setting(containerEl)
.setName('Show banner in internal embed')
.setDesc(createFragment(frag => {
frag.appendText('Choose whether to display the banner in the internal embed. This is the embed that appears when you write ');
frag.createEl('code', { text: '![[file]]' });
frag.appendText(' in a file');
}))
.addToggle(toggle => toggle
.setValue(showInInternalEmbed)
.onChange(async (val) => this.saveSettings({ showInInternalEmbed: val }, { reloadSettings: true, refreshViews: true })));
// Internal embed banner height
if (this.plugin.settings.showInInternalEmbed) {
new Setting(containerEl)
.setName('Internal embed banner height')
.setDesc('Set the banner size inside the internal embed')
.addText(text => {
text.inputEl.type = 'number';
text.setValue(`${internalEmbedHeight}`);
text.setPlaceholder(`${DEFAULT_VALUES.internalEmbedHeight}`);
text.onChange(async (val) => this.saveSettings({ internalEmbedHeight: val ? parseInt(val) : null }));
});
}
// Show banner in preview embed
new Setting(containerEl)
.setName('Show banner in preview embed')
.setDesc(createFragment(frag => {
frag.appendText('Choose whether to display the banner in the page preview embed. This is the embed that appears from the ');
frag.createEl('span', { text: 'Page Preview ', attr: { style: 'color: --var(text-normal)' }});
frag.appendText('core plugin')
}))
.addToggle(toggle => toggle
.setValue(showInPreviewEmbed)
.onChange(async (val) => this.saveSettings({ showInPreviewEmbed: val }, { reloadSettings: true })));
// Preview embed banner height
if (this.plugin.settings.showInPreviewEmbed) {
new Setting(containerEl)
.setName('Preview embed banner height')
.setDesc('Set the banner size inside the page preview embed')
.addText(text => {
text.inputEl.type = 'number';
text.setValue(`${previewEmbedHeight}`);
text.setPlaceholder(`${DEFAULT_VALUES.previewEmbedHeight}`);
text.onChange(async (val) => this.saveSettings({ previewEmbedHeight: val ? parseInt(val) : null }));
});
}
// Customizable banner metadata fields
new Setting(containerEl)
.setName('Frontmatter field name')
.setDesc(createFragment(frag => {
frag.appendText('Set a customizable frontmatter field to use for banner data.');
frag.createEl('br');
frag.appendText('For example, the default value ');
frag.createEl('code', { text: DEFAULT_VALUES.frontmatterField });
frag.appendText(' will use the fields ');
frag.createEl('code', { text: DEFAULT_VALUES.frontmatterField });
frag.appendText(', ');
frag.createEl('code', { text: `${DEFAULT_VALUES.frontmatterField}_x` });
frag.appendText(', ');
frag.createEl('code', { text: `${DEFAULT_VALUES.frontmatterField}_y` });
frag.appendText(', and so on...');
}))
.addText(text => text
.setValue(frontmatterField)
.setPlaceholder(DEFAULT_VALUES.frontmatterField)
.onChange(async (val) => this.saveSettings({ frontmatterField: val || null }, { refreshViews: true })));
// Banner drag modifier key
new Setting(containerEl)
.setName('Banner drag modifier key')
.setDesc(createFragment(frag => {
frag.appendText('Set a modifier key that must be used to drag a banner.');
frag.createEl('br');
frag.appendText('For example, setting it to ');
frag.createEl('b', { text: '⇧ Shift' });
frag.appendText(' means that you must hold down Shift as you drag the banner to move it. This can help to avoid accidental banner shifts.');
}))
.addDropdown(dropdown => dropdown
.addOptions(BANNER_DRAG_MOD_OPTIONS)
.setValue(bannerDragModifier)
.onChange(async (val: BannerDragModOption) => {
await this.saveSettings({ bannerDragModifier: val }, { refreshViews: true });
this.plugin.toggleBannerCursor(val === 'none');
}));
this.createHeader(
'Banner Icons',
'Give people a lil\' notion of what your note is about'
);
// Horizontal icon alignment
const settingHIA = new Setting(containerEl)
.setName('Horizontal alignment')
.setDesc(createFragment(frag => {
frag.appendText('Align the icon horizontally.');
frag.createEl('br');;
frag.appendText('If set to ');
frag.createEl('b', { text: 'Custom' });
frag.appendText(', you can set an offset, relative to the left side of the note. This can be any valid ');
frag.createEl('a', { text: 'CSS length value', href: 'https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#lengths' });
frag.appendText(', such as ');
frag.createEl('code', { text: '10px' });
frag.appendText(', ');
frag.createEl('code', { text: '-30%' });
frag.appendText(', ');
frag.createEl('code', { text: 'calc(1em + 10px)' });
frag.appendText(', and so on...');
}));
if (iconHorizontalAlignment === 'custom') {
settingHIA.addText(text => text
.setValue(iconHorizontalTransform)
.setPlaceholder(DEFAULT_VALUES.iconHorizontalTransform)
.onChange(async (val) => this.saveSettings({ iconHorizontalTransform: val || null }, { refreshViews: true })));
}
settingHIA.addDropdown(dd => dd
.addOptions(ICON_HORIZONTAL_OPTIONS)
.setValue(iconHorizontalAlignment)
.onChange(async (val: IconHorizontalOption) => this.saveSettings({ iconHorizontalAlignment: val }, { reloadSettings: true, refreshViews: true })));
// Vertical icon alignment
const settingVIA = new Setting(containerEl)
.setName('Vertical alignment')
.setDesc(createFragment(frag => {
frag.appendText('Align the icon vertically, relative to a banner (if any).');
frag.createEl('br');;
frag.appendText('If set to ');
frag.createEl('b', { text: 'Custom' });
frag.appendText(', you can set an offset, relative to the center of a banner\'s lower edge. This follows the same format as the setting above.');
}));
if (iconVerticalAlignment === 'custom') {
settingVIA.addText(text => text
.setValue(iconVerticalTransform)
.setPlaceholder(DEFAULT_VALUES.iconVerticalTransform)
.onChange(async (val) => this.saveSettings({ iconVerticalTransform: val || null }, { refreshViews: true })));
}
settingVIA.addDropdown(dd => dd
.addOptions(ICON_VERTICAL_OPTIONS)
.setValue(iconVerticalAlignment)
.onChange(async (val: IconVerticalOption) => this.saveSettings({ iconVerticalAlignment: val }, { reloadSettings: true, refreshViews: true })));
new Setting(containerEl)
.setName('Use Twemoji')
.setDesc(createFragment(frag => {
frag.appendText('Twitter\'s emoji have better support here. ');
frag.createEl('b', { text: 'NOTE: ' })
frag.appendText('This is only applied in the Icon modal and the banner icon in the preview view');
}))
.addToggle(toggle => toggle
.setValue(useTwemoji)
.onChange(async (val) => this.saveSettings({ useTwemoji: val }, { refreshViews: true })));
this.createHeader(
'Local Image Modal',
'For the modal that shows when you run the "Add/Change banner with local image" command'
);
// Show preview images in local image modal
new Setting(containerEl)
.setName('Show preview images')
.setDesc('Enabling this will display a preview of the images suggested')
.addToggle(toggle => toggle
.setValue(showPreviewInLocalModal)
.onChange(async (val) => this.saveSettings({ showPreviewInLocalModal: val })));
// Limit of suggestions in local image modal
new Setting(containerEl)
.setName('Suggestions limit')
.setDesc(createFragment(frag => {
frag.appendText('Show up to this many suggestions when searching through local images.');
frag.createEl('br');
frag.createEl('b', { text: 'NOTE: '});
frag.appendText('Using a high number while ');
frag.createEl('span', { text: 'Show preview images ', attr: { style: 'color: var(--text-normal)' } });
frag.appendText('is on can lead to some slowdowns');
}))
.addText(text => {
text.inputEl.type = 'number';
text.setValue(`${localSuggestionsLimit}`);
text.setPlaceholder(`${DEFAULT_VALUES.localSuggestionsLimit}`);
text.onChange(async (val) => this.saveSettings({ localSuggestionsLimit: val ? parseInt(val) : null }));
});
// Search in a specific folder for banners
new Setting(containerEl)
.setName('Banners folder')
.setDesc(createFragment(frag => {
frag.appendText('Select a folder to exclusively search for banner files in.');
frag.createEl('br');
frag.appendText('If empty, it will search the entire vault for image files');
}))
.addText(text => text
.setValue(bannersFolder)
.setPlaceholder(DEFAULT_VALUES.bannersFolder)
.onChange(async (val) => this.saveSettings({ bannersFolder: val || null } )));
this.createHeader(
'Experimental Things',
'Not as well-tested and probably finicky'
);
// Drag banners in mobile
new Setting(containerEl)
.setName('Allow mobile drag')
.setDesc(createFragment(frag => {
frag.appendText('Allow dragging the banner on mobile devices.');
frag.createEl('br');
frag.createEl('b', { text: 'NOTE: ' });
frag.appendText('App reload might be necessary');
}))
.addToggle(toggle => toggle
.setValue(allowMobileDrag)
.onChange(async (val) => this.saveSettings({ allowMobileDrag: val }, { refreshViews: true })));
}
private createHeader(text: string, desc: string = null) {
const header = this.containerEl.createDiv({ cls: 'setting-item setting-item-heading banner-setting-header' });
header.createEl('p', { text, cls: 'banner-setting-header-title' });
if (desc) {
header.createEl('p', { text: desc, cls: 'banner-setting-header-description' });
}
}
}
Example #15
Source File: settingsTab.ts From obsidian-charts with GNU Affero General Public License v3.0 | 4 votes |
export class ChartSettingTab extends PluginSettingTab {
plugin: ChartPlugin;
constructor(app: App, plugin: ChartPlugin) {
super(app, plugin);
this.plugin = plugin;
}
isColor(strColor: string) {
var s = new Option().style;
s.color = strColor;
return s.color == strColor;
}
display(): void {
let { containerEl, plugin } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Settings - Obsidian Charts' });
containerEl.createEl('h3', { text: "General" });
new Setting(containerEl)
.setName("Show Button in Context Menu")
.setDesc("If enabled, you will se a Button in your Editor Context Menu to open the Chart Creator.")
.addToggle(cb => {
cb
.setValue(this.plugin.settings.contextMenu)
.onChange(async value => {
plugin.settings.contextMenu = value;
await plugin.saveSettings();
})
});
new Setting(containerEl)
.setName('Donate')
.setDesc('If you like this Plugin, consider donating to support continued development:')
.addButton((bt) => {
bt.buttonEl.outerHTML = `<a href="https://www.buymeacoffee.com/phibr0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=phibr0&button_colour=5F7FFF&font_colour=ffffff&font_family=Inter&outline_colour=000000&coffee_colour=FFDD00"></a>`;
});
containerEl.createEl('h3', {
text: "Colors", attr: {
style: "margin-bottom: 0"
}
});
const desc = containerEl.createEl("p", { cls: "setting-item-description" });
desc.append(
"Set the Colors for your Charts. This will set the border Color and the inner Color will be the same, but with less opacity. This ensures better compatibility with Dark and Light Mode. ",
"You can use any ",
desc.createEl("a", {
href: "https://www.w3schools.com/cssref/css_colors.asp",
text: "valid CSS Color."
}),
)
new Setting(containerEl).setName('Enable Theme Colors').setDesc('If your Obsidian Theme (or snippet) provides Colors you can use them instead.').addToggle(cb => {
cb.setValue(plugin.settings.themeable).onChange(async value => {
plugin.settings.themeable = value;
await plugin.saveSettings();
this.display();
})
});
if (!plugin.settings.themeable) {
plugin.settings.colors.forEach((color, idx) => {
const nameEl = document.createDocumentFragment();
nameEl.createSpan({ text: "●", attr: { style: `color: ${color}` } });
nameEl.appendText(` Color #${idx + 1}`);
new Setting(containerEl)
.setName(nameEl)
.setDesc('This will be the border Color used in the Charts you create.')
.addButton(btn => {
btn.setButtonText("Change Color");
new Picker({
parent: btn.buttonEl,
onDone: async (color) => {
this.plugin.settings.colors[idx] = color.hex;
await this.plugin.saveSettings();
this.display();
},
popup: "left",
color: color,
alpha: false,
});
})
.addExtraButton(btn => {
btn.setIcon("trash").setTooltip("Remove").onClick(async () => {
this.plugin.settings.colors.remove(color);
await this.plugin.saveSettings();
this.display();
});
if (this.plugin.settings.colors.length === 1) {
btn.setDisabled(true);
}
})
.addExtraButton(btn => {
btn.setIcon("reset").setTooltip("Reset to default").onClick(async () => {
this.plugin.settings.colors[idx] = DEFAULT_SETTINGS.colors[idx] ?? "#ffffff";
await this.plugin.saveSettings();
this.display();
});
});
});
new Setting(containerEl)
.addButton(btn => {
btn.setButtonText("Add Color").onClick(async () => {
this.plugin.settings.colors.push("#ffffff");
await this.plugin.saveSettings();
this.display();
})
});
}
containerEl.createEl('h3', { text: "Chart to Image Converter" });
const detailEl = containerEl.createEl("details");
detailEl.createEl("summary", { text: "How to use" });
detailEl.createEl("img", { attr: { src: "https://media.discordapp.net/attachments/855181471643861002/897811615037136966/charttoimage.gif" } });
new Setting(containerEl)
.setName("Image Format")
.setDesc("The Format to be used, when generating a Image from a Chart.")
.addDropdown(cb => {
cb.addOptions({
'image/jpeg': 'jpeg',
'image/png': 'png',
'image/webp': 'webp',
});
cb.setValue(plugin.settings.imageSettings.format);
cb.onChange(async value => {
(plugin.settings.imageSettings.format as any) = value;
await plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Image Quality")
.setDesc("If using a lossy format, set the Image Quality.")
.addSlider(cb => {
cb.setDynamicTooltip()
.setLimits(0.01, 1, 0.01)
.setValue(plugin.settings.imageSettings.quality)
.onChange(async value => {
plugin.settings.imageSettings.quality = value;
await plugin.saveSettings();
});
});
}
}
Example #16
Source File: settingsTab.ts From obsidian-customizable-sidebar with MIT License | 4 votes |
export default class CustomSidebarSettingsTab extends PluginSettingTab {
plugin: CustomSidebarPlugin;
constructor(app: App, plugin: CustomSidebarPlugin) {
super(app, plugin);
this.plugin = plugin;
addEventListener("CS-addedCommand", () => {
this.display();
});
}
display(): void {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Customizable Sidebar Settings' });
new Setting(containerEl)
.setName("Add Command to Sidebar")
.setDesc("Add a new command to the left Sidebar Ribbon")
.addButton((bt) => {
bt.setButtonText("Add Command")
.onClick(() => {
new CommandSuggester(this.plugin).open();
});
});
this.plugin.settings.sidebarCommands.forEach((c, index) => {
const iconDiv = createDiv({ cls: "CS-settings-icon" });
setIcon(iconDiv, c.icon, 20);
const setting = new Setting(containerEl)
.setName(c.name);
if (index > 0) {
setting.addExtraButton(bt => {
bt.setIcon("up-arrow-with-tail")
.setTooltip("Move up")
.onClick(async () => await this.moveCommand(c, 'up'));
})
}
if (index < this.plugin.settings.sidebarCommands.length - 1) {
setting.addExtraButton(bt => {
bt.setIcon("down-arrow-with-tail")
.setTooltip("Move down")
.onClick(async () => await this.moveCommand(c, 'down'));
})
}
setting
.addExtraButton(bt => {
bt.setIcon("trash")
.setTooltip("Remove Command")
.onClick(async () => {
this.plugin.settings.sidebarCommands.remove(c);
await this.plugin.saveSettings();
this.display();
const ribbonButton = Array.from(this.leftRibbonPanel.children)
.find((btn) => c.name === btn.getAttribute('aria-label'))
this.leftRibbonPanel.removeChild(ribbonButton);
})
})
.addExtraButton(bt => {
bt.setIcon("gear")
.setTooltip("Edit Icon")
.onClick(() => {
new IconPicker(this.plugin, c, true).open();
})
});
setting.nameEl.prepend(iconDiv);
setting.nameEl.addClass("CS-flex");
});
//@ts-ignore
const children: HTMLCollection = this.app.workspace.leftRibbon.ribbonActionsEl.children;
for (let i = 0; i < children.length; i++) {
if (!this.plugin.settings.sidebarCommands.contains(this.plugin.settings.sidebarCommands.find(c => c.name === (children.item(i) as HTMLElement).getAttribute("aria-label")))) {
new Setting(containerEl)
.setName("Hide " + (children.item(i) as HTMLElement).getAttribute("aria-label") + "?")
.addToggle(cb => {
cb.setValue((children.item(i) as HTMLElement).style.display === "none")
cb.onChange(async value => {
if(value === true) {
(children.item(i) as HTMLElement).style.display = "none";
this.plugin.settings.hiddenCommands.push((children.item(i) as HTMLElement).getAttribute("aria-label"));
await this.plugin.saveSettings();
} else {
(children.item(i) as HTMLElement).style.display = "flex";
this.plugin.settings.hiddenCommands.remove((children.item(i) as HTMLElement).getAttribute("aria-label"));
await this.plugin.saveSettings();
}
});
});
}
}
new Setting(containerEl)
.setName("Desktop only: Support floating sidebars")
.setDesc("Change the sidebar behavior to match mobile: they will open above content panes unless pinned.")
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.pinSidebar !== undefined);
toggle.onChange(async value => {
if ( value ) {
// start with default pinned/open
this.plugin.settings.pinSidebar = {
right: true,
left: true
};
} else {
delete this.plugin.settings.pinSidebar;
}
this.plugin.sidebarPins();
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName('Donate')
.setDesc('If you like this plugin, consider donating to support continued development:')
.setClass("AT-extra")
.addButton((bt) => {
bt.buttonEl.outerHTML = `<a href="https://www.buymeacoffee.com/phibr0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=phibr0&button_colour=5F7FFF&font_colour=ffffff&font_family=Inter&outline_colour=000000&coffee_colour=FFDD00"></a>`;
});
}
private get leftRibbonPanel(): HTMLElement {
// @ts-ignore `ribbonActionsEl` is not defined in api
return this.app.workspace.leftRibbon.ribbonActionsEl as HTMLElement;
}
private async moveCommand(command: Command, direction: 'up' | 'down') {
// Move command in settings
const commands = this.plugin.settings.sidebarCommands;
const index = commands.indexOf(command);
if (direction === 'up') {
commands.splice(index - 1, 0, commands.splice(index, 1)[0]);
} else {
commands.splice(index + 1, 0, commands.splice(index, 1)[0]);
}
await this.plugin.saveSettings();
this.display();
// Move command button in left ribbon
const ribbonButton = Array.from(this.leftRibbonPanel.children)
.find((btn) => command.name === btn.getAttribute('aria-label'));
if (direction === 'up') {
ribbonButton.previousSibling.before(ribbonButton);
} else {
ribbonButton.nextSibling.after(ribbonButton);
}
}
}
Example #17
Source File: settingsTab.ts From obsidian-dictionary with GNU Affero General Public License v3.0 | 4 votes |
export default class SettingsTab extends PluginSettingTab {
plugin: DictionaryPlugin;
constructor(app: App, plugin: DictionaryPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl, plugin } = this;
containerEl.empty();
containerEl.createEl('h2', { text: t('Dictionary Settings') });
new Setting(containerEl)
.setName(t('Language'))
.setDesc(t('The Language the Plugin will use to search for Definitions and Pronunciations.'))
.addDropdown((dropdown) => {
for (const language in LANGUAGES) {
dropdown.addOption(language, LANGUAGES[language]);
}
dropdown.setValue(plugin.settings.normalLang)
.onChange(async (value) => {
plugin.settings.defaultLanguage = value as keyof typeof LANGUAGES;
plugin.settings.normalLang = value as keyof typeof LANGUAGES;
await this.save();
this.display();
});
});
new Setting(containerEl)
.setName('Get Language from File')
.setDesc('Use the lang or language key in the frontmatter to set the Language dependent on your open File. Example: lang: "en_US" or language: "de".')
.addToggle(toggle => {
toggle.setValue(this.plugin.settings.getLangFromFile).onChange(async value => {
this.plugin.settings.getLangFromFile = value;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName(t('Definition Provider'))
.setDesc(t('The API the Plugin will use to search for Definitions.'))
.addDropdown((dropdown) => {
const list: Record<string, string> = {};
for (const api of plugin.manager.definitionProvider) {
if (api.supportedLanguages.contains(plugin.settings.defaultLanguage)) {
list[api.name] = api.name;
}
}
dropdown.addOptions(list)
.setValue(plugin.settings.apiSettings[plugin.settings.defaultLanguage].definitionApiName ?? Object.keys(list).first())
.onChange(async (value) => {
plugin.settings.apiSettings[plugin.settings.defaultLanguage].definitionApiName = value;
await this.save();
});
});
new Setting(containerEl)
.setName(t('Synonym Provider'))
.setDesc(t('The API the Plugin will use to search for Synonyms.'))
.addDropdown((dropdown) => {
const list: Record<string, string> = {};
for (const api of plugin.manager.synonymProvider) {
if (api.supportedLanguages.contains(plugin.settings.defaultLanguage)) {
list[api.name] = api.name;
}
}
dropdown.addOptions(list)
.setValue(plugin.settings.apiSettings[plugin.settings.defaultLanguage].synonymApiName ?? Object.keys(list).first())
.onChange(async (value) => {
plugin.settings.apiSettings[plugin.settings.defaultLanguage].synonymApiName = value;
await this.save();
});
});
new Setting(containerEl)
.setName(t('Synonym Suggestions'))
.setDesc(t('Show synonyms for highlighted words'))
.addToggle(toggle => {
if (plugin.settings.shouldShowSynonymPopover) {
toggle.setValue(true)
} else {
toggle.setValue(false)
}
toggle.onChange(async (value) => {
plugin.settings.shouldShowSynonymPopover = value;
await this.save();
})
});
if (plugin.manager.partOfSpeechProvider.length) {
const desc = document.createDocumentFragment();
desc.append(
t('Enabling this will allow the Plugin to analyze full sentences to better suggest synonyms based on the context.'),
desc.createEl("br"),
t('Click '),
desc.createEl("a", {
href: "https://github.com/phibr0/obsidian-dictionary#privacy",
text: t('here')
}),
t(' for Privacy Concerns.'),
);
new Setting(containerEl)
.setName(t('Advanced Synonym Search'))
.setDesc(desc)
.addToggle(toggle => {
toggle.setValue(plugin.settings.advancedSynonymAnalysis)
toggle.onChange(async (value) => {
plugin.settings.advancedSynonymAnalysis = value;
await this.save();
})
});
}
new Setting(containerEl)
.setName(t('Show Options in Context Menu'))
.setDesc(t('Enable custom Context Menu with options to search for synonyms (only if the auto suggestions are disabled) and to look up a full definition in the Sidebar. Warning: This will override Obsidian\'s default Context Menu.'))
.addToggle(toggle => {
if (plugin.settings.shouldShowCustomContextMenu) {
toggle.setValue(true)
} else {
toggle.setValue(false)
}
toggle.onChange(async (value) => {
plugin.settings.shouldShowCustomContextMenu = value;
await this.save();
})
});
containerEl.createEl('h3', { text: t("Local-Dictionary-Builder Settings") });
new Setting(containerEl)
.setName(t('Local Dictionary Folder'))
.setDesc(t('Specify a Folder, where all new Notes created by the Dictionary are placed. Please note that this Folder needs to already exist.'))
.addText(text => text
.setPlaceholder(t('Dictionary'))
.setValue(plugin.settings.folder)
.onChange(async (value) => {
plugin.settings.folder = value;
await this.save();
}));
new Setting(containerEl)
.setName(t('Use Language specific Subfolders'))
.setDesc(t('Create Subfolders for every language, e.g. "Dictionary/en-US/Cake"'))
.addToggle(toggle => {
toggle.setValue(plugin.settings.languageSpecificSubFolders)
toggle.onChange(async (value) => {
plugin.settings.languageSpecificSubFolders = value;
await this.save();
})
});
new Setting(containerEl)
.setName(t('Capitalize File Name'))
.setDesc(t('If you disable this, the names of newly created files will be all lowercase.'))
.addToggle(toggle => {
toggle.setValue(plugin.settings.capitalizedFileName)
toggle.onChange(async (value) => {
plugin.settings.capitalizedFileName = value;
await this.save();
})
});
new Setting(containerEl)
.setName(t('Filename Prefix and Suffix'))
.setDesc(t('Here you can add a Prefix and Suffix for your newly created Files.'))
.setClass("dictionaryprefixsuffix")
.addText(text => text
.setPlaceholder(t("Prefix"))
.setValue(plugin.settings.prefix)
.onChange(async (value) => {
plugin.settings.prefix = value;
await this.save();
}))
.addText(text => text
.setPlaceholder(t("Suffix"))
.setValue(plugin.settings.suffix)
.onChange(async (value) => {
plugin.settings.suffix = value;
await this.save();
}));
const templateDescription = document.createDocumentFragment();
templateDescription.append(
t('Here you can edit the Template for newly created Files.'),
templateDescription.createEl("br"),
templateDescription.createEl("a", {
href: "https://github.com/phibr0/obsidian-dictionary#variables",
text: t('Click for a List of Variables'),
}),
);
new Setting(containerEl)
.setName(t('Template'))
.setDesc(templateDescription)
.setClass("dictionarytextarea")
.addTextArea(text => text
.setPlaceholder(DEFAULT_SETTINGS.template)
.setValue(plugin.settings.template)
.onChange(async (value) => {
plugin.settings.template = value;
await this.save();
}))
.addExtraButton(cb => {
cb.setIcon("reset")
.setTooltip(t("Reset to default"))
.setDisabled(this.plugin.settings.template === DEFAULT_SETTINGS.template)
.onClick(async () => {
this.plugin.settings.template = DEFAULT_SETTINGS.template;
await this.plugin.saveSettings();
});
});
containerEl.createEl('h3', { text: t("Caching Settings") });
new Setting(containerEl)
.setName(t("Use Caching"))
.setDesc(t("Enable or disable caching. Caching provides a semi-offline experience by saving every result for later use."))
.addToggle(toggle => {
toggle.setValue(plugin.settings.useCaching)
toggle.onChange(async (value) => {
plugin.settings.useCaching = value;
await this.save();
})
});
const cachingInfo = document.createDocumentFragment();
cachingInfo.append(
t('Here you can delete all cached Data.'),
templateDescription.createEl("br"),
t("You currently have "),
plugin.cache.cachedDefinitions.length.toString(),
t(" cached Definitions and "),
plugin.cache.cachedSynonyms.length.toString(),
t(" cached Synonyms.")
);
new Setting(containerEl)
.setName(t("Delete Cache"))
.setDesc(cachingInfo)
.addButton(button => {
button.setDisabled(!plugin.settings.useCaching);
button.setButtonText(t("Delete"));
button.onClick(async () => {
plugin.cache.cachedSynonyms = [];
plugin.cache.cachedDefinitions = [];
await this.plugin.saveCache();
new Notice(t("Success"));
this.display();
});
});
containerEl.createEl('h3', { text: t("Miscellaneous") });
new Setting(containerEl)
.setName(t('More Information'))
.setDesc(t('View Information about the API\'s and the Plugin itself.'))
.setClass("extra")
.addButton((bt) => {
bt.setButtonText(t('More Info'))
bt.onClick((_) => {
new InfoModal(plugin).open();
});
});
new Setting(containerEl)
.setName(t('Donate'))
.setDesc(t('If you like this Plugin, consider donating to support continued development:'))
.setClass("extra")
.addButton((bt) => {
bt.buttonEl.outerHTML = `<a href="https://www.buymeacoffee.com/phibr0"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=phibr0&button_colour=5F7FFF&font_colour=ffffff&font_family=Inter&outline_colour=000000&coffee_colour=FFDD00"></a>`;
});
}
private async save() {
await this.plugin.saveSettings();
}
}
Example #18
Source File: index.ts From obsidian-hypothesis-plugin with MIT License | 4 votes |
export class SettingsTab extends PluginSettingTab {
public app: App;
private plugin: HypothesisPlugin;
private renderer: Renderer;
private tokenManager: TokenManager;
private syncGroup: SyncGroup;
constructor(app: App, plugin: HypothesisPlugin) {
super(app, plugin);
this.app = app;
this.plugin = plugin;
this.renderer = new Renderer();
this.tokenManager = new TokenManager();
this.syncGroup = new SyncGroup();
}
public async display(): Promise<void> {
const { containerEl } = this;
containerEl.empty();
if (get(settingsStore).isConnected) {
this.disconnect();
} else {
this.connect();
}
this.autoSyncInterval();
this.highlightsFolder();
this.folderPath();
this.syncOnBoot();
this.dateFormat();
this.template();
this.manageGroups();
this.resetSyncHistory();
}
private disconnect(): void {
const syncMessage = get(settingsStore).lastSyncDate
? `Last sync ${moment(get(settingsStore).lastSyncDate).fromNow()}`
: 'Sync has never run';
const descFragment = document.createRange().createContextualFragment(`
${get(settingsStore).history.totalArticles} article(s) & ${get(settingsStore).history.totalHighlights} highlight(s) synced<br/>
${syncMessage}
`);
new Setting(this.containerEl)
.setName(`Connected to Hypothes.is as ${(get(settingsStore).user).match(/([^:]+)@/)[1]}`)
.setDesc(descFragment)
.addButton((button) => {
return button
.setButtonText('Disconnect')
.setCta()
.onClick(async () => {
button
.removeCta()
.setButtonText('Removing API token...')
.setDisabled(true);
await settingsStore.actions.disconnect();
this.display(); // rerender
});
});
}
private connect(): void {
new Setting(this.containerEl)
.setName('Connect to Hypothes.is')
.addButton((button) => {
return button
.setButtonText('Connect')
.setCta()
.onClick(async () => {
button
.removeCta()
.setButtonText('Removing API token...')
.setDisabled(true);
const tokenModal = new ApiTokenModal(this.app, this.tokenManager);
await tokenModal.waitForClose;
this.display(); // rerender
});
});
}
private autoSyncInterval(): void {
new Setting(this.containerEl)
.setName('Auto sync in interval (minutes)')
.setDesc('Sync every X minutes. To disable auto sync, specify negative value or zero (default)')
.addText((text) => {
text
.setPlaceholder(String(0))
.setValue(String(get(settingsStore).autoSyncInterval))
.onChange(async (value) => {
if (!isNaN(Number(value))) {
const minutes = Number(value);
await settingsStore.actions.setAutoSyncInterval(minutes);
const autoSyncInterval = get(settingsStore).autoSyncInterval;
console.log(autoSyncInterval);
if (autoSyncInterval > 0) {
this.plugin.clearAutoSync();
this.plugin.startAutoSync(minutes);
console.log(
`Auto sync enabled! Every ${minutes} minutes.`
);
} else if (autoSyncInterval <= 0) {
this.plugin.clearAutoSync() && console.log("Auto sync disabled!");
}
}
});
});
}
private highlightsFolder(): void {
new Setting(this.containerEl)
.setName('Highlights folder location')
.setDesc('Vault folder to use for writing hypothesis highlights')
.addDropdown((dropdown) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const files = (this.app.vault.adapter as any).files;
const folders = pickBy(files, (val) => {
return val.type === 'folder';
});
Object.keys(folders).forEach((val) => {
dropdown.addOption(val, val);
});
return dropdown
.setValue(get(settingsStore).highlightsFolder)
.onChange(async (value) => {
await settingsStore.actions.setHighlightsFolder(value);
});
});
}
private template(): void {
const descFragment = document
.createRange()
.createContextualFragment(templateInstructions);
new Setting(this.containerEl)
.setName('Highlights template')
.setDesc(descFragment)
.addTextArea((text) => {
text.inputEl.style.width = '100%';
text.inputEl.style.height = '450px';
text.inputEl.style.fontSize = '0.8em';
text
.setValue(get(settingsStore).template)
.onChange(async (value) => {
const isValid = this.renderer.validate(value);
if (isValid) {
await settingsStore.actions.setTemplate(value);
}
text.inputEl.style.border = isValid ? '' : '1px solid red';
});
return text;
});
}
private folderPath(): void {
new Setting(this.containerEl)
.setName('Use domain folders')
.setDesc('Group generated files into folders based on the domain of the annotated URL')
.addToggle((toggle) =>
toggle
.setValue(get(settingsStore).useDomainFolders)
.onChange(async (value) => {
await settingsStore.actions.setUseDomainFolder(value);
})
);
}
private syncOnBoot(): void {
new Setting(this.containerEl)
.setName('Sync on Startup')
.setDesc(
'Automatically sync new highlights when Obsidian starts'
)
.addToggle((toggle) =>
toggle
.setValue(get(settingsStore).syncOnBoot)
.onChange(async (value) => {
await settingsStore.actions.setSyncOnBoot(value);
})
);
}
private resetSyncHistory(): void {
new Setting(this.containerEl)
.setName('Reset sync')
.setDesc('Wipe sync history to allow for resync')
.addButton((button) => {
return button
.setButtonText('Reset')
.setDisabled(!get(settingsStore).isConnected)
.setWarning()
.onClick(async () => {
await settingsStore.actions.resetSyncHistory();
this.display(); // rerender
});
});
}
private dateFormat(): void {
const descFragment = document
.createRange()
.createContextualFragment(datetimeInstructions);
new Setting(this.containerEl)
.setName('Date & time format')
.setDesc(descFragment)
.addText((text) => {
text
.setPlaceholder('YYYY-MM-DD HH:mm:ss')
.setValue(get(settingsStore).dateTimeFormat)
.onChange(async (value) => {
await settingsStore.actions.setDateTimeFormat(value);
});
});
}
private async resyncDeletedFile(): Promise<void> {
new Setting(this.containerEl)
.setName('Sync deleted file(s)')
.setDesc('Manually sync deleted file(s)')
.addButton((button) => {
return button
.setButtonText('Show deleted file(s)')
.setCta()
.onClick(async () => {
button
.removeCta()
.setButtonText('Resync deleted file..')
.setDisabled(true);
const resyncDelFileModal = new ResyncDelFileModal(this.app);
await resyncDelFileModal.waitForClose;
this.display(); // rerender
});
});
}
private async manageGroups(): Promise<void> {
const descFragment = document.createRange().createContextualFragment(`Add/remove group(s) to be synced.<br/>
${(get(settingsStore).groups).length} group(s) synced from Hypothesis<br/>`);
new Setting(this.containerEl)
.setName('Groups')
.setDesc(descFragment)
.addExtraButton((button) => {
return button
.setIcon('switch')
.setTooltip('Reset group selections')
.setDisabled(!get(settingsStore).isConnected)
.onClick(async () => {
await settingsStore.actions.resetGroups();
await this.syncGroup.startSync();
this.display(); // rerender
});
})
.addButton((button) => {
return button
.setButtonText('Manage')
.setCta()
.setDisabled(!get(settingsStore).isConnected)
.onClick(async () => {
const manageGroupsModal = new ManageGroupsModal(this.app);
await manageGroupsModal.waitForClose;
this.display(); // rerender
});
});
}
}
Example #19
Source File: settings-tab.ts From obsidian-ReadItLater with MIT License | 4 votes |
export class ReadItLaterSettingsTab extends PluginSettingTab {
plugin: ReadItLaterPlugin;
constructor(app: App, plugin: ReadItLaterPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'Settings for the ReadItLater plugin.' });
new Setting(containerEl)
.setName('Inbox dir')
.setDesc(
'Enter valid folder name. For nested folders use this format: Folder A/Folder B. If no folder is enetred, new note will be created in vault root.',
)
.addText((text) =>
text
.setPlaceholder('Defaults to root')
.setValue(this.plugin.settings.inboxDir || DEFAULT_SETTINGS.inboxDir)
.onChange(async (value) => {
this.plugin.settings.inboxDir = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Open new note')
.setDesc('If enabled, new note will open in current workspace')
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.openNewNote || DEFAULT_SETTINGS.openNewNote)
.onChange(async (value) => {
this.plugin.settings.openNewNote = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Download images')
.setDesc('If this is true, the used images are downloaded to the defined folder (just on Desktop)')
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.downloadImages || DEFAULT_SETTINGS.downloadImages)
.onChange(async (value) => {
this.plugin.settings.downloadImages = value;
assetDirSetting.setDisabled(!value);
await this.plugin.saveSettings();
}),
);
const assetDirSetting = new Setting(containerEl)
.setName('Assets dir')
.setDesc(
'Enter valid folder name. For nested folders use this format: Folder A/Folder B. If no folder is enetred, new note will be created in vault root.',
)
.addText((text) =>
text
.setPlaceholder('Defaults to root')
.setValue(this.plugin.settings.assetsDir || DEFAULT_SETTINGS.inboxDir + '/assets')
.setDisabled(!this.plugin.settings.downloadImages)
.onChange(async (value) => {
this.plugin.settings.assetsDir = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Youtube note template title')
.setDesc('Available variables: %title%')
.addText((text) =>
text
.setPlaceholder('Defaults to %title%')
.setValue(this.plugin.settings.youtubeNoteTitle || DEFAULT_SETTINGS.youtubeNoteTitle)
.onChange(async (value) => {
this.plugin.settings.youtubeNoteTitle = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Youtube note template')
.setDesc('Available variables: %videoTitle%, %videoURL%, %videoId%, %videoPlayer%')
.addTextArea((textarea) => {
textarea
.setValue(this.plugin.settings.youtubeNote || DEFAULT_SETTINGS.youtubeNote)
.onChange(async (value) => {
this.plugin.settings.youtubeNote = value;
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 10;
textarea.inputEl.cols = 25;
});
new Setting(containerEl)
.setName('Twitter note template title')
.setDesc('Available variables: %tweetAuthorName%, %date%')
.addText((text) =>
text
.setPlaceholder('Defaults to %tweetAuthorName%')
.setValue(this.plugin.settings.twitterNoteTitle || DEFAULT_SETTINGS.twitterNoteTitle)
.onChange(async (value) => {
this.plugin.settings.twitterNoteTitle = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Twitter note template')
.setDesc('Available variables: %tweetAuthorName%, %tweetURL%, %tweetContent%')
.addTextArea((textarea) => {
textarea
.setValue(this.plugin.settings.twitterNote || DEFAULT_SETTINGS.twitterNote)
.onChange(async (value) => {
this.plugin.settings.twitterNote = value;
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 10;
textarea.inputEl.cols = 25;
});
new Setting(containerEl)
.setName('Parsable article note template title')
.setDesc('Available variables: %title%')
.addText((text) =>
text
.setPlaceholder('Defaults to %title%')
.setValue(
this.plugin.settings.parseableArticleNoteTitle || DEFAULT_SETTINGS.parseableArticleNoteTitle,
)
.onChange(async (value) => {
this.plugin.settings.parseableArticleNoteTitle = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Parsable article note template')
.setDesc('Available variables: %articleTitle%, %articleURL%, %articleContent%')
.addTextArea((textarea) => {
textarea
.setValue(this.plugin.settings.parsableArticleNote || DEFAULT_SETTINGS.parsableArticleNote)
.onChange(async (value) => {
this.plugin.settings.parsableArticleNote = value;
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 10;
textarea.inputEl.cols = 25;
});
new Setting(containerEl)
.setName('Not paresable article note template title')
.setDesc('Available variables: %date%')
.addText((text) =>
text
.setPlaceholder(`Defaults to 'Article %date%'`)
.setValue(
this.plugin.settings.notParseableArticleNoteTitle ||
DEFAULT_SETTINGS.notParseableArticleNoteTitle,
)
.onChange(async (value) => {
this.plugin.settings.notParseableArticleNoteTitle = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Not parseable article note template')
.setDesc('Available variables: %articleURL%')
.addTextArea((textarea) => {
textarea
.setValue(this.plugin.settings.notParsableArticleNote || DEFAULT_SETTINGS.notParsableArticleNote)
.onChange(async (value) => {
this.plugin.settings.notParsableArticleNote = value;
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 10;
textarea.inputEl.cols = 25;
});
new Setting(containerEl)
.setName('Text snippet note template title')
.setDesc('Available variables: %date%')
.addText((text) =>
text
.setPlaceholder(`Defaults to 'Notice %date%'`)
.setValue(this.plugin.settings.textSnippetNoteTitle || DEFAULT_SETTINGS.textSnippetNoteTitle)
.onChange(async (value) => {
this.plugin.settings.textSnippetNoteTitle = value;
await this.plugin.saveSettings();
}),
);
new Setting(containerEl)
.setName('Text snippet note template')
.setDesc('Available variables: %content%')
.addTextArea((textarea) => {
textarea
.setValue(this.plugin.settings.textSnippetNote || DEFAULT_SETTINGS.textSnippetNote)
.onChange(async (value) => {
this.plugin.settings.textSnippetNote = value;
await this.plugin.saveSettings();
});
textarea.inputEl.rows = 10;
textarea.inputEl.cols = 25;
});
}
}
Example #20
Source File: settings.ts From obsidian-initiative-tracker with GNU General Public License v3.0 | 4 votes |
export default class InitiativeTrackerSettings extends PluginSettingTab {
constructor(private plugin: InitiativeTracker) {
super(plugin.app, plugin);
}
async display(): Promise<void> {
try {
let { containerEl } = this;
containerEl.empty();
containerEl.addClass("initiative-tracker-settings");
containerEl.createEl("h2", { text: "Initiative Tracker Settings" });
this._displayBase(containerEl.createDiv());
if (!this.plugin.data.openState) {
this.plugin.data.openState = {
player: true,
party: true,
plugin: true,
status: true
};
}
this._displayPlayers(
containerEl.createEl("details", {
cls: "initiative-tracker-additional-container",
attr: {
...(this.plugin.data.openState.player
? { open: true }
: {})
}
})
);
this._displayParties(
containerEl.createEl("details", {
cls: "initiative-tracker-additional-container",
attr: {
...(this.plugin.data.openState.party
? { open: true }
: {})
}
})
);
this._displayStatuses(
containerEl.createEl("details", {
cls: "initiative-tracker-additional-container",
attr: {
...(this.plugin.data.openState.status
? { open: true }
: {})
}
})
);
this._displayIntegrations(
containerEl.createEl("details", {
cls: "initiative-tracker-additional-container",
attr: {
...(this.plugin.data.openState.plugin
? { open: true }
: {})
}
})
);
this._displayHomebrew(
containerEl.createDiv("initiative-tracker-additional-container")
);
const div = containerEl.createDiv("coffee");
div.createEl("a", {
href: "https://www.buymeacoffee.com/valentine195"
}).createEl("img", {
attr: {
src: "https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=☕&slug=valentine195&button_colour=e3e7ef&font_colour=262626&font_family=Inter&outline_colour=262626&coffee_colour=ff0000"
}
});
} catch (e) {
console.error(e);
new Notice(
"There was an error displaying the settings tab for Obsidian Initiative Tracker."
);
}
}
private _displayBase(containerEl: HTMLDivElement) {
containerEl.empty();
new Setting(containerEl).setHeading().setName("Basic Settings");
new Setting(containerEl)
.setName("Display Encounter Difficulty")
.setDesc(
"Display encounter difficulty based on creature CR and player level. Creatures without CR or level will not be considered in the calculation."
)
.addToggle((t) => {
t.setValue(this.plugin.data.displayDifficulty).onChange(
async (v) => {
this.plugin.data.displayDifficulty = v;
await this.plugin.saveSettings();
}
);
});
new Setting(containerEl)
.setName("Roll Equivalent Creatures Together")
.setDesc(
"Equivalent creatures (same HP, AC and Name) will roll the same initiative by default."
)
.addToggle((t) => {
t.setValue(this.plugin.data.condense).onChange(async (v) => {
this.plugin.data.condense = v;
const view = this.plugin.view;
if (view) {
view.setCondensed(this.plugin.data.condense);
}
await this.plugin.saveSettings();
});
});
/* new Setting(containerEl)
.setName("Monster Property used for Modifier")
.setDesc(
"The tracker will try to use this property on a monster to calculate initiative."
)
.addText((t) => {
t.setValue(this.plugin.data.modifier).onChange((v) => {
this.plugin.data.modifier = v;
});
t.inputEl.onblur = async () => {
const view = this.plugin.view;
if (view) view.rollInitiatives();
await this.plugin.saveSettings();
};
}); */
}
private _displayPlayers(additionalContainer: HTMLDetailsElement) {
additionalContainer.empty();
additionalContainer.ontoggle = () => {
this.plugin.data.openState.player = additionalContainer.open;
};
const summary = additionalContainer.createEl("summary");
new Setting(summary).setHeading().setName("Players");
summary.createDiv("collapser").createDiv("handle");
new Setting(additionalContainer)
.setName("Add New Player")
.setDesc(
"Players added here will be available to add to a party. If you do not have a party created, all players will be added to a new encounter."
)
.addButton((button: ButtonComponent): ButtonComponent => {
let b = button
.setTooltip("Add Player")
.setButtonText("+")
.onClick(async () => {
const modal = new NewPlayerModal(this.plugin);
modal.open();
modal.onClose = async () => {
if (!modal.saved) return;
await this.plugin.savePlayer({
...modal.player,
player: true
});
this._displayPlayers(additionalContainer);
};
});
return b;
});
const additional = additionalContainer.createDiv("additional");
const playerView = additional.createDiv("initiative-tracker-players");
if (!this.plugin.data.players.length) {
additional
.createDiv({
attr: {
style: "display: flex; justify-content: center; padding-bottom: 18px;"
}
})
.createSpan({
text: "No saved players! Create one to see it here."
});
} else {
const headers = playerView.createDiv(
"initiative-tracker-player headers"
);
headers.createDiv({ text: "Name" });
new ExtraButtonComponent(headers.createDiv())
.setIcon(HP)
.setTooltip("Max HP");
new ExtraButtonComponent(headers.createDiv())
.setIcon(AC)
.setTooltip("Armor Class");
new ExtraButtonComponent(headers.createDiv())
.setIcon(INITIATIVE)
.setTooltip("Initiative Modifier");
headers.createDiv();
for (let player of this.plugin.data.players) {
const playerDiv = playerView.createDiv(
"initiative-tracker-player"
);
playerDiv.createDiv({ text: player.name });
playerDiv.createDiv({
text: `${player.hp ?? DEFAULT_UNDEFINED}`
});
playerDiv.createDiv({
text: `${player.ac ?? DEFAULT_UNDEFINED}`
});
playerDiv.createDiv({
text: `${player.modifier ?? DEFAULT_UNDEFINED}`
});
const icons = playerDiv.createDiv(
"initiative-tracker-player-icon"
);
new ExtraButtonComponent(icons.createDiv())
.setIcon("pencil")
.setTooltip("Edit")
.onClick(() => {
const modal = new NewPlayerModal(this.plugin, player);
modal.open();
modal.onClose = async () => {
if (!modal.saved) return;
await this.plugin.updatePlayer(
player,
modal.player
);
this.plugin.app.workspace.trigger(
"initiative-tracker:creature-updated-in-settings",
player
);
this._displayPlayers(additionalContainer);
};
});
new ExtraButtonComponent(icons.createDiv())
.setIcon("trash")
.setTooltip("Delete")
.onClick(async () => {
this.plugin.data.players =
this.plugin.data.players.filter((p) => p != player);
await this.plugin.saveSettings();
this._displayPlayers(additionalContainer);
});
}
}
}
private _displayParties(additionalContainer: HTMLDetailsElement) {
additionalContainer.empty();
additionalContainer.ontoggle = () => {
this.plugin.data.openState.party = additionalContainer.open;
};
const summary = additionalContainer.createEl("summary");
new Setting(summary).setHeading().setName("Parties");
summary.createDiv("collapser").createDiv("handle");
const explanation = additionalContainer.createDiv(
"initiative-tracker-explanation"
);
explanation.createEl("span", {
text: "Parties allow you to create different groups of your players. Each player can be a member of multiple parties."
});
explanation.createEl("br");
explanation.createEl("br");
explanation.createEl("span", {
text: "You can set a default party for encounters to use, or specify the party for the encounter in the encounter block. While running an encounter in the tracker, you can change the active party, allowing you to quickly switch which players are in combat."
});
new Setting(additionalContainer)
.setName("Default Party")
.setDesc(
"The tracker will load this party to encounters by default."
)
.addDropdown((d) => {
d.addOption("none", "None");
for (const party of this.plugin.data.parties) {
d.addOption(party.name, party.name);
}
d.setValue(this.plugin.data.defaultParty ?? "none");
d.onChange(async (v) => {
this.plugin.data.defaultParty = v == "none" ? null : v;
this.plugin.saveSettings();
});
});
new Setting(additionalContainer)
.setName("Add New Party")
.addButton((button: ButtonComponent): ButtonComponent => {
let b = button
.setTooltip("Add Party")
.setButtonText("+")
.onClick(async () => {
const modal = new PartyModal(this.plugin);
modal.open();
modal.onClose = async () => {
if (modal.canceled) return;
if (!modal.party.name || !modal.party.name.length)
return;
if (
this.plugin.data.parties.filter(
(party) => party.name == modal.party.name
)
) {
const map = new Map(
[...this.plugin.data.parties].map((c) => [
c.name,
c
])
);
map.set(modal.party.name, modal.party);
this.plugin.data.parties = Array.from(
map.values()
);
} else {
this.plugin.data.parties.push(modal.party);
}
await this.plugin.saveSettings();
this._displayParties(additionalContainer);
};
});
return b;
});
const additional = additionalContainer.createDiv("additional");
if (!this.plugin.data.parties.length) {
additional
.createDiv({
attr: {
style: "display: flex; justify-content: center; padding-bottom: 18px;"
}
})
.createSpan({
text: "No saved parties! Create one to see it here."
});
} else {
for (const party of this.plugin.data.parties) {
new Setting(additional)
.setName(party.name)
.setDesc(party.players.join(", "))
.addExtraButton((b) => {
b.setIcon("pencil").onClick(() => {
const modal = new PartyModal(this.plugin, party);
modal.open();
modal.onClose = async () => {
if (modal.canceled) return;
if (
!modal.party.name ||
!modal.party.name.length
)
return;
this.plugin.data.parties.splice(
this.plugin.data.parties.indexOf(party),
1,
modal.party
);
if (
this.plugin.data.parties.filter(
(s) => s.name == modal.party.name
).length > 1
) {
if (
this.plugin.data.parties.filter(
(status) =>
status.name == modal.party.name
)
) {
const map = new Map(
this.plugin.data.parties.map(
(c) => [c.name, c]
)
);
map.set(modal.party.name, modal.party);
this.plugin.data.parties = Array.from(
map.values()
);
}
}
await this.plugin.saveSettings();
this._displayParties(additionalContainer);
};
});
})
.addExtraButton((b) => {
b.setIcon("trash").onClick(async () => {
this.plugin.data.parties =
this.plugin.data.parties.filter(
(p) => p.name != party.name
);
if (this.plugin.data.defaultParty == party.name) {
this.plugin.data.defaultParty =
this.plugin.data.parties[0]?.name ?? null;
}
await this.plugin.saveSettings();
this._displayParties(additionalContainer);
});
});
}
}
}
private _displayStatuses(additionalContainer: HTMLDetailsElement) {
additionalContainer.empty();
additionalContainer.ontoggle = () => {
this.plugin.data.openState.status = additionalContainer.open;
};
const summary = additionalContainer.createEl("summary");
new Setting(summary).setHeading().setName("Statuses");
summary.createDiv("collapser").createDiv("handle");
const add = new Setting(additionalContainer)
.setName("Add New Status")
.setDesc("These statuses will be available to apply to creatures.")
.addButton((button: ButtonComponent): ButtonComponent => {
let b = button
.setTooltip("Add Status")
.setButtonText("+")
.onClick(async () => {
const modal = new StatusModal(this.plugin);
modal.onClose = async () => {
if (modal.canceled) return;
if (!modal.status.name) return;
if (
this.plugin.data.statuses.filter(
(status) => status.name == modal.status.name
)
) {
const map = new Map(
[...this.plugin.data.statuses].map((c) => [
c.name,
c
])
);
map.set(modal.status.name, modal.status);
this.plugin.data.statuses = Array.from(
map.values()
);
} else {
this.plugin.data.statuses.push(modal.status);
}
await this.plugin.saveSettings();
this._displayStatuses(additionalContainer);
};
modal.open();
});
return b;
});
if (!Conditions.every((c) => this.plugin.data.statuses.includes(c))) {
add.addExtraButton((b) =>
b
.setIcon("reset")
.setTooltip("Re-add Default Statuses")
.onClick(async () => {
this.plugin.data.statuses = Array.from(
new Map(
[
...this.plugin.data.statuses,
...Conditions
].map((c) => [c.name, c])
).values()
);
await this.plugin.saveSettings();
this._displayStatuses(additionalContainer);
})
);
}
const additional = additionalContainer.createDiv("additional");
for (const status of this.plugin.data.statuses) {
new Setting(additional)
.setName(status.name)
.setDesc(status.description)
.addExtraButton((b) =>
b.setIcon("pencil").onClick(() => {
const modal = new StatusModal(this.plugin, status);
modal.onClose = async () => {
if (modal.canceled) return;
if (!modal.status.name) return;
this.plugin.data.statuses.splice(
this.plugin.data.statuses.indexOf(status),
1,
modal.status
);
if (
this.plugin.data.statuses.filter(
(s) => s.name == modal.status.name
).length > 1
) {
if (
this.plugin.data.statuses.filter(
(status) =>
status.name == modal.status.name
)
) {
const map = new Map(
this.plugin.data.statuses.map((c) => [
c.name,
c
])
);
map.set(modal.status.name, modal.status);
this.plugin.data.statuses = Array.from(
map.values()
);
}
}
await this.plugin.saveSettings();
this._displayStatuses(additionalContainer);
};
modal.open();
})
)
.addExtraButton((b) =>
b.setIcon("trash").onClick(async () => {
this.plugin.data.statuses =
this.plugin.data.statuses.filter(
(s) => s.name != status.name
);
await this.plugin.saveSettings();
this._displayStatuses(additionalContainer);
})
)
.setClass("initiative-status-item");
}
}
private async _displayIntegrations(containerEl: HTMLDetailsElement) {
containerEl.empty();
containerEl.ontoggle = () => {
this.plugin.data.openState.plugin = containerEl.open;
};
const summary = containerEl.createEl("summary");
new Setting(summary).setHeading().setName("Plugin Integrations");
summary.createDiv("collapser").createDiv("handle");
if (!this.plugin.canUseStatBlocks) {
this.plugin.data.sync = false;
await this.plugin.saveSettings();
}
new Setting(containerEl)
.setName("Sync Monsters from TTRPG Statblocks")
.setDesc(
createFragment((e) => {
e.createSpan({
text: "Homebrew creatures saved to the TTRPG Statblocks plugin will be available in the quick-add."
});
if (!this.plugin.canUseStatBlocks) {
e.createEl("br");
e.createEl("br");
e.createSpan({
text: "Install and enable the "
});
e.createEl("a", {
text: "TTRPG Statblocks",
href: "obsidian://show-plugin?id=obsidian-5e-statblocks"
});
e.createSpan({
text: " plugin to use homebrew creatures."
});
}
})
)
.addToggle((t) => {
t.setDisabled(!this.plugin.canUseStatBlocks).setValue(
this.plugin.data.sync
);
t.onChange(async (v) => {
this.plugin.data.sync = v;
await this.plugin.saveSettings();
this._displayIntegrations(containerEl);
});
});
if (this.plugin.data.sync) {
const synced = new Setting(containerEl).setDesc(
`${this.plugin.statblock_creatures.length} creatures synced.`
);
synced.settingEl.addClass("initiative-synced");
setIcon(synced.nameEl, "check-in-circle");
synced.nameEl.appendChild(createSpan({ text: "Synced" }));
}
new Setting(containerEl)
.setName("Initiative Formula")
.setDesc(
createFragment((e) => {
e.createSpan({
text: "Initiative formula to use when calculating initiative. Use "
});
e.createEl("code", { text: "%mod%" });
e.createSpan({
text: " for the modifier placeholder."
});
if (!this.plugin.canUseDiceRoller) {
e.createEl("br");
e.createEl("br");
e.createSpan({
attr: {
style: `color: var(--text-error);`
},
text: "Requires the "
});
e.createEl("a", {
text: "Dice Roller",
href: "https://github.com/valentine195/obsidian-dice-roller",
cls: "external-link"
});
e.createSpan({
attr: {
style: `color: var(--text-error);`
},
text: " plugin to modify."
});
}
})
)
.addText((t) => {
if (!this.plugin.canUseDiceRoller) {
t.setDisabled(true);
this.plugin.data.initiative = "1d20 + %mod%";
}
t.setValue(this.plugin.data.initiative);
t.onChange((v) => {
this.plugin.data.initiative = v;
});
t.inputEl.onblur = async () => {
const view = this.plugin.view;
if (view) view.rollInitiatives();
await this.plugin.saveSettings();
};
});
new Setting(containerEl)
.setName("Integrate with Obsidian Leaflet")
.setDesc(
createFragment((e) => {
e.createSpan({
text: "Integrate with the Obsidian Leaflet plugin and display combats on a map."
});
if (!this.plugin.canUseLeaflet) {
e.createEl("br");
e.createEl("br");
e.createSpan({
attr: {
style: `color: var(--text-error);`
},
text: "Requires "
});
e.createEl("a", {
text: "Obsidian Leaflet",
href: "https://github.com/valentine195/obsidian-leaflet-plugin",
cls: "external-link"
});
e.createSpan({
attr: {
style: `color: var(--text-error);`
},
text: " version 4.0.0 to modify."
});
}
})
)
.addToggle((t) => {
if (!this.plugin.canUseLeaflet) {
t.setDisabled(true);
this.plugin.data.leafletIntegration = false;
}
t.setValue(this.plugin.data.leafletIntegration);
t.onChange(async (v) => {
this.plugin.data.leafletIntegration = v;
this.plugin.view.setMapState(v);
await this.plugin.saveSettings();
this._displayIntegrations(containerEl);
});
});
if (this.plugin.canUseLeaflet && this.plugin.data.leafletIntegration) {
new Setting(containerEl)
.setName("Default Player Marker Type")
.setDesc(
createFragment((e) => {
if (this.plugin.data.playerMarker) {
const div = e.createDiv("marker-type-display");
const inner = div.createDiv("marker-icon-display");
const marker = this.plugin.leaflet.markerIcons.find(
(icon) =>
icon.type == this.plugin.data.playerMarker
);
if (marker) {
inner.innerHTML = marker.html;
}
}
})
)
.addDropdown((drop) => {
for (let marker of this.plugin.leaflet.markerIcons) {
drop.addOption(marker.type, marker.type);
}
drop.setValue(this.plugin.data.playerMarker ?? "default");
drop.onChange(async (v) => {
this.plugin.data.playerMarker = v;
await this.plugin.saveSettings();
this._displayIntegrations(containerEl);
});
});
new Setting(containerEl)
.setName("Default Monster Marker Type")
.setDesc(
createFragment((e) => {
if (this.plugin.data.monsterMarker) {
const div = e.createDiv("marker-type-display");
const inner = div.createDiv("marker-icon-display");
const marker = this.plugin.leaflet.markerIcons.find(
(icon) =>
icon.type == this.plugin.data.monsterMarker
);
if (marker) {
inner.innerHTML = marker.html;
}
}
})
)
.addDropdown((drop) => {
for (let marker of this.plugin.leaflet.markerIcons) {
drop.addOption(marker.type, marker.type);
}
drop.setValue(this.plugin.data.monsterMarker);
drop.onChange(async (v) => {
this.plugin.data.monsterMarker = v;
await this.plugin.saveSettings();
this._displayIntegrations(containerEl);
});
});
}
}
private _displayHomebrew(additionalContainer: HTMLElement) {
additionalContainer.empty();
if (this.plugin.data.homebrew.length) {
const additional = additionalContainer.createDiv("additional");
new Setting(additional).setHeading().setName("Homebrew Creatures");
const warning = additional
.createDiv({
attr: {
style: "display: flex; justify-content: center; padding: 18px;"
}
})
.createEl("strong");
warning.createSpan({
text: "Homebrew creatures have moved to the "
});
warning.createEl("a", {
text: "5e Statblocks",
href: "obsidian://show-plugin?id=obsidian-5e-statblocks"
});
warning.createSpan({
text: " plugin."
});
if (this.plugin.canUseStatBlocks) {
new Setting(additional)
.setName("Migrate Hombrew")
.setDesc(
"Move all created homebrew creatures to the 5e Statblocks plugin."
)
.addButton((b) => {
b.setIcon("install")
.setTooltip("Migrate")
.onClick(async () => {
const statblocks = this.app.plugins.getPlugin(
"obsidian-5e-statblocks"
);
const existing =
statblocks.settings.monsters.length;
await statblocks.saveMonsters(
this.plugin.data.homebrew
);
new Notice(
`${
statblocks.settings.monsters.length -
existing
} of ${
this.plugin.data.homebrew.length
} Homebrew Monsters saved.`
);
});
})
.addExtraButton((b) => {
b.setIcon("cross-in-box")
.setTooltip("Delete Homebrew")
.onClick(async () => {
if (
await confirmWithModal(
this.app,
"Are you sure you want to delete all homebrew creatures?"
)
) {
this.plugin.data.homebrew = [];
await this.plugin.saveSettings();
this._displayHomebrew(additionalContainer);
}
});
});
} else {
additional
.createDiv({
attr: {
style: "display: flex; justify-content: center; padding: 18px;"
}
})
.createEl("strong");
warning.createSpan({
text: "Install the "
});
warning.createEl("a", {
text: "5e Statblocks",
href: "obsidian://show-plugin?id=obsidian-5e-statblocks"
});
warning.createSpan({
text: " plugin to migrate."
});
}
}
}
}
Example #21
Source File: settings.ts From obsidian-admonition with MIT License | 4 votes |
export default class AdmonitionSetting extends PluginSettingTab {
additionalEl: HTMLDivElement;
notice: Notice;
constructor(app: App, public plugin: ObsidianAdmonition) {
super(app, plugin);
}
async display(): Promise<void> {
this.containerEl.empty();
this.containerEl.addClass("admonition-settings");
this.containerEl.createEl("h2", { text: t("Admonition Settings") });
const admonitionEl = this.containerEl.createDiv(
"admonitions-nested-settings"
);
if (!Platform.isMobile) {
new Setting(admonitionEl)
.setName("Export Custom Types as CSS")
.setDesc("Export a CSS snippet for custom callout types.")
.addButton((b) =>
b
.setIcon("download")
.onClick(() => {
const sheet = [
`/* This snippet was auto-generated by the Admonitions plugin */\n\n`
];
const file = new Blob(
[
this.plugin.calloutManager.generateCssString()
],
{
type: "text/css"
}
);
createEl("a", {
attr: {
download: "custom_callouts.css",
href: URL.createObjectURL(file)
}
}).click();
})
.setDisabled(
!Object.keys(this.plugin.data.userAdmonitions)
.length
)
);
}
new Setting(admonitionEl)
.setName("Use CSS Snippet for Custom Callouts")
.setDesc(
"Instead of managing it internally, Admonitions will maintain a CSS snippet to enable your custom types for callouts."
)
.addToggle((t) =>
t.setValue(this.plugin.data.useSnippet).onChange((v) => {
this.plugin.data.useSnippet = v;
this.plugin.saveSettings();
this.plugin.calloutManager.setUseSnippet();
})
);
new Setting(admonitionEl)
.setName(t("Add New"))
.setDesc(
"Add a new Admonition type. All custom Admonitions will also be usable as callouts."
)
.addButton((button: ButtonComponent): ButtonComponent => {
let b = button
.setTooltip(t("Add Additional"))
.setButtonText("+")
.onClick(async () => {
let modal = new SettingsModal(this.plugin);
modal.onClose = async () => {
if (modal.saved) {
const admonition = {
type: modal.type,
color: modal.color,
icon: modal.icon,
command: false,
title: modal.title,
injectColor: modal.injectColor,
noTitle: modal.noTitle,
copy: modal.copy
};
this.plugin.addAdmonition(admonition);
this.plugin.calloutManager.addAdmonition(
admonition
);
this.display();
}
};
modal.open();
});
return b;
});
this.additionalEl = admonitionEl.createDiv("additional");
this.buildTypes();
this.buildAdmonitions(
this.containerEl.createEl("details", {
cls: "admonitions-nested-settings",
attr: {
...(this.plugin.data.open.admonitions ? { open: true } : {})
}
})
);
this.buildIcons(
this.containerEl.createEl("details", {
cls: "admonitions-nested-settings",
attr: {
...(this.plugin.data.open.icons ? { open: true } : {})
}
})
);
this.buildOtherSyntaxes(
this.containerEl.createEl("details", {
cls: "admonitions-nested-settings",
attr: {
...(this.plugin.data.open.other ? { open: true } : {})
}
})
);
this.buildAdvanced(
this.containerEl.createEl("details", {
cls: "admonitions-nested-settings",
attr: {
...(this.plugin.data.open.advanced ? { open: true } : {})
}
})
);
const div = this.containerEl.createDiv("coffee");
div.createEl("a", {
href: "https://www.buymeacoffee.com/valentine195"
}).createEl("img", {
attr: {
src: "https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=☕&slug=valentine195&button_colour=e3e7ef&font_colour=262626&font_family=Inter&outline_colour=262626&coffee_colour=ff0000"
}
});
}
buildAdmonitions(containerEl: HTMLDetailsElement) {
containerEl.empty();
containerEl.ontoggle = () => {
this.plugin.data.open.admonitions = containerEl.open;
this.plugin.saveSettings();
};
const summary = containerEl.createEl("summary");
new Setting(summary).setHeading().setName("Admonitions & Callouts");
summary.createDiv("collapser").createDiv("handle");
new Setting(containerEl)
.setName("Add Drop Shadow")
.setDesc("A drop shadow will be added to admonitions.")
.addToggle((t) => {
t.setValue(this.plugin.data.dropShadow).onChange(async (v) => {
this.plugin.data.dropShadow = v;
this.display();
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName(t("Collapsible by Default"))
.setDesc(
createFragment((e) => {
e.createSpan({
text: "All admonitions & callouts will be collapsible by default. Use "
});
e.createEl("code", {
text: "collapse: none"
});
e.createSpan({
text: t(" to prevent.")
});
})
)
.addToggle((t) => {
t.setValue(this.plugin.data.autoCollapse).onChange(
async (v) => {
this.plugin.data.autoCollapse = v;
this.display();
await this.plugin.saveSettings();
}
);
});
if (this.plugin.data.autoCollapse) {
new Setting(containerEl)
.setName(t("Default Collapse Type"))
.setDesc(
"Collapsible admonitions & callouts will be either opened or closed."
)
.addDropdown((d) => {
d.addOption("open", "open");
d.addOption("closed", "closed");
d.setValue(this.plugin.data.defaultCollapseType);
d.onChange(async (v: "open" | "closed") => {
this.plugin.data.defaultCollapseType = v;
await this.plugin.saveSettings();
});
});
}
new Setting(containerEl)
.setName(t("Add Copy Button"))
.setDesc("Add a 'copy content' button to admonitions & callouts.")
.addToggle((t) => {
t.setValue(this.plugin.data.copyButton);
t.onChange(async (v) => {
this.plugin.data.copyButton = v;
if (!v) {
document
.querySelectorAll(".admonition-content-copy")
.forEach((el) => {
el.detach();
});
}
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName(t("Parse Titles as Markdown"))
.setDesc(t("Admonition Titles will be rendered as markdown."))
.addToggle((t) => {
t.setValue(this.plugin.data.parseTitles);
t.onChange(async (v) => {
this.plugin.data.parseTitles = v;
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Set Admonition Colors")
.setDesc(
"Disable this setting to turn off admonition coloring by default. Can be overridden in the admonition definition."
)
.addToggle((t) =>
t
.setValue(this.plugin.data.injectColor)
.setTooltip(
`${
this.plugin.data.injectColor ? "Disable" : "Enable"
} Admonition Color`
)
.onChange(async (v) => {
this.plugin.data.injectColor = v;
await this.plugin.saveSettings();
await this.buildTypes();
})
);
new Setting(containerEl)
.setName("Hide Empty Admonitions")
.setDesc(
"Any admonition that does not have content inside it will be hidden."
)
.addToggle((t) =>
t.setValue(this.plugin.data.hideEmpty).onChange(async (v) => {
this.plugin.data.hideEmpty = v;
await this.plugin.saveSettings();
await this.buildTypes();
})
);
}
buildIcons(containerEl: HTMLDetailsElement) {
containerEl.empty();
containerEl.ontoggle = () => {
this.plugin.data.open.icons = containerEl.open;
this.plugin.saveSettings();
};
const summary = containerEl.createEl("summary");
new Setting(summary).setHeading().setName("Icon Packs");
summary.createDiv("collapser").createDiv("handle");
new Setting(containerEl)
.setName("Use Font Awesome Icons")
.setDesc(
"Font Awesome Free icons will be available in the item picker. Existing Admonitions defined using Font Awesome icons will continue to work."
)
.addToggle((t) => {
t.setValue(this.plugin.data.useFontAwesome).onChange((v) => {
this.plugin.data.useFontAwesome = v;
this.plugin.iconManager.setIconDefinitions();
this.plugin.saveSettings();
});
});
let selected: DownloadableIconPack;
const possibilities = Object.entries(DownloadableIcons).filter(
([icon]) => !this.plugin.data.icons.includes(icon)
);
new Setting(containerEl)
.setName("Load Additional Icons")
.setDesc(
"Load an additional icon pack. This requires an internet connection."
)
.addDropdown((d) => {
if (!possibilities.length) {
d.setDisabled(true);
return;
}
for (const [icon, display] of possibilities) {
d.addOption(icon, display);
}
d.onChange((v: DownloadableIconPack) => (selected = v));
selected = d.getValue() as DownloadableIconPack;
})
.addExtraButton((b) => {
b.setIcon("plus-with-circle")
.setTooltip("Load")
.onClick(async () => {
if (!selected || !selected.length) return;
await this.plugin.iconManager.downloadIcon(selected);
this.buildIcons(containerEl);
});
if (!possibilities.length) b.setDisabled(true);
});
const iconsEl = containerEl.createDiv("admonitions-nested-settings");
new Setting(iconsEl);
for (const icon of this.plugin.data.icons) {
new Setting(iconsEl)
.setName(DownloadableIcons[icon])
.addExtraButton((b) => {
b.setIcon("reset")
.setTooltip("Redownload")
.onClick(async () => {
await this.plugin.iconManager.removeIcon(icon);
await this.plugin.iconManager.downloadIcon(icon);
this.buildIcons(containerEl);
});
})
.addExtraButton((b) => {
b.setIcon("trash").onClick(async () => {
if (
Object.values(
this.plugin.data.userAdmonitions
).find((admonition) => admonition.icon.type == icon)
) {
if (
!(await confirmWithModal(
this.plugin.app,
"You have Admonitions using icons from this pack. Are you sure you want to remove it?"
))
)
return;
}
await this.plugin.iconManager.removeIcon(icon);
this.buildIcons(containerEl);
});
});
}
}
buildOtherSyntaxes(containerEl: HTMLDetailsElement) {
containerEl.empty();
containerEl.ontoggle = () => {
this.plugin.data.open.other = containerEl.open;
this.plugin.saveSettings();
};
const summary = containerEl.createEl("summary");
new Setting(summary).setHeading().setName("Additional Syntaxes");
summary.createDiv("collapser").createDiv("handle");
containerEl.createEl("p", {
text: "Obsidian 0.14 has introduced Callout boxes to its core functionality using the same syntax as the Microsoft Document callouts.",
cls: "setting-item"
});
containerEl.createEl("p", {
text: "This has rendered the Microsoft Document syntax for Admonitions obsolete, but Admonitions can still be used to create and manage your custom callout types.",
cls: "setting-item"
});
containerEl.createEl("p", {
text: "Your existing code block Admonitions will always work!",
cls: "setting-item"
});
if (!this.plugin.data.msDocConverted) {
new Setting(containerEl)
.setName("Convert MSDoc Admonitions to Callouts")
.setDesc(
createFragment((e) => {
const text = e.createDiv("admonition-convert");
setIcon(text.createSpan(), WARNING_ICON_NAME);
text.createSpan({
text: "This "
});
text.createEl("strong", { text: "will" });
text.createSpan({
text: " modify notes. Use at your own risk and please make backups."
});
e.createEl("p", {
text: "With large vaults, this could take awhile!"
});
})
)
.addButton((b) =>
b
.setButtonText("Convert")
.setCta()
.onClick(() => {
this.queue =
this.plugin.app.vault.getMarkdownFiles();
this.notice = new Notice(
createFragment((e) => {
const container =
e.createDiv("admonition-convert");
container.createSpan({
text: "Converting MS-doc admonitions..."
});
setIcon(
container.createSpan(
"admonition-convert-icon"
),
SPIN_ICON_NAME
);
}),
0
);
this.checkAndReplace();
})
);
}
new Setting(containerEl)
.setName("Convert Codeblock Admonitions to Callouts")
.setDesc(
createFragment((e) => {
const text = e.createDiv("admonition-convert");
setIcon(text.createSpan(), WARNING_ICON_NAME);
text.createSpan({
text: "This "
});
text.createEl("strong", { text: "will" });
text.createSpan({
text: " modify notes. Use at your own risk and please make backups."
});
e.createEl("p", {
text: "With large vaults, this could take awhile!"
});
})
)
.addButton((b) =>
b
.setButtonText("Convert")
.setCta()
.onClick(() => {
this.queue = this.plugin.app.vault.getMarkdownFiles();
/* this.queue = [
this.plugin.app.vault.getAbstractFileByPath(
"99 Plugin Testing/admonition/Admonition Codeblock.md"
) as TFile
]; */
this.notice = new Notice(
createFragment((e) => {
const container =
e.createDiv("admonition-convert");
container.createSpan({
text: "Converting Codeblock admonitions..."
});
setIcon(
container.createSpan(
"admonition-convert-icon"
),
SPIN_ICON_NAME
);
}),
0
);
this.converted = 0;
this.checkAndReplaceCodeBlocks();
})
);
}
queue: TFile[] = [];
converted = 0;
async checkAndReplace() {
if (!this.queue.length) {
if (this.converted) {
this.notice.setMessage(
`${this.converted} MS-doc Admonitions converted!`
);
} else {
this.notice.setMessage(
"No MS-doc Admonitions found to convert."
);
}
this.plugin.data.msDocConverted = true;
this.plugin.saveSettings().then(() => this.display());
setTimeout(() => {
this.notice.hide();
this.notice = undefined;
}, 2000);
return;
}
setTimeout(async () => {
const file = this.queue.shift();
const contents = await this.app.vault.read(file);
if (/> \[!([^ :]+)(?::[ ]?(.+))\](x|\+|\-)?/.test(contents)) {
this.converted++;
await this.plugin.app.vault.modify(
file,
contents.replace(
/> \[!([^ :]+)(?::[ ]?(.+))\](x|\+|\-)?/g,
`> [!$1]$3 $2`
)
);
}
this.checkAndReplace();
});
}
async checkAndReplaceCodeBlocks() {
if (!this.queue.length) {
if (this.converted) {
this.notice.setMessage(
`${this.converted} Codeblock Admonitions converted!`
);
} else {
this.notice.setMessage(
"No Codeblock Admonitions found to convert."
);
}
this.display();
setTimeout(() => {
this.notice.hide();
this.notice = undefined;
}, 2000);
return;
}
setTimeout(async () => {
const file = this.queue.shift();
let contents = await this.app.vault.read(file);
if (/^(`{3,})ad-(\w+)([\s\S]*?)?\n^\1/m.test(contents)) {
contents = this.replaceCodeBlockInPlace(contents);
this.app.vault.modify(file, contents);
}
this.checkAndReplaceCodeBlocks();
});
}
replaceCodeBlockInPlace(contents: string): string {
const admonitions =
contents.match(/^(`{3,})ad-(\w+)([\s\S]*?)?\n^\1/gm) ?? [];
for (const admonition of admonitions) {
let [, type] = admonition.match(/^`{3,}ad-(\w+)/),
title = "",
collapse = "";
if (!type) continue;
let content = [];
let mine = true;
for (const line of admonition.split("\n").slice(1, -1)) {
if (mine) {
if (/^title:/.test(line)) {
title =
line.match(/^title:(.*)/)?.[1].trim() ??
type[0].toUpperCase() + type.slice(1).toLowerCase();
continue;
}
if (/^collapse:/.test(line)) {
const state =
line.match(/^collapse:\s?(.*)/)?.[1].trim() ??
"open";
collapse = state == "open" ? "+" : "-";
continue;
}
if (!/^(title|collapse|color|icon):/.test(line)) {
mine = false;
}
}
content.push(line);
}
let parsed = content.join("\n");
if (/^(`{3,})ad-(\w+)([\s\S]*?)?\n^\1/m.test(parsed)) {
parsed = this.replaceCodeBlockInPlace(parsed);
}
contents = contents.replace(
admonition,
`> [!${type}]${collapse}${
title.length ? " " : ""
}${title}\n> ${parsed.split("\n").join("\n> ")}`
);
this.converted++;
}
return contents;
}
buildAdvanced(containerEl: HTMLDetailsElement) {
containerEl.empty();
containerEl.ontoggle = () => {
this.plugin.data.open.advanced = containerEl.open;
this.plugin.saveSettings();
};
const summary = containerEl.createEl("summary");
new Setting(summary).setHeading().setName("Advanced Settings");
summary.createDiv("collapser").createDiv("handle");
new Setting(containerEl)
.setName(t("Markdown Syntax Highlighting"))
.setDesc(
t(
"Use Obsidian's markdown syntax highlighter in admonition code blocks. This setting is experimental and could cause errors."
)
)
.addToggle((t) => {
t.setValue(this.plugin.data.syntaxHighlight);
t.onChange(async (v) => {
this.plugin.data.syntaxHighlight = v;
if (v) {
this.plugin.turnOnSyntaxHighlighting();
} else {
this.plugin.turnOffSyntaxHighlighting();
}
await this.plugin.saveSettings();
});
});
new Setting(containerEl)
.setName("Generate JS for Publish")
.setDesc(
createFragment((f) => {
f.createSpan({
text: "Generate a javascript file to place in your "
});
f.createEl("code", { text: "publish.js" });
f.createSpan({ text: "file." });
f.createEl("br");
f.createEl("strong", {
text: "Please note that this can only be done on custom domain publish sites."
});
})
)
.addButton((b) => {
b.setButtonText("Generate");
b.onClick((evt) => {
const admonition_icons: {
[admonition_type: string]: {
icon: string;
color: string;
};
} = {};
for (let key in this.plugin.admonitions) {
const value = this.plugin.admonitions[key];
admonition_icons[key] = {
icon:
this.plugin.iconManager.getIconNode(value.icon)
?.outerHTML ?? "",
color: value.color
};
}
const js = CONTENT.replace(
/ADMONITION_ICON_MAP\s?=\s?\{\}/,
"ADMONITION_ICON_MAP=" +
JSON.stringify(admonition_icons)
);
const file = new Blob([js], {
type: "text/javascript"
});
const link = createEl("a", {
href: URL.createObjectURL(file),
attr: {
download: "publish.admonition.js"
}
});
link.click();
link.detach();
});
});
}
buildTypes() {
this.additionalEl.empty();
for (const admonition of Object.values(
this.plugin.data.userAdmonitions
)) {
let setting = new Setting(this.additionalEl);
let admonitionElement = this.plugin.getAdmonitionElement(
admonition.type,
admonition.type[0].toUpperCase() +
admonition.type.slice(1).toLowerCase(),
admonition.icon,
admonition.injectColor ?? this.plugin.data.injectColor
? admonition.color
: null
);
setting.infoEl.replaceWith(admonitionElement);
if (!admonition.command) {
setting.addExtraButton((b) => {
b.setIcon(ADD_COMMAND_NAME.toString())
.setTooltip(t("Register Commands"))
.onClick(async () => {
this.plugin.registerCommandsFor(admonition);
await this.plugin.saveSettings();
this.display();
});
});
} else {
setting.addExtraButton((b) => {
b.setIcon(REMOVE_COMMAND_NAME.toString())
.setTooltip(t("Unregister Commands"))
.onClick(async () => {
this.plugin.unregisterCommandsFor(admonition);
await this.plugin.saveSettings();
this.display();
});
});
}
setting
.addExtraButton((b) => {
b.setIcon("pencil")
.setTooltip(t("Edit"))
.onClick(() => {
let modal = new SettingsModal(
this.plugin,
admonition
);
modal.onClose = async () => {
if (modal.saved) {
const hasCommand = admonition.command;
const modalAdmonition = {
type: modal.type,
color: modal.color,
icon: modal.icon,
command: hasCommand,
title: modal.title,
injectColor: modal.injectColor,
noTitle: modal.noTitle,
copy: modal.copy
};
if (
modalAdmonition.type != admonition.type
) {
this.plugin.unregisterType(admonition);
const existing: [string, Admonition][] =
Object.entries(
this.plugin.data.userAdmonitions
);
this.plugin.data.userAdmonitions =
Object.fromEntries(
existing.map(([type, def]) => {
if (
type == admonition.type
) {
return [
modalAdmonition.type,
modalAdmonition
];
}
return [type, def];
})
);
} else {
this.plugin.data.userAdmonitions[
modalAdmonition.type
] = modalAdmonition;
}
this.plugin.registerType(
modalAdmonition.type
);
this.plugin.calloutManager.addAdmonition(
modalAdmonition
);
this.display();
}
};
modal.open();
});
})
.addExtraButton((b) => {
b.setIcon("trash")
.setTooltip(t("Delete"))
.onClick(() => {
this.plugin.removeAdmonition(admonition);
this.display();
});
});
}
}
}
Example #22
Source File: main.ts From obsidian-jupyter with MIT License | 4 votes |
class JupyterSettingTab extends PluginSettingTab {
plugin: JupyterPlugin;
constructor(app: App, plugin: JupyterPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
new Setting(containerEl)
.setName('Python interpreter')
.setDesc('Path to your python interpreter, e.g. `/usr/bin/python`.')
.setClass('wideSettingsElement')
.addText(text => text
.setValue(this.plugin.settings.pythonInterpreter)
.onChange(async (value) => {
this.plugin.settings.pythonInterpreter = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Python setup script')
.setDesc('Script that is run prior to every execution of a python code block.')
.setClass('setupScriptTextArea')
.setClass('wideSettingsElement')
.addTextArea(text => text
.setValue(this.plugin.settings.setupScript)
.onChange(async (value) => {
this.plugin.settings.setupScript = value;
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName('Test python environment')
.setDesc('Run a script to test the setup of your python environment (view developer console for details).')
.addButton(button => {
button.setButtonText('Run test');
button.onClick(evt => {
let client = this.plugin.getJupyterClient({
docId: 'test-document',
sourcePath: null,
frontmatter: null,
addChild: null,
getSectionInfo: null,
});
client.request({
command: 'execute',
source: '1 + 1',
}).then(response => {
console.log('Received response', response);
new Notice('Test successful, view developer console for details.');
}
).catch(error => {
console.error(error);
new Notice('Test failed, view developer console for details.');
}).finally(() => {
client.stop();
this.plugin.clients.delete('test-document');
});
});
});
new Setting(containerEl)
.setName('Install python dependencies')
.setDesc('This will modify your environment-use at your own risk.')
.addButton(button => {
button.setButtonText('Install dependencies');
button.onClick(evt => {
let interpreter = this.plugin.settings.pythonInterpreter;
let command = `${interpreter} -u -m pip install --upgrade --upgrade-strategy eager jupyter`;
new Notice('Installing dependencies; this may take some time...');
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`failed to install dependencies: {error}`);
new Notice('Failed to install dependencies, view developer console for details.');
}
console.log(`install stdout: ${stdout}`);
console.log(`install stderr: ${stdout}`);
new Notice('Installed dependencies, view developer console for details.');
});
});
});
}
}
Example #23
Source File: settings.tsx From obsidian-spaced-repetition with MIT License | 4 votes |
export class SRSettingTab extends PluginSettingTab {
private plugin: SRPlugin;
constructor(app: App, plugin: SRPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createDiv().innerHTML = <h2>{t("SETTINGS_HEADER")}</h2>;
containerEl.createDiv().innerHTML = t("CHECK_WIKI", {
wiki_url: "https://github.com/st3v3nmw/obsidian-spaced-repetition/wiki",
});
new Setting(containerEl)
.setName(t("FOLDERS_TO_IGNORE"))
.setDesc(t("FOLDERS_TO_IGNORE_DESC"))
.addTextArea((text) =>
text
.setValue(this.plugin.data.settings.noteFoldersToIgnore.join("\n"))
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.noteFoldersToIgnore = value
.split(/\n+/)
.map((v) => v.trim())
.filter((v) => v);
await this.plugin.savePluginData();
});
})
);
containerEl.createDiv().innerHTML = <h3>{t("FLASHCARDS")}</h3>;
new Setting(containerEl)
.setName(t("FLASHCARD_TAGS"))
.setDesc(t("FLASHCARD_TAGS_DESC"))
.addTextArea((text) =>
text
.setValue(this.plugin.data.settings.flashcardTags.join(" "))
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.flashcardTags = value.split(/\s+/);
await this.plugin.savePluginData();
});
})
);
new Setting(containerEl)
.setName(t("CONVERT_FOLDERS_TO_DECKS"))
.setDesc(t("CONVERT_FOLDERS_TO_DECKS_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.convertFoldersToDecks)
.onChange(async (value) => {
this.plugin.data.settings.convertFoldersToDecks = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("INLINE_SCHEDULING_COMMENTS"))
.setDesc(t("INLINE_SCHEDULING_COMMENTS_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.cardCommentOnSameLine)
.onChange(async (value) => {
this.plugin.data.settings.cardCommentOnSameLine = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("BURY_SIBLINGS_TILL_NEXT_DAY"))
.setDesc(t("BURY_SIBLINGS_TILL_NEXT_DAY_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.burySiblingCards)
.onChange(async (value) => {
this.plugin.data.settings.burySiblingCards = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("SHOW_CARD_CONTEXT"))
.setDesc(t("SHOW_CARD_CONTEXT_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.showContextInCards)
.onChange(async (value) => {
this.plugin.data.settings.showContextInCards = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("CARD_MODAL_HEIGHT_PERCENT"))
.setDesc(t("CARD_MODAL_SIZE_PERCENT_DESC"))
.addSlider((slider) =>
slider
.setLimits(10, 100, 5)
.setValue(this.plugin.data.settings.flashcardHeightPercentage)
.setDynamicTooltip()
.onChange(async (value) => {
this.plugin.data.settings.flashcardHeightPercentage = value;
await this.plugin.savePluginData();
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.flashcardHeightPercentage =
DEFAULT_SETTINGS.flashcardHeightPercentage;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("CARD_MODAL_WIDTH_PERCENT"))
.setDesc(t("CARD_MODAL_SIZE_PERCENT_DESC"))
.addSlider((slider) =>
slider
.setLimits(10, 100, 5)
.setValue(this.plugin.data.settings.flashcardWidthPercentage)
.setDynamicTooltip()
.onChange(async (value) => {
this.plugin.data.settings.flashcardWidthPercentage = value;
await this.plugin.savePluginData();
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.flashcardWidthPercentage =
DEFAULT_SETTINGS.flashcardWidthPercentage;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl).setName(t("FILENAME_OR_OPEN_FILE")).addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.showFileNameInFileLink)
.onChange(async (value) => {
this.plugin.data.settings.showFileNameInFileLink = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl).setName(t("RANDOMIZE_CARD_ORDER")).addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.randomizeCardOrder)
.onChange(async (value) => {
this.plugin.data.settings.randomizeCardOrder = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl).setName(t("CONVERT_HIGHLIGHTS_TO_CLOZES")).addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.convertHighlightsToClozes)
.onChange(async (value) => {
this.plugin.data.settings.convertHighlightsToClozes = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl).setName(t("CONVERT_BOLD_TEXT_TO_CLOZES")).addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.convertBoldTextToClozes)
.onChange(async (value) => {
this.plugin.data.settings.convertBoldTextToClozes = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("INLINE_CARDS_SEPARATOR"))
.setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.singlelineCardSeparator)
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.singlelineCardSeparator = value;
await this.plugin.savePluginData();
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.singlelineCardSeparator =
DEFAULT_SETTINGS.singlelineCardSeparator;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("INLINE_REVERSED_CARDS_SEPARATOR"))
.setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.singlelineReversedCardSeparator)
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.singlelineReversedCardSeparator = value;
await this.plugin.savePluginData();
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.singlelineReversedCardSeparator =
DEFAULT_SETTINGS.singlelineReversedCardSeparator;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("MULTILINE_CARDS_SEPARATOR"))
.setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.multilineCardSeparator)
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.multilineCardSeparator = value;
await this.plugin.savePluginData();
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.multilineCardSeparator =
DEFAULT_SETTINGS.multilineCardSeparator;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("MULTILINE_REVERSED_CARDS_SEPARATOR"))
.setDesc(t("FIX_SEPARATORS_MANUALLY_WARNING"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.multilineReversedCardSeparator)
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.multilineReversedCardSeparator = value;
await this.plugin.savePluginData();
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.multilineReversedCardSeparator =
DEFAULT_SETTINGS.multilineReversedCardSeparator;
await this.plugin.savePluginData();
this.display();
});
});
containerEl.createDiv().innerHTML = <h3>{t("NOTES")}</h3>;
new Setting(containerEl)
.setName(t("TAGS_TO_REVIEW"))
.setDesc(t("TAGS_TO_REVIEW_DESC"))
.addTextArea((text) =>
text
.setValue(this.plugin.data.settings.tagsToReview.join(" "))
.onChange((value) => {
applySettingsUpdate(async () => {
this.plugin.data.settings.tagsToReview = value.split(/\s+/);
await this.plugin.savePluginData();
});
})
);
new Setting(containerEl)
.setName(t("OPEN_RANDOM_NOTE"))
.setDesc(t("OPEN_RANDOM_NOTE_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.openRandomNote)
.onChange(async (value) => {
this.plugin.data.settings.openRandomNote = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl).setName(t("AUTO_NEXT_NOTE")).addToggle((toggle) =>
toggle.setValue(this.plugin.data.settings.autoNextNote).onChange(async (value) => {
this.plugin.data.settings.autoNextNote = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("DISABLE_FILE_MENU_REVIEW_OPTIONS"))
.setDesc(t("DISABLE_FILE_MENU_REVIEW_OPTIONS_DESC"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.data.settings.disableFileMenuReviewOptions)
.onChange(async (value) => {
this.plugin.data.settings.disableFileMenuReviewOptions = value;
await this.plugin.savePluginData();
})
);
new Setting(containerEl)
.setName(t("MAX_N_DAYS_REVIEW_QUEUE"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.maxNDaysNotesReviewQueue.toString())
.onChange((value) => {
applySettingsUpdate(async () => {
const numValue: number = Number.parseInt(value);
if (!isNaN(numValue)) {
if (numValue < 1) {
new Notice(t("MIN_ONE_DAY"));
text.setValue(
this.plugin.data.settings.maxNDaysNotesReviewQueue.toString()
);
return;
}
this.plugin.data.settings.maxNDaysNotesReviewQueue = numValue;
await this.plugin.savePluginData();
} else {
new Notice(t("VALID_NUMBER_WARNING"));
}
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.maxNDaysNotesReviewQueue =
DEFAULT_SETTINGS.maxNDaysNotesReviewQueue;
await this.plugin.savePluginData();
this.display();
});
});
containerEl.createDiv().innerHTML = <h3>{t("ALGORITHM")}</h3>;
containerEl.createDiv().innerHTML = t("CHECK_ALGORITHM_WIKI", {
algo_url:
"https://github.com/st3v3nmw/obsidian-spaced-repetition/wiki/Spaced-Repetition-Algorithm",
});
new Setting(containerEl)
.setName(t("BASE_EASE"))
.setDesc(t("BASE_EASE_DESC"))
.addText((text) =>
text.setValue(this.plugin.data.settings.baseEase.toString()).onChange((value) => {
applySettingsUpdate(async () => {
const numValue: number = Number.parseInt(value);
if (!isNaN(numValue)) {
if (numValue < 130) {
new Notice(t("BASE_EASE_MIN_WARNING"));
text.setValue(this.plugin.data.settings.baseEase.toString());
return;
}
this.plugin.data.settings.baseEase = numValue;
await this.plugin.savePluginData();
} else {
new Notice(t("VALID_NUMBER_WARNING"));
}
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.baseEase = DEFAULT_SETTINGS.baseEase;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("LAPSE_INTERVAL_CHANGE"))
.setDesc(t("LAPSE_INTERVAL_CHANGE_DESC"))
.addSlider((slider) =>
slider
.setLimits(1, 99, 1)
.setValue(this.plugin.data.settings.lapsesIntervalChange * 100)
.setDynamicTooltip()
.onChange(async (value: number) => {
this.plugin.data.settings.lapsesIntervalChange = value / 100;
await this.plugin.savePluginData();
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.lapsesIntervalChange =
DEFAULT_SETTINGS.lapsesIntervalChange;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("EASY_BONUS"))
.setDesc(t("EASY_BONUS_DESC"))
.addText((text) =>
text
.setValue((this.plugin.data.settings.easyBonus * 100).toString())
.onChange((value) => {
applySettingsUpdate(async () => {
const numValue: number = Number.parseInt(value) / 100;
if (!isNaN(numValue)) {
if (numValue < 1.0) {
new Notice(t("EASY_BONUS_MIN_WARNING"));
text.setValue(
(this.plugin.data.settings.easyBonus * 100).toString()
);
return;
}
this.plugin.data.settings.easyBonus = numValue;
await this.plugin.savePluginData();
} else {
new Notice(t("VALID_NUMBER_WARNING"));
}
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.easyBonus = DEFAULT_SETTINGS.easyBonus;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("MAX_INTERVAL"))
.setDesc(t("MAX_INTERVAL_DESC"))
.addText((text) =>
text
.setValue(this.plugin.data.settings.maximumInterval.toString())
.onChange((value) => {
applySettingsUpdate(async () => {
const numValue: number = Number.parseInt(value);
if (!isNaN(numValue)) {
if (numValue < 1) {
new Notice(t("MAX_INTERVAL_MIN_WARNING"));
text.setValue(
this.plugin.data.settings.maximumInterval.toString()
);
return;
}
this.plugin.data.settings.maximumInterval = numValue;
await this.plugin.savePluginData();
} else {
new Notice(t("VALID_NUMBER_WARNING"));
}
});
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.maximumInterval =
DEFAULT_SETTINGS.maximumInterval;
await this.plugin.savePluginData();
this.display();
});
});
new Setting(containerEl)
.setName(t("MAX_LINK_CONTRIB"))
.setDesc(t("MAX_LINK_CONTRIB_DESC"))
.addSlider((slider) =>
slider
.setLimits(0, 100, 1)
.setValue(this.plugin.data.settings.maxLinkFactor * 100)
.setDynamicTooltip()
.onChange(async (value: number) => {
this.plugin.data.settings.maxLinkFactor = value / 100;
await this.plugin.savePluginData();
})
)
.addExtraButton((button) => {
button
.setIcon("reset")
.setTooltip(t("RESET_DEFAULT"))
.onClick(async () => {
this.plugin.data.settings.maxLinkFactor = DEFAULT_SETTINGS.maxLinkFactor;
await this.plugin.savePluginData();
this.display();
});
});
containerEl.createDiv().innerHTML = <h3>{t("LOGGING")}</h3>;
new Setting(containerEl).setName(t("DISPLAY_DEBUG_INFO")).addToggle((toggle) =>
toggle.setValue(this.plugin.data.settings.showDebugMessages).onChange(async (value) => {
this.plugin.data.settings.showDebugMessages = value;
await this.plugin.savePluginData();
})
);
}
}
Example #24
Source File: settings.ts From remotely-save with Apache License 2.0 | 4 votes |
export class RemotelySaveSettingTab extends PluginSettingTab {
readonly plugin: RemotelySavePlugin;
constructor(app: App, plugin: RemotelySavePlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
const t = (x: TransItemType, vars?: any) => {
return this.plugin.i18n.t(x, vars);
};
containerEl.createEl("h1", { text: "Remotely Save" });
//////////////////////////////////////////////////
// below for service chooser (part 1/2)
//////////////////////////////////////////////////
// we need to create the div in advance of any other service divs
const serviceChooserDiv = containerEl.createDiv();
serviceChooserDiv.createEl("h2", { text: t("settings_chooseservice") });
//////////////////////////////////////////////////
// below for s3
//////////////////////////////////////////////////
const s3Div = containerEl.createEl("div", { cls: "s3-hide" });
s3Div.toggleClass("s3-hide", this.plugin.settings.serviceType !== "s3");
s3Div.createEl("h2", { text: t("settings_s3") });
const s3LongDescDiv = s3Div.createEl("div", { cls: "settings-long-desc" });
for (const c of [
t("settings_s3_disclaimer1"),
t("settings_s3_disclaimer2"),
]) {
s3LongDescDiv.createEl("p", {
text: c,
cls: "s3-disclaimer",
});
}
if (!VALID_REQURL) {
s3LongDescDiv.createEl("p", {
text: t("settings_s3_cors"),
});
}
s3LongDescDiv.createEl("p", {
text: t("settings_s3_prod"),
});
const s3LinksUl = s3LongDescDiv.createEl("ul");
s3LinksUl.createEl("li").createEl("a", {
href: "https://docs.aws.amazon.com/general/latest/gr/s3.html",
text: t("settings_s3_prod1"),
});
s3LinksUl.createEl("li").createEl("a", {
href: "https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-your-credentials.html",
text: t("settings_s3_prod2"),
});
if (!VALID_REQURL) {
s3LinksUl.createEl("li").createEl("a", {
href: "https://docs.aws.amazon.com/AmazonS3/latest/userguide/enabling-cors-examples.html",
text: t("settings_s3_prod3"),
});
}
new Setting(s3Div)
.setName(t("settings_s3_endpoint"))
.setDesc(t("settings_s3_endpoint"))
.addText((text) =>
text
.setPlaceholder("")
.setValue(this.plugin.settings.s3.s3Endpoint)
.onChange(async (value) => {
this.plugin.settings.s3.s3Endpoint = value.trim();
await this.plugin.saveSettings();
})
);
new Setting(s3Div)
.setName(t("settings_s3_region"))
.setDesc(t("settings_s3_region_desc"))
.addText((text) =>
text
.setPlaceholder("")
.setValue(`${this.plugin.settings.s3.s3Region}`)
.onChange(async (value) => {
this.plugin.settings.s3.s3Region = value.trim();
await this.plugin.saveSettings();
})
);
new Setting(s3Div)
.setName(t("settings_s3_accesskeyid"))
.setDesc(t("settings_s3_accesskeyid_desc"))
.addText((text) => {
wrapTextWithPasswordHide(text);
text
.setPlaceholder("")
.setValue(`${this.plugin.settings.s3.s3AccessKeyID}`)
.onChange(async (value) => {
this.plugin.settings.s3.s3AccessKeyID = value.trim();
await this.plugin.saveSettings();
});
});
new Setting(s3Div)
.setName(t("settings_s3_secretaccesskey"))
.setDesc(t("settings_s3_secretaccesskey_desc"))
.addText((text) => {
wrapTextWithPasswordHide(text);
text
.setPlaceholder("")
.setValue(`${this.plugin.settings.s3.s3SecretAccessKey}`)
.onChange(async (value) => {
this.plugin.settings.s3.s3SecretAccessKey = value.trim();
await this.plugin.saveSettings();
});
});
new Setting(s3Div)
.setName(t("settings_s3_bucketname"))
.setDesc(t("settings_s3_bucketname"))
.addText((text) =>
text
.setPlaceholder("")
.setValue(`${this.plugin.settings.s3.s3BucketName}`)
.onChange(async (value) => {
this.plugin.settings.s3.s3BucketName = value.trim();
await this.plugin.saveSettings();
})
);
new Setting(s3Div)
.setName(t("settings_s3_urlstyle"))
.setDesc(t("settings_s3_urlstyle_desc"))
.addDropdown((dropdown) => {
dropdown.addOption(
"virtualHostedStyle",
"Virtual Hosted-Style (default)"
);
dropdown.addOption("pathStyle", "Path-Style");
dropdown
.setValue(
this.plugin.settings.s3.forcePathStyle
? "pathStyle"
: "virtualHostedStyle"
)
.onChange(async (val: string) => {
this.plugin.settings.s3.forcePathStyle = val === "pathStyle";
await this.plugin.saveSettings();
});
});
if (VALID_REQURL) {
new Setting(s3Div)
.setName(t("settings_s3_bypasscorslocally"))
.setDesc(t("settings_s3_bypasscorslocally_desc"))
.addDropdown((dropdown) => {
dropdown
.addOption("disable", t("disable"))
.addOption("enable", t("enable"));
dropdown
.setValue(
`${
this.plugin.settings.s3.bypassCorsLocally ? "enable" : "disable"
}`
)
.onChange(async (value) => {
if (value === "enable") {
this.plugin.settings.s3.bypassCorsLocally = true;
} else {
this.plugin.settings.s3.bypassCorsLocally = false;
}
await this.plugin.saveSettings();
});
});
}
new Setting(s3Div)
.setName(t("settings_s3_parts"))
.setDesc(t("settings_s3_parts_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("1", "1");
dropdown.addOption("2", "2");
dropdown.addOption("3", "3");
dropdown.addOption("5", "5");
dropdown.addOption("10", "10");
dropdown.addOption("15", "15");
dropdown.addOption("20", "20 (default)");
dropdown
.setValue(`${this.plugin.settings.s3.partsConcurrency}`)
.onChange(async (val) => {
const realVal = parseInt(val);
this.plugin.settings.s3.partsConcurrency = realVal;
await this.plugin.saveSettings();
});
});
new Setting(s3Div)
.setName(t("settings_checkonnectivity"))
.setDesc(t("settings_checkonnectivity_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_checkonnectivity_button"));
button.onClick(async () => {
new Notice(t("settings_checkonnectivity_checking"));
const client = new RemoteClient("s3", this.plugin.settings.s3);
const errors = { msg: "" };
const res = await client.checkConnectivity((err: any) => {
errors.msg = err;
});
if (res) {
new Notice(t("settings_s3_connect_succ"));
} else {
new Notice(t("settings_s3_connect_fail"));
new Notice(errors.msg);
}
});
});
//////////////////////////////////////////////////
// below for dropbpx
//////////////////////////////////////////////////
const dropboxDiv = containerEl.createEl("div", { cls: "dropbox-hide" });
dropboxDiv.toggleClass(
"dropbox-hide",
this.plugin.settings.serviceType !== "dropbox"
);
dropboxDiv.createEl("h2", { text: t("settings_dropbox") });
const dropboxLongDescDiv = dropboxDiv.createEl("div", {
cls: "settings-long-desc",
});
for (const c of [
t("settings_dropbox_disclaimer1"),
t("settings_dropbox_disclaimer2"),
]) {
dropboxLongDescDiv.createEl("p", {
text: c,
cls: "dropbox-disclaimer",
});
}
dropboxLongDescDiv.createEl("p", {
text: t("settings_dropbox_folder", {
pluginID: this.plugin.manifest.id,
remoteBaseDir:
this.plugin.settings.dropbox.remoteBaseDir ||
this.app.vault.getName(),
}),
});
const dropboxSelectAuthDiv = dropboxDiv.createDiv();
const dropboxAuthDiv = dropboxSelectAuthDiv.createDiv({
cls: "dropbox-auth-button-hide settings-auth-related",
});
const dropboxRevokeAuthDiv = dropboxSelectAuthDiv.createDiv({
cls: "dropbox-revoke-auth-button-hide settings-auth-related",
});
const dropboxRevokeAuthSetting = new Setting(dropboxRevokeAuthDiv)
.setName(t("settings_dropbox_revoke"))
.setDesc(
t("settings_dropbox_revoke_desc", {
username: this.plugin.settings.dropbox.username,
})
)
.addButton(async (button) => {
button.setButtonText(t("settings_dropbox_revoke_button"));
button.onClick(async () => {
try {
const self = this;
const client = new RemoteClient(
"dropbox",
undefined,
undefined,
this.plugin.settings.dropbox,
undefined,
this.app.vault.getName(),
() => self.plugin.saveSettings()
);
await client.revokeAuth();
this.plugin.settings.dropbox = JSON.parse(
JSON.stringify(DEFAULT_DROPBOX_CONFIG)
);
await this.plugin.saveSettings();
dropboxAuthDiv.toggleClass(
"dropbox-auth-button-hide",
this.plugin.settings.dropbox.username !== ""
);
dropboxRevokeAuthDiv.toggleClass(
"dropbox-revoke-auth-button-hide",
this.plugin.settings.dropbox.username === ""
);
new Notice(t("settings_dropbox_revoke_notice"));
} catch (err) {
console.error(err);
new Notice(t("settings_dropbox_revoke_noticeerr"));
}
});
});
new Setting(dropboxRevokeAuthDiv)
.setName(t("settings_dropbox_clearlocal"))
.setDesc(t("settings_dropbox_clearlocal_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_dropbox_clearlocal_button"));
button.onClick(async () => {
this.plugin.settings.dropbox = JSON.parse(
JSON.stringify(DEFAULT_DROPBOX_CONFIG)
);
await this.plugin.saveSettings();
dropboxAuthDiv.toggleClass(
"dropbox-auth-button-hide",
this.plugin.settings.dropbox.username !== ""
);
dropboxRevokeAuthDiv.toggleClass(
"dropbox-revoke-auth-button-hide",
this.plugin.settings.dropbox.username === ""
);
new Notice(t("settings_dropbox_clearlocal_notice"));
});
});
new Setting(dropboxAuthDiv)
.setName(t("settings_dropbox_auth"))
.setDesc(t("settings_dropbox_auth_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_dropbox_auth_button"));
button.onClick(async () => {
const modal = new DropboxAuthModal(
this.app,
this.plugin,
dropboxAuthDiv,
dropboxRevokeAuthDiv,
dropboxRevokeAuthSetting
);
this.plugin.oauth2Info.helperModal = modal;
this.plugin.oauth2Info.authDiv = dropboxAuthDiv;
this.plugin.oauth2Info.revokeDiv = dropboxRevokeAuthDiv;
this.plugin.oauth2Info.revokeAuthSetting = dropboxRevokeAuthSetting;
modal.open();
});
});
dropboxAuthDiv.toggleClass(
"dropbox-auth-button-hide",
this.plugin.settings.dropbox.username !== ""
);
dropboxRevokeAuthDiv.toggleClass(
"dropbox-revoke-auth-button-hide",
this.plugin.settings.dropbox.username === ""
);
let newDropboxRemoteBaseDir =
this.plugin.settings.dropbox.remoteBaseDir || "";
new Setting(dropboxDiv)
.setName(t("settings_remotebasedir"))
.setDesc(t("settings_remotebasedir_desc"))
.addText((text) =>
text
.setPlaceholder(this.app.vault.getName())
.setValue(newDropboxRemoteBaseDir)
.onChange((value) => {
newDropboxRemoteBaseDir = value.trim();
})
)
.addButton((button) => {
button.setButtonText(t("confirm"));
button.onClick(() => {
new ChangeRemoteBaseDirModal(
this.app,
this.plugin,
newDropboxRemoteBaseDir,
"dropbox"
).open();
});
});
new Setting(dropboxDiv)
.setName(t("settings_checkonnectivity"))
.setDesc(t("settings_checkonnectivity_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_checkonnectivity_button"));
button.onClick(async () => {
new Notice(t("settings_checkonnectivity_checking"));
const self = this;
const client = new RemoteClient(
"dropbox",
undefined,
undefined,
this.plugin.settings.dropbox,
undefined,
this.app.vault.getName(),
() => self.plugin.saveSettings()
);
const errors = { msg: "" };
const res = await client.checkConnectivity((err: any) => {
errors.msg = `${err}`;
});
if (res) {
new Notice(t("settings_dropbox_connect_succ"));
} else {
new Notice(t("settings_dropbox_connect_fail"));
new Notice(errors.msg);
}
});
});
//////////////////////////////////////////////////
// below for onedrive
//////////////////////////////////////////////////
const onedriveDiv = containerEl.createEl("div", { cls: "onedrive-hide" });
onedriveDiv.toggleClass(
"onedrive-hide",
this.plugin.settings.serviceType !== "onedrive"
);
onedriveDiv.createEl("h2", { text: t("settings_onedrive") });
const onedriveLongDescDiv = onedriveDiv.createEl("div", {
cls: "settings-long-desc",
});
for (const c of [
t("settings_onedrive_disclaimer1"),
t("settings_onedrive_disclaimer2"),
]) {
onedriveLongDescDiv.createEl("p", {
text: c,
cls: "onedrive-disclaimer",
});
}
onedriveLongDescDiv.createEl("p", {
text: t("settings_onedrive_folder", {
pluginID: this.plugin.manifest.id,
remoteBaseDir:
this.plugin.settings.onedrive.remoteBaseDir ||
this.app.vault.getName(),
}),
});
onedriveLongDescDiv.createEl("p", {
text: t("settings_onedrive_nobiz"),
});
const onedriveSelectAuthDiv = onedriveDiv.createDiv();
const onedriveAuthDiv = onedriveSelectAuthDiv.createDiv({
cls: "onedrive-auth-button-hide settings-auth-related",
});
const onedriveRevokeAuthDiv = onedriveSelectAuthDiv.createDiv({
cls: "onedrive-revoke-auth-button-hide settings-auth-related",
});
const onedriveRevokeAuthSetting = new Setting(onedriveRevokeAuthDiv)
.setName(t("settings_onedrive_revoke"))
.setDesc(
t("settings_onedrive_revoke_desc", {
username: this.plugin.settings.onedrive.username,
})
)
.addButton(async (button) => {
button.setButtonText(t("settings_onedrive_revoke_button"));
button.onClick(async () => {
new OnedriveRevokeAuthModal(
this.app,
this.plugin,
onedriveAuthDiv,
onedriveRevokeAuthDiv
).open();
});
});
new Setting(onedriveAuthDiv)
.setName(t("settings_onedrive_auth"))
.setDesc(t("settings_onedrive_auth_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_onedrive_auth_button"));
button.onClick(async () => {
const modal = new OnedriveAuthModal(
this.app,
this.plugin,
onedriveAuthDiv,
onedriveRevokeAuthDiv,
onedriveRevokeAuthSetting
);
this.plugin.oauth2Info.helperModal = modal;
this.plugin.oauth2Info.authDiv = onedriveAuthDiv;
this.plugin.oauth2Info.revokeDiv = onedriveRevokeAuthDiv;
this.plugin.oauth2Info.revokeAuthSetting = onedriveRevokeAuthSetting;
modal.open();
});
});
onedriveAuthDiv.toggleClass(
"onedrive-auth-button-hide",
this.plugin.settings.onedrive.username !== ""
);
onedriveRevokeAuthDiv.toggleClass(
"onedrive-revoke-auth-button-hide",
this.plugin.settings.onedrive.username === ""
);
let newOnedriveRemoteBaseDir =
this.plugin.settings.onedrive.remoteBaseDir || "";
new Setting(onedriveDiv)
.setName(t("settings_remotebasedir"))
.setDesc(t("settings_remotebasedir_desc"))
.addText((text) =>
text
.setPlaceholder(this.app.vault.getName())
.setValue(newOnedriveRemoteBaseDir)
.onChange((value) => {
newOnedriveRemoteBaseDir = value.trim();
})
)
.addButton((button) => {
button.setButtonText(t("confirm"));
button.onClick(() => {
new ChangeRemoteBaseDirModal(
this.app,
this.plugin,
newOnedriveRemoteBaseDir,
"onedrive"
).open();
});
});
new Setting(onedriveDiv)
.setName(t("settings_checkonnectivity"))
.setDesc(t("settings_checkonnectivity_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_checkonnectivity_button"));
button.onClick(async () => {
new Notice(t("settings_checkonnectivity_checking"));
const self = this;
const client = new RemoteClient(
"onedrive",
undefined,
undefined,
undefined,
this.plugin.settings.onedrive,
this.app.vault.getName(),
() => self.plugin.saveSettings()
);
const errors = { msg: "" };
const res = await client.checkConnectivity((err: any) => {
errors.msg = `${err}`;
});
if (res) {
new Notice(t("settings_onedrive_connect_succ"));
} else {
new Notice(t("settings_onedrive_connect_fail"));
new Notice(errors.msg);
}
});
});
//////////////////////////////////////////////////
// below for webdav
//////////////////////////////////////////////////
const webdavDiv = containerEl.createEl("div", { cls: "webdav-hide" });
webdavDiv.toggleClass(
"webdav-hide",
this.plugin.settings.serviceType !== "webdav"
);
webdavDiv.createEl("h2", { text: t("settings_webdav") });
const webdavLongDescDiv = webdavDiv.createEl("div", {
cls: "settings-long-desc",
});
webdavLongDescDiv.createEl("p", {
text: t("settings_webdav_disclaimer1"),
cls: "webdav-disclaimer",
});
if (!VALID_REQURL) {
webdavLongDescDiv.createEl("p", {
text: t("settings_webdav_cors_os"),
});
webdavLongDescDiv.createEl("p", {
text: t("settings_webdav_cors"),
});
}
webdavLongDescDiv.createEl("p", {
text: t("settings_webdav_folder", {
remoteBaseDir:
this.plugin.settings.webdav.remoteBaseDir || this.app.vault.getName(),
}),
});
new Setting(webdavDiv)
.setName(t("settings_webdav_addr"))
.setDesc(t("settings_webdav_addr_desc"))
.addText((text) =>
text
.setPlaceholder("")
.setValue(this.plugin.settings.webdav.address)
.onChange(async (value) => {
this.plugin.settings.webdav.address = value.trim();
if (
this.plugin.settings.webdav.depth === "auto_1" ||
this.plugin.settings.webdav.depth === "auto_infinity"
) {
this.plugin.settings.webdav.depth = "auto_unknown";
}
// TODO: any more elegant way?
applyWebdavPresetRulesInplace(this.plugin.settings.webdav);
// normally saved
await this.plugin.saveSettings();
})
);
new Setting(webdavDiv)
.setName(t("settings_webdav_user"))
.setDesc(t("settings_webdav_user_desc"))
.addText((text) => {
wrapTextWithPasswordHide(text);
text
.setPlaceholder("")
.setValue(this.plugin.settings.webdav.username)
.onChange(async (value) => {
this.plugin.settings.webdav.username = value.trim();
if (
this.plugin.settings.webdav.depth === "auto_1" ||
this.plugin.settings.webdav.depth === "auto_infinity"
) {
this.plugin.settings.webdav.depth = "auto_unknown";
}
await this.plugin.saveSettings();
});
});
new Setting(webdavDiv)
.setName(t("settings_webdav_password"))
.setDesc(t("settings_webdav_password_desc"))
.addText((text) => {
wrapTextWithPasswordHide(text);
text
.setPlaceholder("")
.setValue(this.plugin.settings.webdav.password)
.onChange(async (value) => {
this.plugin.settings.webdav.password = value.trim();
if (
this.plugin.settings.webdav.depth === "auto_1" ||
this.plugin.settings.webdav.depth === "auto_infinity"
) {
this.plugin.settings.webdav.depth = "auto_unknown";
}
await this.plugin.saveSettings();
});
});
new Setting(webdavDiv)
.setName(t("settings_webdav_auth"))
.setDesc(t("settings_webdav_auth_desc"))
.addDropdown(async (dropdown) => {
dropdown.addOption("basic", "basic");
if (VALID_REQURL) {
dropdown.addOption("digest", "digest");
}
// new version config, copied to old version, we need to reset it
if (!VALID_REQURL && this.plugin.settings.webdav.authType !== "basic") {
this.plugin.settings.webdav.authType = "basic";
await this.plugin.saveSettings();
}
dropdown
.setValue(this.plugin.settings.webdav.authType)
.onChange(async (val: WebdavAuthType) => {
this.plugin.settings.webdav.authType = val;
await this.plugin.saveSettings();
});
});
new Setting(webdavDiv)
.setName(t("settings_webdav_depth"))
.setDesc(t("settings_webdav_depth_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("auto", t("settings_webdav_depth_auto"));
dropdown.addOption("manual_1", t("settings_webdav_depth_1"));
dropdown.addOption("manual_infinity", t("settings_webdav_depth_inf"));
let initVal = "auto";
const autoOptions: Set<WebdavDepthType> = new Set([
"auto_unknown",
"auto_1",
"auto_infinity",
]);
if (autoOptions.has(this.plugin.settings.webdav.depth)) {
initVal = "auto";
} else {
initVal = this.plugin.settings.webdav.depth || "auto";
}
type DepthOption = "auto" | "manual_1" | "manual_infinity";
dropdown.setValue(initVal).onChange(async (val: DepthOption) => {
if (val === "auto") {
this.plugin.settings.webdav.depth = "auto_unknown";
this.plugin.settings.webdav.manualRecursive = false;
} else if (val === "manual_1") {
this.plugin.settings.webdav.depth = "manual_1";
this.plugin.settings.webdav.manualRecursive = true;
} else if (val === "manual_infinity") {
this.plugin.settings.webdav.depth = "manual_infinity";
this.plugin.settings.webdav.manualRecursive = false;
}
// TODO: any more elegant way?
applyWebdavPresetRulesInplace(this.plugin.settings.webdav);
// normally save
await this.plugin.saveSettings();
});
});
let newWebdavRemoteBaseDir =
this.plugin.settings.webdav.remoteBaseDir || "";
new Setting(webdavDiv)
.setName(t("settings_remotebasedir"))
.setDesc(t("settings_remotebasedir_desc"))
.addText((text) =>
text
.setPlaceholder(this.app.vault.getName())
.setValue(newWebdavRemoteBaseDir)
.onChange((value) => {
newWebdavRemoteBaseDir = value.trim();
})
)
.addButton((button) => {
button.setButtonText(t("confirm"));
button.onClick(() => {
new ChangeRemoteBaseDirModal(
this.app,
this.plugin,
newWebdavRemoteBaseDir,
"webdav"
).open();
});
});
new Setting(webdavDiv)
.setName(t("settings_checkonnectivity"))
.setDesc(t("settings_checkonnectivity_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_checkonnectivity_button"));
button.onClick(async () => {
new Notice(t("settings_checkonnectivity_checking"));
const self = this;
const client = new RemoteClient(
"webdav",
undefined,
this.plugin.settings.webdav,
undefined,
undefined,
this.app.vault.getName(),
() => self.plugin.saveSettings()
);
const errors = { msg: "" };
const res = await client.checkConnectivity((err: any) => {
errors.msg = `${err}`;
});
if (res) {
new Notice(t("settings_webdav_connect_succ"));
} else {
if (VALID_REQURL) {
new Notice(t("settings_webdav_connect_fail"));
} else {
new Notice(t("settings_webdav_connect_fail_withcors"));
}
new Notice(errors.msg);
}
});
});
//////////////////////////////////////////////////
// below for general chooser (part 2/2)
//////////////////////////////////////////////////
// we need to create chooser
// after all service-div-s being created
new Setting(serviceChooserDiv)
.setName(t("settings_chooseservice"))
.setDesc(t("settings_chooseservice_desc"))
.addDropdown(async (dropdown) => {
dropdown.addOption("s3", t("settings_chooseservice_s3"));
dropdown.addOption("dropbox", t("settings_chooseservice_dropbox"));
dropdown.addOption("webdav", t("settings_chooseservice_webdav"));
dropdown.addOption("onedrive", t("settings_chooseservice_onedrive"));
dropdown
.setValue(this.plugin.settings.serviceType)
.onChange(async (val: SUPPORTED_SERVICES_TYPE) => {
this.plugin.settings.serviceType = val;
s3Div.toggleClass(
"s3-hide",
this.plugin.settings.serviceType !== "s3"
);
dropboxDiv.toggleClass(
"dropbox-hide",
this.plugin.settings.serviceType !== "dropbox"
);
onedriveDiv.toggleClass(
"onedrive-hide",
this.plugin.settings.serviceType !== "onedrive"
);
webdavDiv.toggleClass(
"webdav-hide",
this.plugin.settings.serviceType !== "webdav"
);
await this.plugin.saveSettings();
});
});
//////////////////////////////////////////////////
// below for basic settings
//////////////////////////////////////////////////
const basicDiv = containerEl.createEl("div");
basicDiv.createEl("h2", { text: t("settings_basic") });
let newPassword = `${this.plugin.settings.password}`;
new Setting(basicDiv)
.setName(t("settings_password"))
.setDesc(t("settings_password_desc"))
.addText((text) => {
wrapTextWithPasswordHide(text);
text
.setPlaceholder("")
.setValue(`${this.plugin.settings.password}`)
.onChange(async (value) => {
newPassword = value.trim();
});
})
.addButton(async (button) => {
button.setButtonText(t("confirm"));
button.onClick(async () => {
new PasswordModal(this.app, this.plugin, newPassword).open();
});
});
new Setting(basicDiv)
.setName(t("settings_autorun"))
.setDesc(t("settings_autorun_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("-1", t("settings_autorun_notset"));
dropdown.addOption(`${1000 * 60 * 1}`, t("settings_autorun_1min"));
dropdown.addOption(`${1000 * 60 * 5}`, t("settings_autorun_5min"));
dropdown.addOption(`${1000 * 60 * 10}`, t("settings_autorun_10min"));
dropdown.addOption(`${1000 * 60 * 30}`, t("settings_autorun_30min"));
dropdown
.setValue(`${this.plugin.settings.autoRunEveryMilliseconds}`)
.onChange(async (val: string) => {
const realVal = parseInt(val);
this.plugin.settings.autoRunEveryMilliseconds = realVal;
await this.plugin.saveSettings();
if (
(realVal === undefined || realVal === null || realVal <= 0) &&
this.plugin.autoRunIntervalID !== undefined
) {
// clear
window.clearInterval(this.plugin.autoRunIntervalID);
this.plugin.autoRunIntervalID = undefined;
} else if (
realVal !== undefined &&
realVal !== null &&
realVal > 0
) {
const intervalID = window.setInterval(() => {
this.plugin.syncRun("auto");
}, realVal);
this.plugin.autoRunIntervalID = intervalID;
this.plugin.registerInterval(intervalID);
}
});
});
new Setting(basicDiv)
.setName(t("settings_runoncestartup"))
.setDesc(t("settings_runoncestartup_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("-1", t("settings_runoncestartup_notset"));
dropdown.addOption(
`${1000 * 1 * 1}`,
t("settings_runoncestartup_1sec")
);
dropdown.addOption(
`${1000 * 10 * 1}`,
t("settings_runoncestartup_10sec")
);
dropdown.addOption(
`${1000 * 30 * 1}`,
t("settings_runoncestartup_30sec")
);
dropdown
.setValue(`${this.plugin.settings.initRunAfterMilliseconds}`)
.onChange(async (val: string) => {
const realVal = parseInt(val);
this.plugin.settings.initRunAfterMilliseconds = realVal;
await this.plugin.saveSettings();
});
});
new Setting(basicDiv)
.setName(t("settings_skiplargefiles"))
.setDesc(t("settings_skiplargefiles_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("-1", t("settings_skiplargefiles_notset"));
const mbs = [1, 5, 10, 50, 100, 500, 1000];
for (const mb of mbs) {
dropdown.addOption(`${mb * 1000 * 1000}`, `${mb} MB`);
}
dropdown
.setValue(`${this.plugin.settings.skipSizeLargerThan}`)
.onChange(async (val) => {
this.plugin.settings.skipSizeLargerThan = parseInt(val);
await this.plugin.saveSettings();
});
});
//////////////////////////////////////////////////
// below for advanced settings
//////////////////////////////////////////////////
const advDiv = containerEl.createEl("div");
advDiv.createEl("h2", {
text: t("settings_adv"),
});
new Setting(advDiv)
.setName(t("settings_concurrency"))
.setDesc(t("settings_concurrency_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("1", "1");
dropdown.addOption("2", "2");
dropdown.addOption("3", "3");
dropdown.addOption("5", "5 (default)");
dropdown.addOption("10", "10");
dropdown.addOption("15", "15");
dropdown.addOption("20", "20");
dropdown
.setValue(`${this.plugin.settings.concurrency}`)
.onChange(async (val) => {
const realVal = parseInt(val);
this.plugin.settings.concurrency = realVal;
await this.plugin.saveSettings();
});
});
new Setting(advDiv)
.setName(t("settings_syncunderscore"))
.setDesc(t("settings_syncunderscore_desc"))
.addDropdown((dropdown) => {
dropdown.addOption("disable", t("disable"));
dropdown.addOption("enable", t("enable"));
dropdown
.setValue(
`${this.plugin.settings.syncUnderscoreItems ? "enable" : "disable"}`
)
.onChange(async (val) => {
this.plugin.settings.syncUnderscoreItems = val === "enable";
await this.plugin.saveSettings();
});
});
new Setting(advDiv)
.setName(t("settings_configdir"))
.setDesc(
t("settings_configdir_desc", {
configDir: this.app.vault.configDir,
})
)
.addDropdown((dropdown) => {
dropdown.addOption("disable", t("disable"));
dropdown.addOption("enable", t("enable"));
const bridge = {
secondConfirm: false,
};
dropdown
.setValue(
`${this.plugin.settings.syncConfigDir ? "enable" : "disable"}`
)
.onChange(async (val) => {
if (val === "enable" && !bridge.secondConfirm) {
dropdown.setValue("disable");
new SyncConfigDirModal(this.app, this.plugin, () => {
bridge.secondConfirm = true;
dropdown.setValue("enable");
}).open();
} else {
bridge.secondConfirm = false;
this.plugin.settings.syncConfigDir = false;
await this.plugin.saveSettings();
}
});
});
//////////////////////////////////////////////////
// below for import and export functions
//////////////////////////////////////////////////
// import and export
const importExportDiv = containerEl.createEl("div");
importExportDiv.createEl("h2", {
text: t("settings_importexport"),
});
new Setting(importExportDiv)
.setName(t("settings_export"))
.setDesc(t("settings_export_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_export_desc_button"));
button.onClick(async () => {
new ExportSettingsQrCodeModal(this.app, this.plugin).open();
});
});
new Setting(importExportDiv)
.setName(t("settings_import"))
.setDesc(t("settings_import_desc"));
//////////////////////////////////////////////////
// below for debug
//////////////////////////////////////////////////
const debugDiv = containerEl.createEl("div");
debugDiv.createEl("h2", { text: t("settings_debug") });
new Setting(debugDiv)
.setName(t("settings_debuglevel"))
.setDesc(t("settings_debuglevel_desc"))
.addDropdown(async (dropdown) => {
dropdown.addOption("info", "info");
dropdown.addOption("debug", "debug");
dropdown
.setValue(this.plugin.settings.currLogLevel)
.onChange(async (val: string) => {
this.plugin.settings.currLogLevel = val;
log.setLevel(val as any);
await this.plugin.saveSettings();
log.info(`the log level is changed to ${val}`);
});
});
new Setting(debugDiv)
.setName(t("settings_outputsettingsconsole"))
.setDesc(t("settings_outputsettingsconsole_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_outputsettingsconsole_button"));
button.onClick(async () => {
const c = messyConfigToNormal(await this.plugin.loadData());
log.info(c);
new Notice(t("settings_outputsettingsconsole_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_syncplans"))
.setDesc(t("settings_syncplans_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_syncplans_button_json"));
button.onClick(async () => {
await exportVaultSyncPlansToFiles(
this.plugin.db,
this.app.vault,
this.plugin.vaultRandomID,
"json"
);
new Notice(t("settings_syncplans_notice"));
});
})
.addButton(async (button) => {
button.setButtonText(t("settings_syncplans_button_table"));
button.onClick(async () => {
await exportVaultSyncPlansToFiles(
this.plugin.db,
this.app.vault,
this.plugin.vaultRandomID,
"table"
);
new Notice(t("settings_syncplans_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_delsyncplans"))
.setDesc(t("settings_delsyncplans_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_delsyncplans_button"));
button.onClick(async () => {
await clearAllSyncPlanRecords(this.plugin.db);
new Notice(t("settings_delsyncplans_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_logtodb"))
.setDesc(t("settings_logtodb_desc"))
.addDropdown(async (dropdown) => {
dropdown.addOption("enable", t("enable"));
dropdown.addOption("disable", t("disable"));
dropdown
.setValue(this.plugin.settings.logToDB ? "enable" : "disable")
.onChange(async (val: string) => {
const logToDB = val === "enable";
if (logToDB) {
applyLogWriterInplace((...msg: any[]) => {
insertLoggerOutputByVault(
this.plugin.db,
this.plugin.vaultRandomID,
...msg
);
});
} else {
restoreLogWritterInplace();
}
clearExpiredLoggerOutputRecords(this.plugin.db);
this.plugin.settings.logToDB = logToDB;
await this.plugin.saveSettings();
});
});
new Setting(debugDiv)
.setName(t("settings_logtodbexport"))
.setDesc(
t("settings_logtodbexport_desc", {
debugFolder: DEFAULT_DEBUG_FOLDER,
})
)
.addButton(async (button) => {
button.setButtonText(t("settings_logtodbexport_button"));
button.onClick(async () => {
await exportVaultLoggerOutputToFiles(
this.plugin.db,
this.app.vault,
this.plugin.vaultRandomID
);
new Notice(t("settings_logtodbexport_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_logtodbclear"))
.setDesc(t("settings_logtodbclear_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_logtodbclear_button"));
button.onClick(async () => {
await clearAllLoggerOutputRecords(this.plugin.db);
new Notice(t("settings_logtodbclear_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_delsyncmap"))
.setDesc(t("settings_delsyncmap_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_delsyncmap_button"));
button.onClick(async () => {
await clearAllSyncMetaMapping(this.plugin.db);
new Notice(t("settings_delsyncmap_notice"));
});
});
new Setting(debugDiv)
.setName(t("settings_outputbasepathvaultid"))
.setDesc(t("settings_outputbasepathvaultid_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_outputbasepathvaultid_button"));
button.onClick(async () => {
new Notice(this.plugin.getVaultBasePath());
new Notice(this.plugin.vaultRandomID);
});
});
new Setting(debugDiv)
.setName(t("settings_resetcache"))
.setDesc(t("settings_resetcache_desc"))
.addButton(async (button) => {
button.setButtonText(t("settings_resetcache_button"));
button.onClick(async () => {
await destroyDBs();
new Notice(t("settings_resetcache_notice"));
});
});
}
hide() {
let { containerEl } = this;
containerEl.empty();
super.hide();
}
}
Example #25
Source File: main.ts From obsidian-readwise with GNU General Public License v3.0 | 4 votes |
class ReadwiseSettingTab extends PluginSettingTab {
plugin: ReadwisePlugin;
constructor(app: App, plugin: ReadwisePlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let {containerEl} = this;
containerEl.empty();
containerEl.createEl('h1', {text: 'Readwise Official'});
containerEl.createEl('p', {text: 'Created by '}).createEl('a', {text: 'Readwise', href: 'https://readwise.io'});
containerEl.getElementsByTagName('p')[0].appendText(' ?');
containerEl.createEl('h2', {text: 'Settings'});
if (this.plugin.settings.token) {
new Setting(containerEl)
.setName("Sync your Readwise data with Obsidian")
.setDesc("On first sync, the Readwise plugin will create a new folder containing all your highlights")
.setClass('rw-setting-sync')
.addButton((button) => {
button.setCta().setTooltip("Once the sync begins, you can close this plugin page")
.setButtonText('Initiate Sync')
.onClick(async () => {
if (this.plugin.settings.isSyncing) {
// NOTE: This is used to prevent multiple syncs at the same time. However, if a previous sync fails,
// it can stop new syncs from happening. Make sure to set isSyncing to false
// if there's ever errors/failures in previous sync attempts, so that
// we don't block syncing subsequent times.
new Notice("Readwise sync already in progress");
} else {
this.plugin.clearInfoStatus(containerEl);
this.plugin.settings.isSyncing = true;
await this.plugin.saveData(this.plugin.settings);
button.setButtonText("Syncing...");
await this.plugin.requestArchive(button);
}
});
});
let el = containerEl.createEl("div", {cls: "rw-info-container"});
containerEl.find(".rw-setting-sync > .setting-item-control ").prepend(el);
new Setting(containerEl)
.setName("Customize formatting options")
.setDesc("You can customize which items export to Obsidian and how they appear from the Readwise website")
.addButton((button) => {
button.setButtonText("Customize").onClick(() => {
window.open(`${baseURL}/export/obsidian/preferences`);
});
});
new Setting(containerEl)
.setName('Customize base folder')
.setDesc("By default, the plugin will save all your highlights into a folder named Readwise")
// TODO: change this to search filed when the API is exposed (https://github.com/obsidianmd/obsidian-api/issues/22)
.addText(text => text
.setPlaceholder('Defaults to: Readwise')
.setValue(this.plugin.settings.readwiseDir)
.onChange(async (value) => {
this.plugin.settings.readwiseDir = normalizePath(value || "Readwise");
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Configure resync frequency')
.setDesc("If not set to Manual, Readwise will automatically resync with Obsidian when the app is open at the specified interval")
.addDropdown(dropdown => {
dropdown.addOption("0", "Manual");
dropdown.addOption("60", "Every 1 hour");
dropdown.addOption((12 * 60).toString(), "Every 12 hours");
dropdown.addOption((24 * 60).toString(), "Every 24 hours");
// select the currently-saved option
dropdown.setValue(this.plugin.settings.frequency);
dropdown.onChange((newValue) => {
// update the plugin settings
this.plugin.settings.frequency = newValue;
this.plugin.saveSettings();
// destroy & re-create the scheduled task
this.plugin.configureSchedule();
});
});
new Setting(containerEl)
.setName("Sync automatically when Obsidian opens")
.setDesc("If enabled, Readwise will automatically resync with Obsidian each time you open the app")
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.triggerOnLoad);
toggle.onChange((val) => {
this.plugin.settings.triggerOnLoad = val;
this.plugin.saveSettings();
});
}
);
new Setting(containerEl)
.setName("Resync deleted files")
.setDesc("If enabled, you can refresh individual items by deleting the file in Obsidian and initiating a resync")
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.refreshBooks);
toggle.onChange(async (val) => {
this.plugin.settings.refreshBooks = val;
await this.plugin.saveSettings();
if (val) {
this.plugin.refreshBookExport();
}
});
}
);
if (this.plugin.settings.lastSyncFailed) {
this.plugin.showInfoStatus(containerEl.find(".rw-setting-sync .rw-info-container").parentElement, "Last sync failed", "rw-error");
}
}
if (!this.plugin.settings.token) {
new Setting(containerEl)
.setName("Connect Obsidian to Readwise")
.setClass("rw-setting-connect")
.setDesc("The Readwise plugin enables automatic syncing of all your highlights from Kindle, Instapaper, Pocket, and more. Note: Requires Readwise account.")
.addButton((button) => {
button.setButtonText("Connect").setCta().onClick(async (evt) => {
const success = await this.plugin.getUserAuthToken(evt.target as HTMLElement);
if (success) {
this.display();
}
});
});
let el = containerEl.createEl("div", {cls: "rw-info-container"});
containerEl.find(".rw-setting-connect > .setting-item-control ").prepend(el);
}
const help = containerEl.createEl('p',);
help.innerHTML = "Question? Please see our <a href='https://help.readwise.io/article/125-how-does-the-readwise-to-obsidian-export-integration-work'>Documentation</a> or email us at <a href='mailto:[email protected]'>[email protected]</a> ?";
}
}
Example #26
Source File: switcherPlusSettingTab.ts From obsidian-switcher-plus with GNU General Public License v3.0 | 4 votes |
export class SwitcherPlusSettingTab extends PluginSettingTab {
constructor(
app: App,
plugin: SwitcherPlusPlugin,
private config: SwitcherPlusSettings,
) {
super(app, plugin);
}
display(): void {
const { containerEl, config } = this;
const generalSection = new GeneralSettingsTabSection(this.app, this, config);
const editorSection = new EditorSettingsTabSection(this.app, this, config);
const starredSection = new StarredSettingsTabSection(this.app, this, config);
const commandListSection = new CommandListSettingsTabSection(this.app, this, config);
const workspaceListSection = new WorkspaceSettingsTabSection(this.app, this, config);
const relatedItemsSection = new RelatedItemsSettingsTabSection(
this.app,
this,
config,
);
containerEl.empty();
containerEl.createEl('h2', { text: 'Quick Switcher++ Settings' });
generalSection.display(containerEl);
this.setSymbolModeSettingsGroup(containerEl, config);
this.setHeadingsModeSettingsGroup(containerEl, config);
editorSection.display(containerEl);
relatedItemsSection.display(containerEl);
starredSection.display(containerEl);
commandListSection.display(containerEl);
workspaceListSection.display(containerEl);
}
private setSymbolModeSettingsGroup(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl).setHeading().setName('Symbol List Mode Settings');
SwitcherPlusSettingTab.setSymbolListCommand(containerEl, config);
SwitcherPlusSettingTab.setSymbolsInLineOrder(containerEl, config);
SwitcherPlusSettingTab.setAlwaysNewPaneForSymbols(containerEl, config);
SwitcherPlusSettingTab.setUseActivePaneForSymbolsOnMobile(containerEl, config);
SwitcherPlusSettingTab.setSelectNearestHeading(containerEl, config);
this.setEnabledSymbolTypes(containerEl, config);
}
private setHeadingsModeSettingsGroup(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl).setHeading().setName('Headings List Mode Settings');
SwitcherPlusSettingTab.setHeadingsListCommand(containerEl, config);
SwitcherPlusSettingTab.setStrictHeadingsOnly(containerEl, config);
SwitcherPlusSettingTab.setSearchAllHeadings(containerEl, config);
this.setExcludeFolders(containerEl, config);
}
private static setAlwaysNewPaneForSymbols(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Open Symbols in new pane')
.setDesc(
'Enabled, always open a new pane when navigating to Symbols. Disabled, navigate in an already open pane (if one exists)',
)
.addToggle((toggle) =>
toggle.setValue(config.alwaysNewPaneForSymbols).onChange((value) => {
config.alwaysNewPaneForSymbols = value;
config.save();
}),
);
}
private static setUseActivePaneForSymbolsOnMobile(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Open Symbols in active pane on mobile devices')
.setDesc(
'Enabled, navigate to the target file and symbol in the active editor pane. Disabled, open a new pane when navigating to Symbols, even on mobile devices.',
)
.addToggle((toggle) =>
toggle.setValue(config.useActivePaneForSymbolsOnMobile).onChange((value) => {
config.useActivePaneForSymbolsOnMobile = value;
config.save();
}),
);
}
private static setSelectNearestHeading(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Auto-select nearest heading')
.setDesc(
'Enabled, in an unfiltered symbol list, select the closest preceding Heading to the current cursor position. Disabled, the first symbol in the list is selected.',
)
.addToggle((toggle) =>
toggle.setValue(config.selectNearestHeading).onChange((value) => {
config.selectNearestHeading = value;
config.save();
}),
);
}
private static setSymbolsInLineOrder(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('List symbols as indented outline')
.setDesc(
'Enabled, symbols will be displayed in the (line) order they appear in the source text, indented under any preceding heading. Disabled, symbols will be grouped by type: Headings, Tags, Links, Embeds.',
)
.addToggle((toggle) =>
toggle.setValue(config.symbolsInLineOrder).onChange((value) => {
config.symbolsInLineOrder = value;
config.save();
}),
);
}
private setEnabledSymbolTypes(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl).setName('Show Headings').addToggle((toggle) =>
toggle
.setValue(config.isSymbolTypeEnabled(SymbolType.Heading))
.onChange((value) => {
config.setSymbolTypeEnabled(SymbolType.Heading, value);
config.save();
}),
);
new Setting(containerEl).setName('Show Tags').addToggle((toggle) =>
toggle.setValue(config.isSymbolTypeEnabled(SymbolType.Tag)).onChange((value) => {
config.setSymbolTypeEnabled(SymbolType.Tag, value);
config.save();
}),
);
new Setting(containerEl).setName('Show Embeds').addToggle((toggle) =>
toggle.setValue(config.isSymbolTypeEnabled(SymbolType.Embed)).onChange((value) => {
config.setSymbolTypeEnabled(SymbolType.Embed, value);
config.save();
}),
);
this.setEnableLinks(containerEl, config);
}
private setEnableLinks(containerEl: HTMLElement, config: SwitcherPlusSettings): void {
const isLinksEnabled = config.isSymbolTypeEnabled(SymbolType.Link);
new Setting(containerEl).setName('Show Links').addToggle((toggle) => {
toggle.setValue(isLinksEnabled).onChange(async (value) => {
config.setSymbolTypeEnabled(SymbolType.Link, value);
// have to await the save here because the call to display() will trigger a read
// of the updated data
await config.saveSettings();
// reload the settings panel. This will cause the sublink types toggle
// controls to be shown/hidden based on isLinksEnabled status
this.display();
});
});
if (isLinksEnabled) {
SwitcherPlusSettingTab.addSubLinkTypeToggle(
containerEl,
config,
LinkType.Heading,
'Links to headings',
);
SwitcherPlusSettingTab.addSubLinkTypeToggle(
containerEl,
config,
LinkType.Block,
'Links to blocks',
);
}
}
private static addSubLinkTypeToggle(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
linkType: LinkType,
name: string,
): void {
new Setting(containerEl)
.setClass('qsp-setting-item-indent')
.setName(name)
.addToggle((toggle) => {
const isExcluded = (config.excludeLinkSubTypes & linkType) === linkType;
toggle.setValue(!isExcluded).onChange((isEnabled) => {
let exclusions = config.excludeLinkSubTypes;
if (isEnabled) {
// remove from exclusion list
exclusions &= ~linkType;
} else {
// add to exclusion list
exclusions |= linkType;
}
config.excludeLinkSubTypes = exclusions;
config.save();
});
});
}
private static setSymbolListCommand(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Symbol list mode trigger')
.setDesc('Character that will trigger symbol list mode in the switcher')
.addText((text) =>
text
.setPlaceholder(config.symbolListPlaceholderText)
.setValue(config.symbolListCommand)
.onChange((value) => {
const val = value.length ? value : config.symbolListPlaceholderText;
config.symbolListCommand = val;
config.save();
}),
);
}
private static setHeadingsListCommand(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Headings list mode trigger')
.setDesc('Character that will trigger headings list mode in the switcher')
.addText((text) =>
text
.setPlaceholder(config.headingsListPlaceholderText)
.setValue(config.headingsListCommand)
.onChange((value) => {
const val = value.length ? value : config.headingsListPlaceholderText;
config.headingsListCommand = val;
config.save();
}),
);
}
private static setStrictHeadingsOnly(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Show headings only')
.setDesc(
'Enabled, only show suggestions where there is a match in the first H1 contained in the file. Disabled, if there is not a match in the first H1, fallback to showing suggestions where there is a filename or path match.',
)
.addToggle((toggle) =>
toggle.setValue(config.strictHeadingsOnly).onChange((value) => {
config.strictHeadingsOnly = value;
config.save();
}),
);
}
private static setSearchAllHeadings(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
new Setting(containerEl)
.setName('Search all headings')
.setDesc(
'Enabled, search through all headings contained in each file. Disabled, only search through the first H1 in each file.',
)
.addToggle((toggle) =>
toggle.setValue(config.searchAllHeadings).onChange((value) => {
config.searchAllHeadings = value;
config.save();
}),
);
}
private setExcludeFolders(
containerEl: HTMLElement,
config: SwitcherPlusSettings,
): void {
const settingName = 'Exclude folders';
new Setting(containerEl)
.setName(settingName)
.setDesc(
`When in Headings list mode, folder path that match any regex listed here will not be searched for suggestions. Path should start from the Vault Root. Add one path per line.`,
)
.addTextArea((textArea) => {
textArea.setValue(config.excludeFolders.join('\n'));
textArea.inputEl.addEventListener('blur', () => {
const excludes = textArea
.getValue()
.split('\n')
.filter((v) => v.length > 0);
if (this.validateExcludeFolderList(settingName, excludes)) {
config.excludeFolders = excludes;
config.save();
}
});
});
}
private validateExcludeFolderList(settingName: string, excludes: string[]) {
let isValid = true;
let failedMsg = '';
for (const str of excludes) {
try {
new RegExp(str);
} catch (err) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
failedMsg += `<span class="qsp-warning">${str}</span><br/>${err}<br/><br/>`;
isValid = false;
}
}
if (!isValid) {
const popup = new Modal(this.app);
popup.titleEl.setText(settingName);
popup.contentEl.innerHTML = `Changes not saved. The following regex contain errors:<br/><br/>${failedMsg}`;
popup.open();
}
return isValid;
}
}
Example #27
Source File: settings.ts From obsidian-pandoc with MIT License | 4 votes |
export default class PandocPluginSettingTab extends PluginSettingTab {
plugin: PandocPlugin;
errorMessages: { [key: string]: string } = {
pandoc: "Pandoc is not installed or accessible on your PATH. This plugin's functionality will be limited.",
latex: "LaTeX is not installed or accessible on your PATH. Please install it if you want PDF exports via LaTeX.",
}
constructor(app: App, plugin: PandocPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
containerEl.createEl('h3', {text: 'Pandoc Plugin'});
const createError = (text: string) =>
containerEl.createEl('p', { cls: 'pandoc-plugin-error', text });
for (const binary in this.plugin.features) {
const path = this.plugin.features[binary];
if (path === undefined) {
createError(this.errorMessages[binary]);
}
}
new Setting(containerEl)
.setName("Custom CSS file for HTML output")
.setDesc("This local CSS file will be read and injected into HTML exports. Use an absolute path or a path relative to the vault.")
.addText(text => text
.setPlaceholder('File name')
.setValue(this.plugin.settings.customCSSFile)
.onChange(async (value: string) => {
if (!value.length) this.plugin.settings.customCSSFile = null;
else this.plugin.settings.customCSSFile = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Inject app CSS (HTML output only)")
.setDesc("This applies app & plugin CSS to HTML exports, but the files become a little bigger.")
.addDropdown(dropdown => dropdown
.addOptions({
"current": "Current theme",
"none": "Neither theme",
"light": "Light theme",
"dark": "Dark theme",
})
.setValue(this.plugin.settings.injectAppCSS)
.onChange(async (value: string) => {
this.plugin.settings.injectAppCSS = value as 'current' | 'none' | 'light' | 'dark';
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Internal link processing")
.setDesc("This controls how [[wiki-links]] are formatted. Doesn't affect HTML output.")
.addDropdown(dropdown => dropdown
.addOptions({
"text": "Turn into text",
"link": "Leave as links",
"strip": "Remove links",
"unchanged": "Leave unchanged",
})
.setValue(this.plugin.settings.linkStrippingBehaviour)
.onChange(async (value: string) => {
this.plugin.settings.linkStrippingBehaviour = value as 'strip' | 'text' | 'link' | 'unchanged';
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Export files from HTML or markdown?")
.setDesc("Export from markdown, or from the HTML visible in Obsidian? HTML supports fancy plugin features, markdown supports Pandoc features like citations.")
.addDropdown(dropdown => dropdown
.addOptions({
"html": "HTML",
"md": "Markdown",
})
.setValue(this.plugin.settings.exportFrom)
.onChange(async (value: string) => {
this.plugin.settings.exportFrom = value as 'html' | 'md';
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Export folder")
.setDesc("Absolute path to an export folder, like 'C:\Users\Example\Documents' or '/home/user/zettelkasten'. If left blank, files are saved next to where they were exported from.")
.addText(text => text
.setPlaceholder('same as target')
.setValue(this.plugin.settings.outputFolder)
.onChange(async (value: string) => {
this.plugin.settings.outputFolder = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Show Pandoc command line interface commands")
.setDesc("Doesn't apply to HTML exports. Using the CLI will have slightly different results due to how this plugin works.")
.addToggle(toggle => toggle
.setValue(this.plugin.settings.showCLICommands)
.onChange(async (value: boolean) => {
this.plugin.settings.showCLICommands = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Pandoc path")
.setDesc("Optional override for Pandoc's path if you have command not found issues. On Mac/Linux use the output of 'which pandoc' in a terminal; on Windows use the output of 'Get-Command pandoc' in powershell.")
.addText(text => text
.setPlaceholder('pandoc')
.setValue(this.plugin.settings.pandoc)
.onChange(async (value: string) => {
this.plugin.settings.pandoc = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("PDFLaTeX path")
.setDesc("Optional override for pdflatex's path. Same as above but with 'which pdflatex'")
.addText(text => text
.setPlaceholder('pdflatex')
.setValue(this.plugin.settings.pdflatex)
.onChange(async (value: string) => {
this.plugin.settings.pdflatex = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName("Extra Pandoc arguments")
.setDesc("Add extra command line arguments so you can use templates or bibliographies. Newlines are turned into spaces")
.addTextArea(text => text
.setPlaceholder('Example: --bibliography "Zotero Exports\My Library.json" or --template letter')
.setValue(this.plugin.settings.extraArguments)
.onChange(async (value: string) => {
this.plugin.settings.extraArguments = value;
await this.plugin.saveSettings();
})
.inputEl.style.minHeight='150px');
}
}
Example #28
Source File: settings.ts From Obsidian_to_Anki with GNU General Public License v3.0 | 4 votes |
export class SettingsTab extends PluginSettingTab {
setup_custom_regexp(note_type: string, row_cells: HTMLCollection) {
const plugin = (this as any).plugin
let regexp_section = plugin.settings["CUSTOM_REGEXPS"]
let custom_regexp = new Setting(row_cells[1] as HTMLElement)
.addText(
text => text.setValue(
regexp_section.hasOwnProperty(note_type) ? regexp_section[note_type] : ""
)
.onChange((value) => {
plugin.settings["CUSTOM_REGEXPS"][note_type] = value
plugin.saveAllData()
})
)
custom_regexp.settingEl = row_cells[1] as HTMLElement
custom_regexp.infoEl.remove()
custom_regexp.controlEl.className += " anki-center"
}
setup_link_field(note_type: string, row_cells: HTMLCollection) {
const plugin = (this as any).plugin
let link_fields_section = plugin.settings.FILE_LINK_FIELDS
let link_field = new Setting(row_cells[2] as HTMLElement)
.addDropdown(
async dropdown => {
if (!(plugin.fields_dict[note_type])) {
plugin.fields_dict = await plugin.loadFieldsDict()
if (Object.keys(plugin.fields_dict).length != plugin.note_types.length) {
new Notice('Need to connect to Anki to generate fields dictionary...')
try {
plugin.fields_dict = await plugin.generateFieldsDict()
new Notice("Fields dictionary successfully generated!")
}
catch(e) {
new Notice("Couldn't connect to Anki! Check console for error message.")
return
}
}
}
const field_names = plugin.fields_dict[note_type]
for (let field of field_names) {
dropdown.addOption(field, field)
}
dropdown.setValue(
link_fields_section.hasOwnProperty(note_type) ? link_fields_section[note_type] : field_names[0]
)
dropdown.onChange((value) => {
plugin.settings.FILE_LINK_FIELDS[note_type] = value
plugin.saveAllData()
})
}
)
link_field.settingEl = row_cells[2] as HTMLElement
link_field.infoEl.remove()
link_field.controlEl.className += " anki-center"
}
setup_context_field(note_type: string, row_cells: HTMLCollection) {
const plugin = (this as any).plugin
let context_fields_section: Record<string, string> = plugin.settings.CONTEXT_FIELDS
let context_field = new Setting(row_cells[3] as HTMLElement)
.addDropdown(
async dropdown => {
const field_names = plugin.fields_dict[note_type]
for (let field of field_names) {
dropdown.addOption(field, field)
}
dropdown.setValue(
context_fields_section.hasOwnProperty(note_type) ? context_fields_section[note_type] : field_names[0]
)
dropdown.onChange((value) => {
plugin.settings.CONTEXT_FIELDS[note_type] = value
plugin.saveAllData()
})
}
)
context_field.settingEl = row_cells[3] as HTMLElement
context_field.infoEl.remove()
context_field.controlEl.className += " anki-center"
}
create_collapsible(name: string) {
let {containerEl} = this;
let div = containerEl.createEl('div', {cls: "collapsible-item"})
div.innerHTML = `
<div class="collapsible-item-self"><div class="collapsible-item-collapse collapse-icon anki-rotated"><svg viewBox="0 0 100 100" width="8" height="8" class="right-triangle"><path fill="currentColor" stroke="currentColor" d="M94.9,20.8c-1.4-2.5-4.1-4.1-7.1-4.1H12.2c-3,0-5.7,1.6-7.1,4.1c-1.3,2.4-1.2,5.2,0.2,7.6L43.1,88c1.5,2.3,4,3.7,6.9,3.7 s5.4-1.4,6.9-3.7l37.8-59.6C96.1,26,96.2,23.2,94.9,20.8L94.9,20.8z"></path></svg></div><div class="collapsible-item-inner"></div><header>${name}</header></div>
`
div.addEventListener('click', function () {
this.classList.toggle("active")
let icon = this.firstElementChild.firstElementChild as HTMLElement
icon.classList.toggle("anki-rotated")
let content = this.nextElementSibling as HTMLElement
if (content.style.display === "block") {
content.style.display = "none"
} else {
content.style.display = "block"
}
})
}
setup_note_table() {
let {containerEl} = this;
const plugin = (this as any).plugin
containerEl.createEl('h3', {text: 'Note type settings'})
this.create_collapsible("Note Type Table")
let note_type_table = containerEl.createEl('table', {cls: "anki-settings-table"})
let head = note_type_table.createTHead()
let header_row = head.insertRow()
for (let header of ["Note Type", "Custom Regexp", "File Link Field", "Context Field"]) {
let th = document.createElement("th")
th.appendChild(document.createTextNode(header))
header_row.appendChild(th)
}
let main_body = note_type_table.createTBody()
if (!(plugin.settings.hasOwnProperty("CONTEXT_FIELDS"))) {
plugin.settings.CONTEXT_FIELDS = {}
}
for (let note_type of plugin.note_types) {
let row = main_body.insertRow()
row.insertCell()
row.insertCell()
row.insertCell()
row.insertCell()
let row_cells = row.children
row_cells[0].innerHTML = note_type
this.setup_custom_regexp(note_type, row_cells)
this.setup_link_field(note_type, row_cells)
this.setup_context_field(note_type, row_cells)
}
}
setup_syntax() {
let {containerEl} = this;
const plugin = (this as any).plugin
let syntax_settings = containerEl.createEl('h3', {text: 'Syntax Settings'})
for (let key of Object.keys(plugin.settings["Syntax"])) {
new Setting(syntax_settings)
.setName(key)
.addText(
text => text.setValue(plugin.settings["Syntax"][key])
.onChange((value) => {
plugin.settings["Syntax"][key] = value
plugin.saveAllData()
})
)
}
}
setup_defaults() {
let {containerEl} = this;
const plugin = (this as any).plugin
let defaults_settings = containerEl.createEl('h3', {text: 'Defaults'})
// To account for new add context
if (!(plugin.settings["Defaults"].hasOwnProperty("Add Context"))) {
plugin.settings["Defaults"]["Add Context"] = false
}
// To account for new scheduling interval
if (!(plugin.settings["Defaults"].hasOwnProperty("Scheduling Interval"))) {
plugin.settings["Defaults"]["Scheduling Interval"] = 0
}
// To account for new highlights to clozes
if (!(plugin.settings["Defaults"].hasOwnProperty("CurlyCloze - Highlights to Clozes"))) {
plugin.settings["Defaults"]["CurlyCloze - Highlights to Clozes"] = false
}
// To account for new add obsidian tags
if (!(plugin.settings["Defaults"].hasOwnProperty("Add Obsidian Tags"))) {
plugin.settings["Defaults"]["Add Obsidian Tags"] = false
}
for (let key of Object.keys(plugin.settings["Defaults"])) {
// To account for removal of regex setting
if (key === "Regex") {
continue
}
if (typeof plugin.settings["Defaults"][key] === "string") {
new Setting(defaults_settings)
.setName(key)
.setDesc(defaultDescs[key])
.addText(
text => text.setValue(plugin.settings["Defaults"][key])
.onChange((value) => {
plugin.settings["Defaults"][key] = value
plugin.saveAllData()
})
)
} else if (typeof plugin.settings["Defaults"][key] === "boolean") {
new Setting(defaults_settings)
.setName(key)
.setDesc(defaultDescs[key])
.addToggle(
toggle => toggle.setValue(plugin.settings["Defaults"][key])
.onChange((value) => {
plugin.settings["Defaults"][key] = value
plugin.saveAllData()
})
)
} else {
new Setting(defaults_settings)
.setName(key)
.setDesc(defaultDescs[key])
.addSlider(
slider => {
slider.setValue(plugin.settings["Defaults"][key])
.setLimits(0, 360, 5)
.setDynamicTooltip()
.onChange(async (value) => {
plugin.settings["Defaults"][key] = value
await plugin.saveAllData()
if (plugin.hasOwnProperty("schedule_id")) {
window.clearInterval(plugin.schedule_id)
}
if (value != 0) {
plugin.schedule_id = window.setInterval(async () => await plugin.scanVault(), value * 1000 * 60)
plugin.registerInterval(plugin.schedule_id)
}
})
}
)
}
}
}
get_folders(): TFolder[] {
const app = (this as any).plugin.app
let folder_list: TFolder[] = [app.vault.getRoot()]
for (let folder of folder_list) {
let filtered_list: TFolder[] = folder.children.filter((element) => element.hasOwnProperty("children")) as TFolder[]
folder_list.push(...filtered_list)
}
return folder_list.slice(1) //Removes initial vault folder
}
setup_folder_deck(folder: TFolder, row_cells: HTMLCollection) {
const plugin = (this as any).plugin
let folder_decks = plugin.settings.FOLDER_DECKS
if (!(folder_decks.hasOwnProperty(folder.path))) {
folder_decks[folder.path] = ""
}
let folder_deck = new Setting(row_cells[1] as HTMLElement)
.addText(
text => text.setValue(folder_decks[folder.path])
.onChange((value) => {
plugin.settings.FOLDER_DECKS[folder.path] = value
plugin.saveAllData()
})
)
folder_deck.settingEl = row_cells[1] as HTMLElement
folder_deck.infoEl.remove()
folder_deck.controlEl.className += " anki-center"
}
setup_folder_tag(folder: TFolder, row_cells: HTMLCollection) {
const plugin = (this as any).plugin
let folder_tags = plugin.settings.FOLDER_TAGS
if (!(folder_tags.hasOwnProperty(folder.path))) {
folder_tags[folder.path] = ""
}
let folder_tag = new Setting(row_cells[2] as HTMLElement)
.addText(
text => text.setValue(folder_tags[folder.path])
.onChange((value) => {
plugin.settings.FOLDER_TAGS[folder.path] = value
plugin.saveAllData()
})
)
folder_tag.settingEl = row_cells[2] as HTMLElement
folder_tag.infoEl.remove()
folder_tag.controlEl.className += " anki-center"
}
setup_folder_table() {
let {containerEl} = this;
const plugin = (this as any).plugin
const folder_list = this.get_folders()
containerEl.createEl('h3', {text: 'Folder settings'})
this.create_collapsible("Folder Table")
let folder_table = containerEl.createEl('table', {cls: "anki-settings-table"})
let head = folder_table.createTHead()
let header_row = head.insertRow()
for (let header of ["Folder", "Folder Deck", "Folder Tags"]) {
let th = document.createElement("th")
th.appendChild(document.createTextNode(header))
header_row.appendChild(th)
}
let main_body = folder_table.createTBody()
if (!(plugin.settings.hasOwnProperty("FOLDER_DECKS"))) {
plugin.settings.FOLDER_DECKS = {}
}
if (!(plugin.settings.hasOwnProperty("FOLDER_TAGS"))) {
plugin.settings.FOLDER_TAGS = {}
}
for (let folder of folder_list) {
let row = main_body.insertRow()
row.insertCell()
row.insertCell()
row.insertCell()
let row_cells = row.children
row_cells[0].innerHTML = folder.path
this.setup_folder_deck(folder, row_cells)
this.setup_folder_tag(folder, row_cells)
}
}
setup_buttons() {
let {containerEl} = this
const plugin = (this as any).plugin
let action_buttons = containerEl.createEl('h3', {text: 'Actions'})
new Setting(action_buttons)
.setName("Regenerate Note Type Table")
.setDesc("Connect to Anki to regenerate the table with new note types, or get rid of deleted note types.")
.addButton(
button => {
button.setButtonText("Regenerate").setClass("mod-cta")
.onClick(async () => {
new Notice("Need to connect to Anki to update note types...")
try {
plugin.note_types = await AnkiConnect.invoke('modelNames')
plugin.regenerateSettingsRegexps()
plugin.fields_dict = await plugin.loadFieldsDict()
if (Object.keys(plugin.fields_dict).length != plugin.note_types.length) {
new Notice('Need to connect to Anki to generate fields dictionary...')
try {
plugin.fields_dict = await plugin.generateFieldsDict()
new Notice("Fields dictionary successfully generated!")
}
catch(e) {
new Notice("Couldn't connect to Anki! Check console for error message.")
return
}
}
await plugin.saveAllData()
this.setup_display()
new Notice("Note types updated!")
} catch(e) {
new Notice("Couldn't connect to Anki! Check console for details.")
}
})
}
)
new Setting(action_buttons)
.setName("Clear Media Cache")
.setDesc(`Clear the cached list of media filenames that have been added to Anki.
The plugin will skip over adding a media file if it's added a file with the same name before, so clear this if e.g. you've updated the media file with the same name.`)
.addButton(
button => {
button.setButtonText("Clear").setClass("mod-cta")
.onClick(async () => {
plugin.added_media = []
await plugin.saveAllData()
new Notice("Media Cache cleared successfully!")
})
}
)
new Setting(action_buttons)
.setName("Clear File Hash Cache")
.setDesc(`Clear the cached dictionary of file hashes that the plugin has scanned before.
The plugin will skip over a file if the file path and the hash is unaltered.`)
.addButton(
button => {
button.setButtonText("Clear").setClass("mod-cta")
.onClick(async () => {
plugin.file_hashes = {}
await plugin.saveAllData()
new Notice("File Hash Cache cleared successfully!")
})
}
)
}
setup_display() {
let {containerEl} = this
containerEl.empty()
containerEl.createEl('h2', {text: 'Obsidian_to_Anki settings'})
containerEl.createEl('a', {text: 'For more information check the wiki', href: "https://github.com/Pseudonium/Obsidian_to_Anki/wiki"})
this.setup_note_table()
this.setup_folder_table()
this.setup_syntax()
this.setup_defaults()
this.setup_buttons()
}
async display() {
this.setup_display()
}
}
Example #29
Source File: main.ts From obsidian-custom-attachment-location with GNU General Public License v3.0 | 4 votes |
class CustomAttachmentLocationSettingTab extends PluginSettingTab {
plugin: CustomAttachmentLocation;
constructor(app: App, plugin: CustomAttachmentLocation) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let {containerEl} = this;
containerEl.empty();
containerEl.createEl('h2', {text: 'Custom Attachment Location'});
let el = new Setting(containerEl)
.setName('Location for New Attachments')
.setDesc('Start with "./" to use relative path. Available variables: ${filename}.(NOTE: DO NOT start with "/" or end with "/". )')
.addText(text => text
.setPlaceholder('./assets/${filename}')
.setValue(this.plugin.settings.attachmentFolderPath)
.onChange(async (value: string) => {
console.log('attachmentFolder: ' + value);
value = normalizePath(value);
console.log('normalized attachmentFolder: ' + value);
this.plugin.settings.attachmentFolderPath = value;
if(value.startsWith('./'))
this.plugin.useRelativePath = true;
else
this.plugin.useRelativePath = false;
await this.plugin.saveSettings();
}));
el.controlEl.addEventListener('change', (()=>{this.display();}));
new Setting(containerEl)
.setName('Pasted Image Name')
.setDesc('Available variables: ${filename}, ${date}.')
.addText(text => text
.setPlaceholder('image-${date}')
.setValue(this.plugin.settings.pastedImageFileName)
.onChange(async (value: string) => {
console.log('pastedImageFileName: ' + value);
this.plugin.settings.pastedImageFileName = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Date Format')
.setDesc('YYYYMMDDHHmmssSSS')
.addMomentFormat(text => text
.setDefaultFormat('YYYYMMDDHHmmssSSS')
.setValue(this.plugin.settings.dateTimeFormat)
.onChange(async (value: string) => {
console.log('dateTimeFormat: ' + value);
this.plugin.settings.dateTimeFormat = value || 'YYYYMMDDHHmmssSSS';
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Automatically rename attachment folder')
.setDesc('When renaming md files, automatically rename attachment folder if folder name contains "${filename}".')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.autoRenameFolder)
.onChange(async (value: boolean) => {
this.plugin.settings.autoRenameFolder = value;
this.display();
await this.plugin.saveSettings();
}));
if(this.plugin.settings.autoRenameFolder)
new Setting(containerEl)
.setName('Automatically rename attachment files [Experimental]')
.setDesc('When renaming md files, automatically rename attachment files if file name contains "${filename}".')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.autoRenameFiles)
.onChange(async (value: boolean) => {
this.plugin.settings.autoRenameFiles = value;
await this.plugin.saveSettings();
}));
}
}