initial commit
This commit is contained in:
266
Program.fs
Normal file
266
Program.fs
Normal file
@@ -0,0 +1,266 @@
|
||||
module Program
|
||||
open Obsidian
|
||||
open Fable.Core
|
||||
open Fable.Core.JsInterop
|
||||
|
||||
[<Fable.Core.ImportAll(from = "obsidian")>]
|
||||
let obsidian : Obsidian.IExports = jsNative
|
||||
|
||||
type SamplePluginSettings = {
|
||||
mutable mySetting : string
|
||||
}
|
||||
|
||||
let defaultSettings : SamplePluginSettings = {
|
||||
mySetting = "default"
|
||||
}
|
||||
|
||||
[<Fable.Core.Import("Command", from = "obsidian")>]
|
||||
type DefaultCommand() =
|
||||
do ()
|
||||
|
||||
let defaultCommand () =
|
||||
let mutable mid = ""
|
||||
let mutable mname = ""
|
||||
let mutable _cb = None
|
||||
let mutable _ccb = None
|
||||
let mutable _hotkeys = None
|
||||
let mutable _editorCallback = None
|
||||
let mutable _editorCheckCallback = None
|
||||
|
||||
{ new Command with
|
||||
member this.callback
|
||||
with get () = _cb
|
||||
and set v = _cb <- v
|
||||
|
||||
member this.checkCallback
|
||||
with get () = _ccb
|
||||
and set v = _ccb <- v
|
||||
|
||||
member this.editorCallback
|
||||
with get () = _editorCallback
|
||||
and set v = _editorCallback <- v
|
||||
|
||||
member this.editorCheckCallback
|
||||
with get () = _editorCheckCallback
|
||||
and set v = _editorCheckCallback <- v
|
||||
|
||||
member this.hotkeys
|
||||
with get () = _hotkeys
|
||||
and set v = _hotkeys <- v
|
||||
|
||||
member this.icon: string option = None
|
||||
|
||||
member this.icon
|
||||
with set (v: string option): unit = ()
|
||||
|
||||
member this.id: string = mid
|
||||
|
||||
member this.id
|
||||
with set (v: string): unit = mid <- v
|
||||
|
||||
member this.mobileOnly: bool option = None
|
||||
|
||||
member this.mobileOnly
|
||||
with set (v: bool option): unit = ()
|
||||
|
||||
member this.name: string = mname
|
||||
|
||||
member this.name
|
||||
with set (v: string): unit = mname <- v
|
||||
}
|
||||
|
||||
[<Fable.Core.Import("PluginSettingTab", from = "obsidian")>]
|
||||
type DefaultPluginSettingTab(app, plugin) =
|
||||
do ()
|
||||
|
||||
type SamplePluginSettingTab(app, plugin) as instance =
|
||||
inherit DefaultPluginSettingTab(app, plugin)
|
||||
|
||||
let settings =
|
||||
instance :> obj :?> PluginSettingTab
|
||||
|
||||
let init () =
|
||||
settings?plugin <- plugin
|
||||
|
||||
instance?display <- fun () ->
|
||||
let containerEl : HTMLElement = settings?containerEl
|
||||
containerEl.empty ()
|
||||
|
||||
let mutable setting : Setting = obsidian.Setting.Create(containerEl)
|
||||
|
||||
setting <- setting
|
||||
.setName(U2.Case1 "Setting #1")
|
||||
.setDesc(U2.Case1 "It's a secret")
|
||||
.addText(fun text ->
|
||||
text
|
||||
.setPlaceholder("Enter your secret")
|
||||
.setValue(plugin?settings.mySetting)
|
||||
.onChange(fun value ->
|
||||
settings?plugin?settings.mySetting <- value
|
||||
settings?plugin?saveSettings ()
|
||||
Some ()
|
||||
) |> ignore
|
||||
|
||||
Some ()
|
||||
)
|
||||
|
||||
do init ()
|
||||
|
||||
|
||||
[<Fable.Core.Import("Modal", from = "obsidian")>]
|
||||
type DefaultModal(app) =
|
||||
do ()
|
||||
|
||||
type SampleModal(app) as instance =
|
||||
inherit DefaultModal(app)
|
||||
|
||||
let modal =
|
||||
instance :> obj :?> Modal
|
||||
|
||||
let init () =
|
||||
|
||||
modal?onOpen <- fun () ->
|
||||
let contentEl : HTMLElement = modal?contentEl
|
||||
U2.Case1 "Woah!" |> contentEl.setText
|
||||
|
||||
modal?onClose <- fun () ->
|
||||
let contentEl : HTMLElement = modal?contentEl
|
||||
contentEl.empty ()
|
||||
|
||||
do init ()
|
||||
|
||||
|
||||
// This workaround allows the members to be defined dynamically, without implementing
|
||||
// the whole interface.
|
||||
[<Fable.Core.Import("Plugin", from = "obsidian")>]
|
||||
type DefaultPlugin(app, manifest) =
|
||||
do ()
|
||||
|
||||
// Note: This cannot be named "Plugin", or the import from the Obsidian API will be renamed
|
||||
type SamplePlugin(app, manifest) as instance =
|
||||
inherit DefaultPlugin(app, manifest)
|
||||
|
||||
// This is what is actually holding the plugin data
|
||||
// It would be better to have the main plugin implement this interface, but I can't quite
|
||||
// get it to work right without an absurd amount of boilerplate
|
||||
let plugin =
|
||||
instance :> obj :?> Plugin
|
||||
|
||||
let init () : unit =
|
||||
plugin?loadSettings <- (fun _ ->
|
||||
promise {
|
||||
let! data = plugin.loadData ()
|
||||
|
||||
match data with
|
||||
| None -> plugin?settings <- defaultSettings
|
||||
| Some v ->
|
||||
try
|
||||
plugin?settings <- v :?> SamplePluginSettings
|
||||
with
|
||||
| _ ->
|
||||
plugin?settings <- defaultSettings
|
||||
}
|
||||
)
|
||||
|
||||
plugin?saveSettings <- (fun () ->
|
||||
promise {
|
||||
do! plugin.saveData (Some(!!plugin?settings))
|
||||
}
|
||||
)
|
||||
|
||||
// This creates an icon in the left ribbon.
|
||||
plugin?ribbonIconEl <-
|
||||
// Called when the user clicks the icon.
|
||||
let callback (evt : Browser.Types.MouseEvent) : Obsidian.Notice =
|
||||
obsidian.Notice.Create(U2.Case1 "This is a notice!")
|
||||
in
|
||||
|
||||
plugin?addRibbonIcon("dice", "Sample Plugin", callback)
|
||||
|
||||
// Perform additional things with the ribbon
|
||||
(plugin?ribbonIconEl : Element).addClass (
|
||||
let array = new ResizeArray<string>(1)
|
||||
array.Add("my-plugin-ribbon-class")
|
||||
array
|
||||
)
|
||||
|
||||
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
||||
let statusBarItemEl : Element = plugin?addStatusBarItem ()
|
||||
"Status Bar Text" |> U2.Case1 |> statusBarItemEl.setText
|
||||
|
||||
|
||||
// This adds a simple command that can be triggered anywhere
|
||||
plugin?addCommand (
|
||||
let mutable cmd = defaultCommand ()
|
||||
cmd.id <- "open-sample-modal-simple"
|
||||
cmd.name <- "Open sample modal (simple)"
|
||||
cmd.callback <- Some (fun _ ->
|
||||
Some((new SampleModal(plugin?app) :> obj :?> Modal).``open`` ())
|
||||
)
|
||||
cmd
|
||||
)
|
||||
|
||||
// This adds an editor command that can perform some operation on the current editor instance
|
||||
plugin?addCommand (
|
||||
let mutable cmd = defaultCommand ()
|
||||
cmd.id <- "sample-editor-command"
|
||||
cmd.name <- "Sample editor command"
|
||||
cmd.editorCallback <- Some (fun (editor : Editor) (view : MarkdownView) ->
|
||||
printf "%A" (editor.getSelection ())
|
||||
let replacement = editor.replaceSelection ("Sample Editor Command")
|
||||
Some replacement
|
||||
)
|
||||
cmd
|
||||
)
|
||||
|
||||
// This adds a complex command that can check whether the current state of the app allows execution of the command
|
||||
plugin?addCommand (
|
||||
let mutable cmd = defaultCommand ()
|
||||
cmd.id <- "open-sample-modal-complex"
|
||||
cmd.name <- "Open sample modal (complex)"
|
||||
cmd.checkCallback <- Some (fun checking ->
|
||||
// Conditions to check
|
||||
let app : App = plugin?app
|
||||
let markdownView =
|
||||
obsidian.MarkdownView :?> Constructor<MarkdownView>
|
||||
|> app.workspace.getActiveViewOfType
|
||||
match markdownView with
|
||||
| Some markdownView ->
|
||||
// If checking is true, we're simply "checking" if the command can be run.
|
||||
// If checking is false, then we want to actually perform the operation.
|
||||
if checking |> not then
|
||||
Some((new SampleModal(plugin?app) :> obj :?> Modal).``open`` ())
|
||||
|> ignore
|
||||
|
||||
// This command will only show up in Command Palette when the check function returns true
|
||||
true |> U2.Case1
|
||||
| None ->
|
||||
false |> U2.Case1
|
||||
|
||||
)
|
||||
cmd
|
||||
)
|
||||
|
||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||
plugin?addSettingTab (new SamplePluginSettingTab (plugin?app, plugin))
|
||||
|
||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
||||
plugin?registerDomEvent (Browser.Dom.document, "click", fun (evt : Browser.Types.MouseEvent) -> (
|
||||
printfn "click: %A" evt
|
||||
))
|
||||
|
||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
||||
plugin?registerInterval Browser.Dom.window.setInterval (fun () -> printfn "setInterval") (5 * 60 * 1000)
|
||||
|
||||
()
|
||||
|
||||
let onload: unit -> unit = fun _ -> plugin?settings <- plugin?loadSettings ()
|
||||
|
||||
do init ()
|
||||
|
||||
do plugin?onload <- onload
|
||||
|
||||
// DO NOT REMOVE
|
||||
// Change the name here to match the type name used above
|
||||
emitJsStatement "" "module.exports = SamplePlugin";
|
||||
Reference in New Issue
Block a user