mirror of
https://github.com/shadiestgoat/obsidian-simple-password.git
synced 2026-07-22 05:46:29 +00:00
Format
This commit is contained in:
parent
bac7923d58
commit
f527d77d1f
9 changed files with 600 additions and 594 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"useTabs": false,
|
||||
"useTabs": true,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
|
|
|
|||
|
|
@ -1,56 +1,56 @@
|
|||
<script lang="ts">
|
||||
let wrongCount = $state(0)
|
||||
let wrongCount = $state(0)
|
||||
|
||||
interface Props {
|
||||
correctPassword: string
|
||||
hint: string
|
||||
value?: string
|
||||
interface Props {
|
||||
correctPassword: string
|
||||
hint: string
|
||||
value?: string
|
||||
placeholder?: string
|
||||
}
|
||||
}
|
||||
|
||||
let { correctPassword, hint, value = $bindable(''), placeholder = "Password" }: Props = $props()
|
||||
let { correctPassword, hint, value = $bindable(''), placeholder = 'Password' }: Props = $props()
|
||||
|
||||
export function submit(shoulClear: boolean): boolean {
|
||||
const correct = value == correctPassword
|
||||
export function submit(shoulClear: boolean): boolean {
|
||||
const correct = value == correctPassword
|
||||
|
||||
if (shoulClear) {
|
||||
value = ''
|
||||
}
|
||||
if (shoulClear) {
|
||||
value = ''
|
||||
}
|
||||
|
||||
if (correct) {
|
||||
return true
|
||||
}
|
||||
if (correct) {
|
||||
return true
|
||||
}
|
||||
|
||||
wrongCount++
|
||||
wrongCount++
|
||||
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="sp-password-input">
|
||||
<!-- svelte-ignore a11y_autofocus -->
|
||||
<!-- This is only rendered in modals, at which point focus SHOULD jump to the new element -->
|
||||
<input type="password" {placeholder} autofocus bind:value />
|
||||
{#if wrongCount > 0}
|
||||
<p class="sp-wrong">
|
||||
Wrong Password!
|
||||
{#if wrongCount > 2 && hint}
|
||||
Hint: <span class="sp-hint">{hint}</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
<input type="password" {placeholder} autofocus bind:value />
|
||||
{#if wrongCount > 0}
|
||||
<p class="sp-wrong">
|
||||
Wrong Password!
|
||||
{#if wrongCount > 2 && hint}
|
||||
Hint: <span class="sp-hint">{hint}</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sp-hint {
|
||||
font-style: italic;
|
||||
}
|
||||
.sp-hint {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sp-password-input {
|
||||
width: 100%;
|
||||
}
|
||||
.sp-password-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
<script lang="ts">
|
||||
import type { App } from 'obsidian'
|
||||
import { PathSuggestions } from 'src/settings'
|
||||
import { onMount } from 'svelte'
|
||||
import type { App } from 'obsidian'
|
||||
import { PathSuggestions } from 'src/settings'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let inputEl: HTMLInputElement
|
||||
let inputEl: HTMLInputElement
|
||||
|
||||
onMount(() => {
|
||||
new PathSuggestions(app, inputEl).onSelect((v) => (path = v))
|
||||
})
|
||||
onMount(() => {
|
||||
new PathSuggestions(app, inputEl).onSelect((v) => (path = v))
|
||||
})
|
||||
|
||||
interface Props {
|
||||
app: App
|
||||
path: string
|
||||
disabled: boolean
|
||||
}
|
||||
interface Props {
|
||||
app: App
|
||||
path: string
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
let { app, path = $bindable(''), disabled }: Props = $props()
|
||||
let { app, path = $bindable(''), disabled }: Props = $props()
|
||||
</script>
|
||||
|
||||
<input type="text" bind:this={inputEl} placeholder="Path" bind:value={path} {disabled} />
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
<svelte:options runes />
|
||||
|
||||
<script lang="ts">
|
||||
import PasswordInput from './PasswordInput.svelte'
|
||||
import PasswordInput from './PasswordInput.svelte'
|
||||
|
||||
interface Props {
|
||||
correctPassword: string
|
||||
hint: string
|
||||
onCorrect?: () => void
|
||||
}
|
||||
interface Props {
|
||||
correctPassword: string
|
||||
hint: string
|
||||
onCorrect?: () => void
|
||||
}
|
||||
|
||||
let { correctPassword, hint, onCorrect = () => {} }: Props = $props()
|
||||
let { correctPassword, hint, onCorrect = () => {} }: Props = $props()
|
||||
|
||||
let passInput: PasswordInput
|
||||
let value = $state('')
|
||||
let passInput: PasswordInput
|
||||
let value = $state('')
|
||||
</script>
|
||||
|
||||
<p>This file is protected, please input your password</p>
|
||||
|
||||
<form
|
||||
class="sp-container"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
class="sp-container"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if (passInput.submit(true)) {
|
||||
onCorrect()
|
||||
}
|
||||
}}
|
||||
if (passInput.submit(true)) {
|
||||
onCorrect()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<PasswordInput bind:this={passInput} bind:value {correctPassword} {hint} />
|
||||
<PasswordInput bind:this={passInput} bind:value {correctPassword} {hint} />
|
||||
|
||||
<button type="submit" disabled={value == ''} aria-label="Submit Button" class="mod-cta">
|
||||
Ok
|
||||
</button>
|
||||
<button type="submit" disabled={value == ''} aria-label="Submit Button" class="mod-cta">
|
||||
Ok
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,77 +1,83 @@
|
|||
<svelte:options runes />
|
||||
|
||||
<script lang="ts">
|
||||
import PasswordInput from './PasswordInput.svelte'
|
||||
import PasswordInput from './PasswordInput.svelte'
|
||||
|
||||
let newPassword = $state('')
|
||||
let conPassword = $state('')
|
||||
let oldPassword = $state('')
|
||||
let newPassword = $state('')
|
||||
let conPassword = $state('')
|
||||
let oldPassword = $state('')
|
||||
|
||||
interface Props {
|
||||
onSubmit: (newPassword: string) => void
|
||||
requireOldPassword: boolean
|
||||
correctPassword?: string
|
||||
hint?: string
|
||||
}
|
||||
interface Props {
|
||||
onSubmit: (newPassword: string) => void
|
||||
requireOldPassword: boolean
|
||||
correctPassword?: string
|
||||
hint?: string
|
||||
}
|
||||
|
||||
let { requireOldPassword, hint = '', correctPassword = '', onSubmit }: Props = $props()
|
||||
let { requireOldPassword, hint = '', correctPassword = '', onSubmit }: Props = $props()
|
||||
|
||||
let passInp: PasswordInput | undefined = $state()
|
||||
let displayMismatch = $derived(
|
||||
!!newPassword && !!conPassword && (newPassword != conPassword || newPassword.length < 3)
|
||||
)
|
||||
let passInp: PasswordInput | undefined = $state()
|
||||
let displayMismatch = $derived(
|
||||
!!newPassword && !!conPassword && (newPassword != conPassword || newPassword.length < 3)
|
||||
)
|
||||
</script>
|
||||
|
||||
<form
|
||||
class="sp-container sp-container-new-password"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
class="sp-container sp-container-new-password"
|
||||
onsubmit={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
let happy = true
|
||||
let happy = true
|
||||
|
||||
if (!passInp?.submit(false)) {
|
||||
happy = false
|
||||
}
|
||||
if (!passInp?.submit(false)) {
|
||||
happy = false
|
||||
}
|
||||
|
||||
if (newPassword != conPassword) {
|
||||
happy = false
|
||||
}
|
||||
if (newPassword != conPassword) {
|
||||
happy = false
|
||||
}
|
||||
|
||||
if (happy) {
|
||||
onSubmit(newPassword)
|
||||
}
|
||||
}}
|
||||
if (happy) {
|
||||
onSubmit(newPassword)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if requireOldPassword}
|
||||
<PasswordInput {correctPassword} {hint} bind:this={passInp} bind:value={oldPassword} placeholder="Old Password" />
|
||||
{/if}
|
||||
{#if requireOldPassword}
|
||||
<PasswordInput
|
||||
{correctPassword}
|
||||
{hint}
|
||||
bind:this={passInp}
|
||||
bind:value={oldPassword}
|
||||
placeholder="Old Password"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<input type="password" placeholder="New Password" bind:value={newPassword} />
|
||||
<input type="password" placeholder="Confirm Password" bind:value={conPassword} />
|
||||
{#if displayMismatch}
|
||||
{#if newPassword.length < 3}
|
||||
<p class="sp-wrong">Password needs to be longer than 3 chracters</p>
|
||||
{:else}
|
||||
<p class="sp-wrong">Passwords don't match</p>
|
||||
{/if}
|
||||
{/if}
|
||||
<input type="password" placeholder="New Password" bind:value={newPassword} />
|
||||
<input type="password" placeholder="Confirm Password" bind:value={conPassword} />
|
||||
{#if displayMismatch}
|
||||
{#if newPassword.length < 3}
|
||||
<p class="sp-wrong">Password needs to be longer than 3 chracters</p>
|
||||
{:else}
|
||||
<p class="sp-wrong">Passwords don't match</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!newPassword ||
|
||||
!conPassword ||
|
||||
!(requireOldPassword && oldPassword) ||
|
||||
displayMismatch}
|
||||
aria-label="Submit Button"
|
||||
class="mod-cta"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!newPassword ||
|
||||
!conPassword ||
|
||||
!(requireOldPassword && oldPassword) ||
|
||||
displayMismatch}
|
||||
aria-label="Submit Button"
|
||||
class="mod-cta"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.sp-container-new-password {
|
||||
flex-direction: column;
|
||||
}
|
||||
.sp-container-new-password {
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
<script lang="ts">
|
||||
import type { App } from 'obsidian'
|
||||
import Path from './Path.svelte'
|
||||
import type { Writable, Readable } from 'svelte/store'
|
||||
import type { App } from 'obsidian'
|
||||
import Path from './Path.svelte'
|
||||
import type { Writable, Readable } from 'svelte/store'
|
||||
|
||||
interface Props {
|
||||
paths: Writable<string[]>
|
||||
app: App
|
||||
disabled: Readable<boolean>
|
||||
}
|
||||
interface Props {
|
||||
paths: Writable<string[]>
|
||||
app: App
|
||||
disabled: Readable<boolean>
|
||||
}
|
||||
|
||||
let { paths, app, disabled }: Props = $props()
|
||||
let { paths, app, disabled }: Props = $props()
|
||||
|
||||
function evWrapper(cb: () => void): {
|
||||
onkeypress: (e: KeyboardEvent) => void
|
||||
onclick: () => void
|
||||
} {
|
||||
return {
|
||||
onclick: cb,
|
||||
onkeypress: (e) => {
|
||||
if (e.key == ' ' || e.key == 'Enter') {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function evWrapper(cb: () => void): {
|
||||
onkeypress: (e: KeyboardEvent) => void
|
||||
onclick: () => void
|
||||
} {
|
||||
return {
|
||||
onclick: cb,
|
||||
onkeypress: (e) => {
|
||||
if (e.key == ' ' || e.key == 'Enter') {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<hr />
|
||||
|
|
@ -31,46 +31,46 @@
|
|||
<h3>Protected Paths</h3>
|
||||
|
||||
<div class="sp-paths">
|
||||
{#each $paths as _, i (i)}
|
||||
<div class="sp-path-container">
|
||||
<Path {app} bind:path={$paths[i]} disabled={$disabled} />
|
||||
<button
|
||||
disabled={$disabled}
|
||||
class="mod-err"
|
||||
aria-label="Remove Path"
|
||||
{...evWrapper(() => {
|
||||
$paths.splice(i, 1)
|
||||
{#each $paths as _, i (i)}
|
||||
<div class="sp-path-container">
|
||||
<Path {app} bind:path={$paths[i]} disabled={$disabled} />
|
||||
<button
|
||||
disabled={$disabled}
|
||||
class="mod-err"
|
||||
aria-label="Remove Path"
|
||||
{...evWrapper(() => {
|
||||
$paths.splice(i, 1)
|
||||
|
||||
$paths = $paths
|
||||
})}
|
||||
>
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
$paths = $paths
|
||||
})}
|
||||
>
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<button
|
||||
disabled={$disabled}
|
||||
class="mod-cta"
|
||||
aria-label="Add New Path"
|
||||
{...evWrapper(() => ($paths = [...$paths, '/']))}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<button
|
||||
disabled={$disabled}
|
||||
class="mod-cta"
|
||||
aria-label="Add New Path"
|
||||
{...evWrapper(() => ($paths = [...$paths, '/']))}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sp-paths {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--size-4-2);
|
||||
}
|
||||
.sp-paths {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--size-4-2);
|
||||
}
|
||||
|
||||
.mod-err {
|
||||
background: var(--background-modifier-error);
|
||||
}
|
||||
.mod-err {
|
||||
background: var(--background-modifier-error);
|
||||
}
|
||||
|
||||
.sp-path-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.sp-path-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
360
src/main.ts
360
src/main.ts
|
|
@ -12,235 +12,235 @@ const ICON_RIBBON_UNLOCKED = 'unlock'
|
|||
|
||||
// So we have a problem when closing tabs: the File is set to null
|
||||
type SafeLeaf = {
|
||||
leaf: WorkspaceLeaf
|
||||
file: TFile
|
||||
leaf: WorkspaceLeaf
|
||||
file: TFile
|
||||
}
|
||||
|
||||
export default class SimplePassword extends Plugin {
|
||||
settings: Settings
|
||||
ribbonIconEl: HTMLElement
|
||||
autolockTimeoutID: ReturnType<typeof setTimeout>
|
||||
lastHoveredFile: string
|
||||
settings: Settings
|
||||
ribbonIconEl: HTMLElement
|
||||
autolockTimeoutID: ReturnType<typeof setTimeout>
|
||||
lastHoveredFile: string
|
||||
|
||||
isLocked: boolean
|
||||
isLocking = false
|
||||
isLocked: boolean
|
||||
isLocking = false
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings()
|
||||
this.isLocked = true
|
||||
async onload() {
|
||||
await this.loadSettings()
|
||||
this.isLocked = true
|
||||
|
||||
this.ribbonIconEl = this.addRibbonIcon(ICON_RIBBON_LOCKED, STR_RIBBON_LOCKED, () => {
|
||||
this.onIconClick()
|
||||
})
|
||||
this.ribbonIconEl = this.addRibbonIcon(ICON_RIBBON_LOCKED, STR_RIBBON_LOCKED, () => {
|
||||
this.onIconClick()
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: 'sp-lock-vault',
|
||||
name: 'Lock Vault',
|
||||
callback: () => {
|
||||
this.lock()
|
||||
}
|
||||
})
|
||||
this.addCommand({
|
||||
id: 'sp-lock-vault',
|
||||
name: 'Lock Vault',
|
||||
callback: () => {
|
||||
this.lock()
|
||||
}
|
||||
})
|
||||
|
||||
this.registerObsidianProtocolHandler('lock', () => {
|
||||
this.lock()
|
||||
})
|
||||
this.registerObsidianProtocolHandler('lock', () => {
|
||||
this.lock()
|
||||
})
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on('file-open', (f: TFile | null) => {
|
||||
if (!f || !this.isLocked) return
|
||||
this.registerEvent(
|
||||
this.app.workspace.on('file-open', (f: TFile | null) => {
|
||||
if (!f || !this.isLocked) return
|
||||
|
||||
if (this.isPathLocked(f.path)) {
|
||||
this.lock()
|
||||
}
|
||||
})
|
||||
)
|
||||
if (this.isPathLocked(f.path)) {
|
||||
this.lock()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
;['create', 'modify', 'delete', 'rename'].forEach((evName) => {
|
||||
this.registerEvent(
|
||||
// @ts-expect-error Overloads + Paramters don't play well
|
||||
this.app.vault.on(evName, () => {
|
||||
this.resetAutolock()
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
;['create', 'modify', 'delete', 'rename'].forEach((evName) => {
|
||||
this.registerEvent(
|
||||
// @ts-expect-error Overloads + Paramters don't play well
|
||||
this.app.vault.on(evName, () => {
|
||||
this.resetAutolock()
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
this.register(() => this.removeAutolock())
|
||||
this.registerEvent(
|
||||
this.register(() => this.removeAutolock())
|
||||
this.registerEvent(
|
||||
this.app.workspace.on(
|
||||
// @ts-expect-error Undocumented api
|
||||
'hover-link',
|
||||
({ linktext }: { linktext: string }) => {
|
||||
'hover-link',
|
||||
({ linktext }: { linktext: string }) => {
|
||||
// Name aside, linktext is always the correct link
|
||||
// Though not always an abs path so
|
||||
this.lastHoveredFile = linktext
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
this.watchDom()
|
||||
this.watchDom()
|
||||
|
||||
this.addSettingTab(new SettingsTab(this.app, this))
|
||||
this.addSettingTab(new SettingsTab(this.app, this))
|
||||
|
||||
// If there are any unprotected things, lock!
|
||||
this.lock()
|
||||
}
|
||||
// If there are any unprotected things, lock!
|
||||
this.lock()
|
||||
}
|
||||
|
||||
removeAutolock(): void {
|
||||
if (this.autolockTimeoutID) {
|
||||
clearTimeout(this.autolockTimeoutID)
|
||||
}
|
||||
}
|
||||
removeAutolock(): void {
|
||||
if (this.autolockTimeoutID) {
|
||||
clearTimeout(this.autolockTimeoutID)
|
||||
}
|
||||
}
|
||||
|
||||
resetAutolock(): void {
|
||||
this.removeAutolock()
|
||||
resetAutolock(): void {
|
||||
this.removeAutolock()
|
||||
|
||||
if (this.settings.autoLockMinutes) {
|
||||
this.autolockTimeoutID = setTimeout(
|
||||
() => {
|
||||
this.lock()
|
||||
},
|
||||
60 * 1000 * this.settings.autoLockMinutes
|
||||
)
|
||||
}
|
||||
}
|
||||
if (this.settings.autoLockMinutes) {
|
||||
this.autolockTimeoutID = setTimeout(
|
||||
() => {
|
||||
this.lock()
|
||||
},
|
||||
60 * 1000 * this.settings.autoLockMinutes
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
isPathLocked(testPath: string): boolean {
|
||||
for (const _p of this.settings.protectedPaths) {
|
||||
const p = new URL(_p, 'file://').pathname
|
||||
isPathLocked(testPath: string): boolean {
|
||||
for (const _p of this.settings.protectedPaths) {
|
||||
const p = new URL(_p, 'file://').pathname
|
||||
|
||||
if (('/' + testPath).startsWith(p)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (('/' + testPath).startsWith(p)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
watchDom() {
|
||||
const domObs = new MutationObserver(() => {
|
||||
if (!this.isLocked || this.isLocking) {
|
||||
return
|
||||
}
|
||||
watchDom() {
|
||||
const domObs = new MutationObserver(() => {
|
||||
if (!this.isLocked || this.isLocking) {
|
||||
return
|
||||
}
|
||||
|
||||
// I decied to add a dom observer clause here, since a user could embed the thing on the fly
|
||||
const embedDoc = document.querySelector('.internal-embed[src]')
|
||||
if (embedDoc) {
|
||||
const path = embedDoc.attributes.getNamedItem('src')?.value
|
||||
if (path) {
|
||||
const realPath = this.app.metadataCache.getFirstLinkpathDest(path, '')?.path
|
||||
if (realPath) {
|
||||
const curFile = this.app.workspace.getActiveFile()
|
||||
const curLeaf = this.app.workspace.getMostRecentLeaf()
|
||||
// I decied to add a dom observer clause here, since a user could embed the thing on the fly
|
||||
const embedDoc = document.querySelector('.internal-embed[src]')
|
||||
if (embedDoc) {
|
||||
const path = embedDoc.attributes.getNamedItem('src')?.value
|
||||
if (path) {
|
||||
const realPath = this.app.metadataCache.getFirstLinkpathDest(path, '')?.path
|
||||
if (realPath) {
|
||||
const curFile = this.app.workspace.getActiveFile()
|
||||
const curLeaf = this.app.workspace.getMostRecentLeaf()
|
||||
|
||||
if (curLeaf && curFile) {
|
||||
this.lock(true, [{ leaf: curLeaf, file: curFile }])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (curLeaf && curFile) {
|
||||
this.lock(true, [{ leaf: curLeaf, file: curFile }])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const popover = document.querySelector('.popover.hover-popover')
|
||||
if (!popover) return
|
||||
const popover = document.querySelector('.popover.hover-popover')
|
||||
if (!popover) return
|
||||
|
||||
console.log("hover", this.lastHoveredFile)
|
||||
console.log('hover', this.lastHoveredFile)
|
||||
|
||||
if (this.isPathLocked(this.lastHoveredFile)) {
|
||||
popover.remove()
|
||||
this.lock(true)
|
||||
return true
|
||||
}
|
||||
})
|
||||
popover.remove()
|
||||
this.lock(true)
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
domObs.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
})
|
||||
domObs.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
})
|
||||
|
||||
this.register(() => domObs.disconnect())
|
||||
}
|
||||
this.register(() => domObs.disconnect())
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs all the needed actions to initiate a lock
|
||||
*/
|
||||
async lock(alwaysRequestPassword = false, extraLeaves: SafeLeaf[] = []) {
|
||||
this.isLocked = true
|
||||
this.isLocking = true
|
||||
this.setRibbonIcon(true)
|
||||
this.removeAutolock()
|
||||
/**
|
||||
* Performs all the needed actions to initiate a lock
|
||||
*/
|
||||
async lock(alwaysRequestPassword = false, extraLeaves: SafeLeaf[] = []) {
|
||||
this.isLocked = true
|
||||
this.isLocking = true
|
||||
this.setRibbonIcon(true)
|
||||
this.removeAutolock()
|
||||
|
||||
const protectedLeaves: SafeLeaf[] = [...extraLeaves]
|
||||
const protectedLeaves: SafeLeaf[] = [...extraLeaves]
|
||||
|
||||
// We always need to know if theres active files, no matter the privacy mode
|
||||
this.app.workspace.iterateRootLeaves((l) => {
|
||||
if (l?.view instanceof FileView && l.view?.file) {
|
||||
if (this.isPathLocked(l.view.file.path)) {
|
||||
protectedLeaves.push({ leaf: l, file: l.view.file })
|
||||
}
|
||||
}
|
||||
})
|
||||
// We always need to know if theres active files, no matter the privacy mode
|
||||
this.app.workspace.iterateRootLeaves((l) => {
|
||||
if (l?.view instanceof FileView && l.view?.file) {
|
||||
if (this.isPathLocked(l.view.file.path)) {
|
||||
protectedLeaves.push({ leaf: l, file: l.view.file })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!alwaysRequestPassword && protectedLeaves.length == 0) {
|
||||
this.isLocking = false
|
||||
return
|
||||
}
|
||||
if (!alwaysRequestPassword && protectedLeaves.length == 0) {
|
||||
this.isLocking = false
|
||||
return
|
||||
}
|
||||
|
||||
if (this.settings.privacyMode == PrivacyMode.CLOSE) {
|
||||
protectedLeaves.forEach((v) => {
|
||||
v.leaf.detach()
|
||||
})
|
||||
}
|
||||
if (this.settings.privacyMode == PrivacyMode.CLOSE) {
|
||||
protectedLeaves.forEach((v) => {
|
||||
v.leaf.detach()
|
||||
})
|
||||
}
|
||||
|
||||
this.requestUserToUnlock(protectedLeaves)
|
||||
}
|
||||
this.requestUserToUnlock(protectedLeaves)
|
||||
}
|
||||
|
||||
requestUserToUnlock(protectedViews: SafeLeaf[] = []) {
|
||||
console.log('Password requested')
|
||||
requestUserToUnlock(protectedViews: SafeLeaf[] = []) {
|
||||
console.log('Password requested')
|
||||
|
||||
new RequirePasswordModal(this.app, this.settings, (success) => {
|
||||
this.isLocked = !success
|
||||
this.isLocking = false
|
||||
new RequirePasswordModal(this.app, this.settings, (success) => {
|
||||
this.isLocked = !success
|
||||
this.isLocking = false
|
||||
|
||||
if (success) {
|
||||
this.setRibbonIcon(false)
|
||||
this.resetAutolock()
|
||||
new Notice('Vault unlocked')
|
||||
if (success) {
|
||||
this.setRibbonIcon(false)
|
||||
this.resetAutolock()
|
||||
new Notice('Vault unlocked')
|
||||
|
||||
if (this.settings.privacyMode == PrivacyMode.CLOSE) {
|
||||
protectedViews.forEach((v) => {
|
||||
this.app.workspace.getLeaf('tab').openFile(v.file)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
new Notice('Password prompt cancelled')
|
||||
if (this.settings.privacyMode == PrivacyMode.CLOSE) {
|
||||
protectedViews.forEach((v) => {
|
||||
this.app.workspace.getLeaf('tab').openFile(v.file)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
new Notice('Password prompt cancelled')
|
||||
|
||||
if (this.settings.privacyMode == PrivacyMode.BLUR) {
|
||||
protectedViews.forEach((v) => v.leaf.detach())
|
||||
}
|
||||
}
|
||||
}).open()
|
||||
}
|
||||
if (this.settings.privacyMode == PrivacyMode.BLUR) {
|
||||
protectedViews.forEach((v) => v.leaf.detach())
|
||||
}
|
||||
}
|
||||
}).open()
|
||||
}
|
||||
|
||||
onIconClick() {
|
||||
if (this.isLocked) {
|
||||
this.requestUserToUnlock()
|
||||
} else {
|
||||
this.lock()
|
||||
}
|
||||
}
|
||||
onIconClick() {
|
||||
if (this.isLocked) {
|
||||
this.requestUserToUnlock()
|
||||
} else {
|
||||
this.lock()
|
||||
}
|
||||
}
|
||||
|
||||
setRibbonIcon(locked: boolean) {
|
||||
this.ribbonIconEl.ariaLabel = locked ? STR_RIBBON_LOCKED : STR_RIBBON_UNLOCKED
|
||||
setIcon(this.ribbonIconEl, locked ? ICON_RIBBON_LOCKED : ICON_RIBBON_UNLOCKED)
|
||||
}
|
||||
setRibbonIcon(locked: boolean) {
|
||||
this.ribbonIconEl.ariaLabel = locked ? STR_RIBBON_LOCKED : STR_RIBBON_UNLOCKED
|
||||
setIcon(this.ribbonIconEl, locked ? ICON_RIBBON_LOCKED : ICON_RIBBON_UNLOCKED)
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData())
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData())
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings)
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
136
src/modals.ts
136
src/modals.ts
|
|
@ -7,89 +7,89 @@ import SettingsPassword from './components/SettingsPassword.svelte'
|
|||
type PasswordCallback = (success: boolean) => void
|
||||
|
||||
export class RequirePasswordModal extends Modal {
|
||||
svelteContent: Record<string, never>
|
||||
settings: Settings
|
||||
succeeded: boolean
|
||||
callback: PasswordCallback
|
||||
svelteContent: Record<string, never>
|
||||
settings: Settings
|
||||
succeeded: boolean
|
||||
callback: PasswordCallback
|
||||
|
||||
constructor(app: App, settings: Settings, cb: PasswordCallback) {
|
||||
super(app)
|
||||
constructor(app: App, settings: Settings, cb: PasswordCallback) {
|
||||
super(app)
|
||||
|
||||
this.settings = settings
|
||||
this.callback = cb
|
||||
this.succeeded = false
|
||||
}
|
||||
this.settings = settings
|
||||
this.callback = cb
|
||||
this.succeeded = false
|
||||
}
|
||||
|
||||
onOpen(): void {
|
||||
this.setTitle('Password Required!')
|
||||
this.shouldRestoreSelection = true
|
||||
this.containerEl.addClass('sp-modal-container')
|
||||
this.containerEl.toggleClass('sp-modal-blur', this.settings.privacyMode == PrivacyMode.BLUR)
|
||||
onOpen(): void {
|
||||
this.setTitle('Password Required!')
|
||||
this.shouldRestoreSelection = true
|
||||
this.containerEl.addClass('sp-modal-container')
|
||||
this.containerEl.toggleClass('sp-modal-blur', this.settings.privacyMode == PrivacyMode.BLUR)
|
||||
|
||||
this.svelteContent = mount(RequirePassword, {
|
||||
target: this.contentEl,
|
||||
props: {
|
||||
correctPassword: this.settings.password,
|
||||
hint: this.settings.hint,
|
||||
onCorrect: () => {
|
||||
this.succeeded = true
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
this.svelteContent = mount(RequirePassword, {
|
||||
target: this.contentEl,
|
||||
props: {
|
||||
correctPassword: this.settings.password,
|
||||
hint: this.settings.hint,
|
||||
onCorrect: () => {
|
||||
this.succeeded = true
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
close(): void {
|
||||
// This needs to be done BEFORE the actual modal closes
|
||||
// This is to ensure that everything is clsoed in case of a non-success
|
||||
this.callback(this.succeeded)
|
||||
close(): void {
|
||||
// This needs to be done BEFORE the actual modal closes
|
||||
// This is to ensure that everything is clsoed in case of a non-success
|
||||
this.callback(this.succeeded)
|
||||
|
||||
super.close()
|
||||
}
|
||||
super.close()
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
unmount(this.svelteContent, { outro: true })
|
||||
}
|
||||
async onClose() {
|
||||
unmount(this.svelteContent, { outro: true })
|
||||
}
|
||||
}
|
||||
|
||||
type NewPasswordCallback = (password: string) => void
|
||||
|
||||
export class NewPasswordModal extends Modal {
|
||||
svelteContent: Record<string, never>
|
||||
settings: Settings
|
||||
callback: NewPasswordCallback
|
||||
password: string
|
||||
svelteContent: Record<string, never>
|
||||
settings: Settings
|
||||
callback: NewPasswordCallback
|
||||
password: string
|
||||
|
||||
constructor(app: App, settings: Settings, cb: NewPasswordCallback) {
|
||||
super(app)
|
||||
constructor(app: App, settings: Settings, cb: NewPasswordCallback) {
|
||||
super(app)
|
||||
|
||||
this.settings = settings
|
||||
this.callback = cb
|
||||
this.password = ''
|
||||
}
|
||||
this.settings = settings
|
||||
this.callback = cb
|
||||
this.password = ''
|
||||
}
|
||||
|
||||
onOpen(): void {
|
||||
this.setTitle('Password Required!')
|
||||
this.shouldRestoreSelection = true
|
||||
this.containerEl.addClass('sp-modal-container')
|
||||
this.containerEl.toggleClass('sp-modal-blur', this.settings.privacyMode == PrivacyMode.BLUR)
|
||||
onOpen(): void {
|
||||
this.setTitle('Password Required!')
|
||||
this.shouldRestoreSelection = true
|
||||
this.containerEl.addClass('sp-modal-container')
|
||||
this.containerEl.toggleClass('sp-modal-blur', this.settings.privacyMode == PrivacyMode.BLUR)
|
||||
|
||||
this.svelteContent = mount(SettingsPassword, {
|
||||
target: this.contentEl,
|
||||
props: {
|
||||
requireOldPassword: this.settings.password != '',
|
||||
correctPassword: this.settings.password,
|
||||
hint: this.settings.hint,
|
||||
onSubmit: (pass) => {
|
||||
this.password = pass
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
this.svelteContent = mount(SettingsPassword, {
|
||||
target: this.contentEl,
|
||||
props: {
|
||||
requireOldPassword: this.settings.password != '',
|
||||
correctPassword: this.settings.password,
|
||||
hint: this.settings.hint,
|
||||
onSubmit: (pass) => {
|
||||
this.password = pass
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
this.callback(this.password)
|
||||
unmount(this.svelteContent, { outro: true })
|
||||
}
|
||||
async onClose() {
|
||||
this.callback(this.password)
|
||||
unmount(this.svelteContent, { outro: true })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
324
src/settings.ts
324
src/settings.ts
|
|
@ -7,198 +7,198 @@ import { mount, unmount } from 'svelte'
|
|||
import { writable, get } from 'svelte/store'
|
||||
|
||||
export enum PrivacyMode {
|
||||
BLUR = 'blur',
|
||||
CLOSE = 'close',
|
||||
NONE = ''
|
||||
BLUR = 'blur',
|
||||
CLOSE = 'close',
|
||||
NONE = ''
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
autoLockMinutes: number
|
||||
privacyMode: PrivacyMode
|
||||
protectedPaths: string[]
|
||||
hint: string
|
||||
password: string
|
||||
autoLockMinutes: number
|
||||
privacyMode: PrivacyMode
|
||||
protectedPaths: string[]
|
||||
hint: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: Settings = {
|
||||
autoLockMinutes: 15,
|
||||
privacyMode: PrivacyMode.BLUR,
|
||||
protectedPaths: ['/'],
|
||||
hint: '',
|
||||
password: ''
|
||||
autoLockMinutes: 15,
|
||||
privacyMode: PrivacyMode.BLUR,
|
||||
protectedPaths: ['/'],
|
||||
hint: '',
|
||||
password: ''
|
||||
}
|
||||
|
||||
export class SettingsTab extends PluginSettingTab {
|
||||
plugin: SimplePassword
|
||||
lockBtn: ButtonComponent
|
||||
lockSet: Setting
|
||||
lockableSettings: Setting[]
|
||||
svelteComp: SettingsPaths
|
||||
plugin: SimplePassword
|
||||
lockBtn: ButtonComponent
|
||||
lockSet: Setting
|
||||
lockableSettings: Setting[]
|
||||
svelteComp: SettingsPaths
|
||||
|
||||
locked = writable(true)
|
||||
locked = writable(true)
|
||||
|
||||
constructor(app: App, plugin: SimplePassword) {
|
||||
super(app, plugin)
|
||||
constructor(app: App, plugin: SimplePassword) {
|
||||
super(app, plugin)
|
||||
|
||||
this.plugin = plugin
|
||||
this.plugin = plugin
|
||||
|
||||
this.locked.subscribe((v) => {
|
||||
if (!this.lockableSettings || !this.lockBtn || !this.lockSet) return
|
||||
this.locked.subscribe((v) => {
|
||||
if (!this.lockableSettings || !this.lockBtn || !this.lockSet) return
|
||||
|
||||
if (v) {
|
||||
this.lockBtn.setIcon('unlock')
|
||||
this.lockSet.setName('Unlock settings below')
|
||||
} else {
|
||||
this.lockBtn.setIcon('lock')
|
||||
this.lockSet.setName('Lock settings below')
|
||||
}
|
||||
if (v) {
|
||||
this.lockBtn.setIcon('unlock')
|
||||
this.lockSet.setName('Unlock settings below')
|
||||
} else {
|
||||
this.lockBtn.setIcon('lock')
|
||||
this.lockSet.setName('Lock settings below')
|
||||
}
|
||||
|
||||
this.lockableSettings.forEach((s) => {
|
||||
s.setDisabled(v)
|
||||
})
|
||||
})
|
||||
}
|
||||
this.lockableSettings.forEach((s) => {
|
||||
s.setDisabled(v)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
display() {
|
||||
const { containerEl } = this
|
||||
display() {
|
||||
const { containerEl } = this
|
||||
|
||||
containerEl.empty()
|
||||
containerEl.addClass('sp-settings')
|
||||
containerEl.empty()
|
||||
containerEl.addClass('sp-settings')
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(this.plugin.settings.password ? 'Change Password' : 'Set Password')
|
||||
.addButton((btn) => {
|
||||
btn.setCta()
|
||||
.setButtonText('Change')
|
||||
.onClick(() => this.onPasswordChangeButton())
|
||||
})
|
||||
new Setting(containerEl)
|
||||
.setName(this.plugin.settings.password ? 'Change Password' : 'Set Password')
|
||||
.addButton((btn) => {
|
||||
btn.setCta()
|
||||
.setButtonText('Change')
|
||||
.onClick(() => this.onPasswordChangeButton())
|
||||
})
|
||||
|
||||
this.lockSet = new Setting(containerEl)
|
||||
.setName('Unlock settings below')
|
||||
.setDesc(
|
||||
'The following settings are sensetive, and therefore require that you enter your password'
|
||||
)
|
||||
.addButton((btn) => {
|
||||
btn.setIcon('unlock').onClick(() => this.onLockBtn())
|
||||
this.lockBtn = btn
|
||||
})
|
||||
.setDisabled(this.plugin.settings.password == '')
|
||||
this.lockSet = new Setting(containerEl)
|
||||
.setName('Unlock settings below')
|
||||
.setDesc(
|
||||
'The following settings are sensetive, and therefore require that you enter your password'
|
||||
)
|
||||
.addButton((btn) => {
|
||||
btn.setIcon('unlock').onClick(() => this.onLockBtn())
|
||||
this.lockBtn = btn
|
||||
})
|
||||
.setDisabled(this.plugin.settings.password == '')
|
||||
|
||||
containerEl.createEl('hr')
|
||||
containerEl.createEl('hr')
|
||||
|
||||
this.lockableSettings = [
|
||||
new Setting(containerEl)
|
||||
.setName('Auto Lock Minutes')
|
||||
.setDesc('After x minutes of inactivity, lock the vault. Set to 0 for no auto lock')
|
||||
.addText((text) => {
|
||||
text.setPlaceholder('# of Minutes').setValue(
|
||||
this.plugin.settings.autoLockMinutes.toString()
|
||||
)
|
||||
text.inputEl.type = 'number'
|
||||
text.onChange((v) => {
|
||||
const f = parseFloat(v)
|
||||
if (!isNaN(f)) {
|
||||
this.plugin.settings.autoLockMinutes = f
|
||||
this.plugin.resetAutolock()
|
||||
this.plugin.saveSettings()
|
||||
}
|
||||
})
|
||||
})
|
||||
.setDisabled(true),
|
||||
new Setting(containerEl)
|
||||
.setName('Privacy Mode')
|
||||
.setDesc('What should we do on lock?')
|
||||
.addDropdown((drop) => {
|
||||
drop.addOptions({
|
||||
[PrivacyMode.BLUR]: 'Blur Background',
|
||||
[PrivacyMode.CLOSE]: 'Close Affected Tabs',
|
||||
[PrivacyMode.NONE]: 'Nothing'
|
||||
})
|
||||
.onChange((v) => {
|
||||
this.plugin.settings.privacyMode = v as PrivacyMode
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
.setValue(this.plugin.settings.privacyMode)
|
||||
})
|
||||
.setDisabled(true),
|
||||
new Setting(containerEl)
|
||||
.setName('Hint')
|
||||
.setDesc('Add a hint for your password (shown in case of > 3 failed attempts)')
|
||||
.addText((text) => {
|
||||
text.setPlaceholder('Hint')
|
||||
.onChange((v) => {
|
||||
this.plugin.settings.hint = v
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
.setValue(this.plugin.settings.hint)
|
||||
})
|
||||
.setDisabled(true)
|
||||
]
|
||||
this.lockableSettings = [
|
||||
new Setting(containerEl)
|
||||
.setName('Auto Lock Minutes')
|
||||
.setDesc('After x minutes of inactivity, lock the vault. Set to 0 for no auto lock')
|
||||
.addText((text) => {
|
||||
text.setPlaceholder('# of Minutes').setValue(
|
||||
this.plugin.settings.autoLockMinutes.toString()
|
||||
)
|
||||
text.inputEl.type = 'number'
|
||||
text.onChange((v) => {
|
||||
const f = parseFloat(v)
|
||||
if (!isNaN(f)) {
|
||||
this.plugin.settings.autoLockMinutes = f
|
||||
this.plugin.resetAutolock()
|
||||
this.plugin.saveSettings()
|
||||
}
|
||||
})
|
||||
})
|
||||
.setDisabled(true),
|
||||
new Setting(containerEl)
|
||||
.setName('Privacy Mode')
|
||||
.setDesc('What should we do on lock?')
|
||||
.addDropdown((drop) => {
|
||||
drop.addOptions({
|
||||
[PrivacyMode.BLUR]: 'Blur Background',
|
||||
[PrivacyMode.CLOSE]: 'Close Affected Tabs',
|
||||
[PrivacyMode.NONE]: 'Nothing'
|
||||
})
|
||||
.onChange((v) => {
|
||||
this.plugin.settings.privacyMode = v as PrivacyMode
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
.setValue(this.plugin.settings.privacyMode)
|
||||
})
|
||||
.setDisabled(true),
|
||||
new Setting(containerEl)
|
||||
.setName('Hint')
|
||||
.setDesc('Add a hint for your password (shown in case of > 3 failed attempts)')
|
||||
.addText((text) => {
|
||||
text.setPlaceholder('Hint')
|
||||
.onChange((v) => {
|
||||
this.plugin.settings.hint = v
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
.setValue(this.plugin.settings.hint)
|
||||
})
|
||||
.setDisabled(true)
|
||||
]
|
||||
|
||||
const paths = writable(this.plugin.settings.protectedPaths)
|
||||
paths.subscribe((v) => {
|
||||
this.plugin.settings.protectedPaths = v
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
const paths = writable(this.plugin.settings.protectedPaths)
|
||||
paths.subscribe((v) => {
|
||||
this.plugin.settings.protectedPaths = v
|
||||
this.plugin.saveSettings()
|
||||
})
|
||||
|
||||
this.svelteComp = mount(SettingsPaths, {
|
||||
target: containerEl,
|
||||
props: {
|
||||
app: this.app,
|
||||
disabled: this.locked,
|
||||
paths
|
||||
}
|
||||
})
|
||||
}
|
||||
this.svelteComp = mount(SettingsPaths, {
|
||||
target: containerEl,
|
||||
props: {
|
||||
app: this.app,
|
||||
disabled: this.locked,
|
||||
paths
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onLockBtn() {
|
||||
if (get(this.locked)) {
|
||||
new RequirePasswordModal(this.app, this.plugin.settings, (success) => {
|
||||
if (success) {
|
||||
this.locked.set(false)
|
||||
}
|
||||
}).open()
|
||||
} else {
|
||||
this.locked.set(true)
|
||||
}
|
||||
}
|
||||
onLockBtn() {
|
||||
if (get(this.locked)) {
|
||||
new RequirePasswordModal(this.app, this.plugin.settings, (success) => {
|
||||
if (success) {
|
||||
this.locked.set(false)
|
||||
}
|
||||
}).open()
|
||||
} else {
|
||||
this.locked.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
onPasswordChangeButton() {
|
||||
new NewPasswordModal(this.app, this.plugin.settings, (p) => {
|
||||
if (p) {
|
||||
new Notice('Changed Password')
|
||||
this.plugin.settings.password = p
|
||||
this.plugin.saveSettings()
|
||||
onPasswordChangeButton() {
|
||||
new NewPasswordModal(this.app, this.plugin.settings, (p) => {
|
||||
if (p) {
|
||||
new Notice('Changed Password')
|
||||
this.plugin.settings.password = p
|
||||
this.plugin.saveSettings()
|
||||
|
||||
this.lockSet.setDisabled(false)
|
||||
this.locked.set(true)
|
||||
} else {
|
||||
new Notice('Password Change Cancelled')
|
||||
}
|
||||
}).open()
|
||||
}
|
||||
this.lockSet.setDisabled(false)
|
||||
this.locked.set(true)
|
||||
} else {
|
||||
new Notice('Password Change Cancelled')
|
||||
}
|
||||
}).open()
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
unmount(this.svelteComp)
|
||||
super.hide()
|
||||
}
|
||||
hide(): void {
|
||||
unmount(this.svelteComp)
|
||||
super.hide()
|
||||
}
|
||||
}
|
||||
|
||||
export class PathSuggestions extends AbstractInputSuggest<string> {
|
||||
protected getSuggestions(query: string): string[] {
|
||||
const p = new URL(query, 'file://').pathname
|
||||
protected getSuggestions(query: string): string[] {
|
||||
const p = new URL(query, 'file://').pathname
|
||||
|
||||
return this.app.vault
|
||||
.getAllFolders(true)
|
||||
.filter((v) => {
|
||||
if (('/' + v.path).startsWith(p)) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
.map((v) => v.path)
|
||||
}
|
||||
return this.app.vault
|
||||
.getAllFolders(true)
|
||||
.filter((v) => {
|
||||
if (('/' + v.path).startsWith(p)) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
.map((v) => v.path)
|
||||
}
|
||||
|
||||
renderSuggestion(value: string, el: HTMLElement): void {
|
||||
el.setText(value)
|
||||
}
|
||||
renderSuggestion(value: string, el: HTMLElement): void {
|
||||
el.setText(value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue