Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
PlayerMiller109 committed Sep 17, 2024
0 parents commit 3f7d752
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
发布于 [Obsidian 中文论坛 t34933](https://forum-zh.obsidian.md/t/topic/34933/1),里面有一些前置的说明。

作者本人不是计算机专业的,一定要充分测试之后再使用,更好更安全的方式是参考示例自己写。

每个 modal 都有一些套路部分,如图红框所示,剩下部分就和定义一个普通函数没区别了,如图绿框所示,整个 modal 可看作一个异步函数 `rgx_form_modal = async (su)=>`。这样,就很好理解在其他文件引用时应该如何书写。

<image width="700" src="https://github.com/PlayerMiller109/obsidian-ample-modal-example/assets/145541890/56dfd86d-85f0-4643-a543-05e9900d8227">

例如,图示的 modal 只有 resolve,且 `this.close()` 后的 `this.r()` 中间没有参数,所以没有返回值,在其他文件使用时,格式就是:

```js
// Suppose you have introduced the modals.js in your plugin and name it "mySimpleApi"
const su = { rgx: '', f: '' }
// other possible expressions...
await this.mySimpleApi.rgx_form_modal(su)
// if no resolve, function stops here.
// other possible expressions...
```
49 changes: 49 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const ob = require('obsidian')
module.exports = class extends ob.Plugin {
mySimpleApi = require(`${app.vault.adapter.basePath}/${app.plugins.manifests['ample-modals'].dir}/src/modals.js`)(app, ob)
// 假设 JS 路径如上, 希望的 Api 名为 mySimpleApi
onload() {
// 这里注册命令以展示 modals
this.addCommand({
id: 'test-suggester', name: 'Test suggester',
callback: async ()=> {
const r1 = await this.mySimpleApi.suggester(['你能看到的'], ['你能得到的'], '预填值, 可不填')
if (!r1) return; console.log(r1)
const r2 = await this.mySimpleApi.suggester(p=> '选项'+p, [1, 2]); if (!r2) return
console.log(r2)
}
})
this.addCommand({
id: 'test-rgx_form_modal', name: 'Test rgx_form_modal',
callback: async ()=> {
const su = { rgx: '/(.*?_)(\\d{4})(\\d{2})(\\d{2})/', f: '`$1$2-$3-$4`' }
await this.mySimpleApi.rgx_form_modal(su)
console.log(su)
}
})
this.addCommand({
id: 'test-inputPrompt', name: 'Test inputPrompt',
callback: async ()=> {
const r = await this.mySimpleApi.inputPrompt('我是标题: 请输入', '我是占位符, 可不填', '我是预填值, 可不填')
if (!r) return; console.log(r)
}
})
this.addCommand({
id: 'test-yesNoPrompt', name: 'Test yesNoPrompt',
callback: async ()=> {
await this.mySimpleApi.yesNoPrompt('我是标题: 你好吗', '我是描述, 可不填')
? console.log('你好呀') : console.log('还没好')
}
})
this.addCommand({
id: 'test-checkboxPrompt', name: 'Test checkboxPrompt',
callback: async ()=> {
const items = ['选项1', '选项2', '选项3']
const chosenItems = await this.mySimpleApi.checkboxPrompt(items, ['选项1', '选项2'])
// 第 2 个参数为预勾选选项, 可不填
console.log(chosenItems)
}
})
}
onunload() {}
}
10 changes: 10 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "ample-modals",
"name": "Ample Modals",
"version": "0.0.1",
"minAppVersion": "1.4.4",
"description": "Plugin modals.",
"author": "PlayerMiller109",
"authorUrl": "https://github.com/PlayerMiller109/obsidian-ample-modals",
"isDesktopOnly": false
}
89 changes: 89 additions & 0 deletions src/modals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
module.exports = (app, ob)=> new class {
suggester = async (display, items, value = '')=> await new class extends ob.FuzzySuggestModal {
constructor(app) {
super(app); this.promise = new Promise(r=> this.r = r)
this.open(); Object.assign(this.inputEl, {value})
}
getItemText = (item)=> Array.isArray(display) ? display[items.indexOf(item)] : display(item)
getItems = ()=> items
onChooseItem = (item, evt)=> this.r(item)
}(app).promise

rgx_form_modal = async (su)=> await new class extends ob.Modal {
constructor(app) {
super(app); this.Setting = ob.Setting
this.promise = new Promise(r=> this.r = r)
this.modalEl.addClass('ample'); this.open()
}
get base() { return new this.Setting(this.contentEl).setClass('full-line-input') }
onOpen() {
this.base
.setName('Rgx').addText(inpu=> inpu.setValue(su.rgx).onChange(value=> su.rgx = value))
.addButton(btn=> btn.setButtonText('Submit').onClick(()=> { this.close(); this.r() }))
this.base.setName('Form').addText(inpu=> inpu.setValue(su.f).onChange(value=> su.f = value))
}
onClose() { this.contentEl.empty() }
}(app).promise

inputPrompt = async (header, placeholder = '', value = '')=> await new class extends ob.Modal {
constructor(app) {
super(app); this.Setting = ob.Setting
this.promise = new Promise((resolve, reject)=> (this.ok = resolve, this.fail = reject)).catch(e=> e)
this.modalEl.addClass('ample'); this.open()
}
onOpen() {
this.setTitle(header)
const area = this.contentEl.createEl('textarea', { cls: 'full-line-input' })
Object.assign(area, {
placeholder, value, style: 'height: 30px;',
oninput: ()=> { area.style.height = '32px'; area.style.height = `${area.scrollHeight}px` },
onkeydown: evt=> {
if (evt.key != 'Enter' || evt.shiftKey || evt.ctrlKey) return; evt.preventDefault()
this.close(); this.ok(area.value)
}
}); area.focus(); area.select()
new this.Setting(this.contentEl)
.addButton(btn=> btn.setButtonText('Cancel').onClick(()=> { this.close(); this.fail() }))
.addButton(btn=> btn.setClass('ok-btn').setButtonText('Ok').onClick(()=> { this.close(); this.ok(area.value) }))
}
onClose() { this.contentEl.empty() }
}(app).promise

yesNoPrompt = async (header, detail)=> await new class extends ob.Modal {
constructor(app) {
super(app); this.Setting = ob.Setting
this.promise = new Promise((resolve, reject)=> (this.ok = resolve, this.fail = reject)).catch(e=> e)
this.modalEl.addClass('ample'); this.open()
}
onOpen() {
this.setTitle(header); this.contentEl.createEl('div', { text: detail })
new this.Setting(this.contentEl)
.addButton(btn=> btn.setButtonText('No').onClick(()=> { this.close(); this.fail(!1) }))
.addButton(btn=> btn.setWarning().setButtonText('Yes').onClick(()=> { this.close(); this.ok(!0) }))
}
onClose() { this.contentEl.empty() }
}(app).promise

checkboxPrompt = async (items, chosenItems)=> await new class extends ob.Modal {
constructor(app) {
super(app); this.Setting = ob.Setting
this.promise = new Promise(r=> this.r = r)
this.modalEl.addClass('ample'); this.open()
}
onOpen() {
items.map(item=> new this.Setting(this.contentEl)
.setClass('toggle-box').setName(item)
.addToggle(box=> box
.setValue(chosenItems.includes(item))
.onChange(flag=>
flag ? chosenItems.push(item) : chosenItems.splice(chosenItems.findIndex(chosen=> chosen == item), 1)
)
)
)
new this.Setting(this.contentEl).addButton(btn=> btn
.setButtonText('Submit').onClick(()=> { this.close(); this.r(chosenItems) })
)
}
onClose() { this.contentEl.empty() }
}(app).promise
}
19 changes: 19 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@charset "UTF-8";

.ample.modal {
& .setting-item {border-top: none;}

& .full-line-input > .setting-item-info {display: none;}
& .full-line-input > .setting-item-control > input,
textarea.full-line-input {
flex-grow: 1; width: 100%; resize: none; overflow: hidden;
}

& .ok-btn {
--interactive-normal: var(--interactive-accent);
--interactive-hover: var(--interactive-accent-hover);
}

& .toggle-box {padding-block: var(--size-4-1);}
& .toggle-box+ .setting-item {padding-bottom: 0;}
}

0 comments on commit 3f7d752

Please sign in to comment.