|
// Copy this entire file into your source directory, you can adapt it if you want |
|
// This code is written in a way that makes use of the same interface as all other Obsidian settings components |
|
|
|
import {setIcon, Setting, ValueComponent} from "obsidian"; |
|
|
|
declare module "obsidian" { |
|
interface Setting { |
|
addButtonList(cb: (component: ButtonListComponent) => any): this; |
|
} |
|
} |
|
|
|
|
|
class ButtonListComponent extends ValueComponent<string[]> { |
|
/** |
|
* Element that contains the list of selected values |
|
* @public |
|
*/ |
|
buttonListEl: HTMLElement; |
|
|
|
/** |
|
* Element that contains available options |
|
* @public |
|
*/ |
|
selectEl: HTMLSelectElement; |
|
|
|
/** |
|
* Each option may only be selected once |
|
* @private |
|
*/ |
|
private uniqueSelection: boolean = true; |
|
|
|
/** |
|
* Selected options will be hidden from the dropdown |
|
* @private |
|
*/ |
|
private hideSelected: boolean = false; |
|
|
|
/** |
|
* Maintain order of options |
|
* @private |
|
*/ |
|
private orderedSelection: boolean = true; |
|
|
|
/** |
|
* User-selected values |
|
* @private |
|
*/ |
|
private selectedValues: string[] = []; |
|
|
|
/** |
|
* Options that are available to select |
|
* @private |
|
*/ |
|
private options: Record<string, string> = {}; |
|
|
|
/** |
|
* Onchange callback |
|
* @private |
|
*/ |
|
private callback: (value: string[]) => any = () => { |
|
}; |
|
|
|
/** |
|
* Is disabled |
|
* @private |
|
*/ |
|
disabled: boolean = false; |
|
|
|
constructor(containerEl: HTMLElement) { |
|
super(); |
|
this.buttonListEl = containerEl.createEl('div', {cls: 'setting-command-hotkeys'}); |
|
this.selectEl = containerEl.createEl('select', {cls: 'dropdown'}); |
|
this.selectEl.createEl('option', {value: '', text: '+'}); |
|
this.selectEl.addEventListener('change', (e) => { |
|
const value = this.selectEl.value; |
|
if (value) { |
|
if ((this.uniqueSelection && !this.selectedValues.includes(value)) || !this.uniqueSelection) { |
|
this.selectedValues.push(value); |
|
|
|
if (this.orderedSelection) |
|
this.selectedValues.sort((a, b) => Object.keys(this.options).indexOf(a) - Object.keys(this.options).indexOf(b)); |
|
|
|
|
|
this.render(); |
|
this.callback(this.selectedValues); |
|
} |
|
this.selectEl.value = ''; |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* Render the component |
|
* @private |
|
*/ |
|
private render() { |
|
this.buttonListEl.empty(); |
|
for (const value of this.selectedValues) { |
|
const buttonEl = this.buttonListEl.createEl('span', {cls: 'setting-hotkey', text: this.options[value]}); |
|
if (!this.disabled) { |
|
const closeBtn = buttonEl.createEl('span', {cls: 'setting-hotkey-icon'}); |
|
setIcon(closeBtn, 'cross'); |
|
closeBtn.addEventListener('click', () => { |
|
this.selectedValues = this.selectedValues.filter((v) => v !== value); |
|
this.render(); |
|
this.callback(this.selectedValues); |
|
}); |
|
} |
|
} |
|
|
|
if (this.hideSelected) { |
|
// Remove all options and only add the ones that are not selected |
|
this.selectEl.empty(); |
|
this.selectEl.createEl('option', {value: '', text: '+'}); |
|
for (const value in this.options) |
|
if (!this.hideSelected || !this.selectedValues.includes(value)) |
|
this.selectEl.createEl('option', {value: value, text: this.options[value]}); |
|
} |
|
} |
|
|
|
setDisabled(disabled: boolean): this { |
|
this.selectEl.disabled = disabled; |
|
this.disabled = disabled; |
|
this.render(); |
|
return this; |
|
} |
|
|
|
addOption(value: string, text: string): this { |
|
this.selectEl.createEl('option', {value: value, text: text}); |
|
this.options[value] = text; |
|
this.render(); |
|
return this; |
|
} |
|
|
|
addOptions(options: { value: string, text: string }[]): this { |
|
for (const {value, text} of options) { |
|
this.selectEl.createEl('option', {value: value, text: text}); |
|
this.options[value] = text; |
|
} |
|
this.render(); |
|
return this; |
|
} |
|
|
|
getValue(): string[] { |
|
return this.selectedValues; |
|
} |
|
|
|
setValue(value: string[]): this { |
|
this.selectedValues = value; |
|
this.render(); |
|
return this; |
|
} |
|
|
|
/** |
|
* Hide selected options from the dropdown |
|
* @param setting - default: false |
|
*/ |
|
setHideSelected(setting: boolean = false) { |
|
this.hideSelected = setting; |
|
|
|
// If the buttonlist's setting can be changed on the fly, re-rendering is necessary |
|
// this.render(); |
|
|
|
// Remove all options and only add the ones that are not selected |
|
this.selectEl.empty(); |
|
this.selectEl.createEl('option', {value: '', text: '+'}); |
|
for (const value in this.options) |
|
if (!this.hideSelected || !this.selectedValues.includes(value)) |
|
this.selectEl.createEl('option', {value: value, text: this.options[value]}); |
|
|
|
return this; |
|
} |
|
|
|
/** |
|
* Do not allow an option to be selected more than once |
|
* @param setting - default: true |
|
*/ |
|
setUniqueSelection(setting: boolean = true): this { |
|
this.uniqueSelection = setting; |
|
|
|
// If the buttonlist's setting can be changed on the fly, re-rendering is necessary |
|
// this.selectedValues = this.selectedValues |
|
// .filter((value, index, self) => self.indexOf(value) === index); |
|
// this.render(); |
|
|
|
return this; |
|
} |
|
|
|
/** |
|
* Set selection to be ordered according to the order of the options |
|
* @param setting - default: true |
|
*/ |
|
setOrderedSelection(setting: boolean = true): this { |
|
this.orderedSelection = setting; |
|
|
|
// If the buttonlist's setting can be changed on the fly, re-rendering is necessary |
|
// this.render(); |
|
|
|
// Sort the selected values according to the order of the options |
|
this.selectedValues = this.selectedValues |
|
.sort((a, b) => Object.keys(this.options).indexOf(a) - Object.keys(this.options).indexOf(b)); |
|
|
|
return this; |
|
} |
|
|
|
|
|
onChange(callback: (value: string[]) => any): this { |
|
this.callback = callback; |
|
return this; |
|
}; |
|
} |
|
|
|
Setting.prototype.addButtonList = function (cb) { |
|
const component = new ButtonListComponent(this.controlEl); |
|
return this.components.push(component), cb(component), this; |
|
} |