so i’m new to obsidian’s plugin api. i have been trying to make a simple plugin to get the rendered html version of the markdown out of the view and save it to the clipboard. i have a few really cool plugins and i’d love to quickly copy paste my notes around the web.
my issue is the MarkdownView passed to the editor callback only seems to have the visible portion of the html in: view.contentEl.innerHTML. i played around trying to force a full render by calling view.previewMode.rerender(true); before line, w/o any luck. am i looking at the wrong object? here’s a snip of the plugin:
this.addCommand({
id: "html-copy",
name: "copy renders file html",
editorCallback: async (editor: Editor, view: MarkdownView) => {
let dom = view.contentEl.innerHTML; // only gets part
navigator.clipboard.writeText(dom);
new Notice(html saved to the clipboard, 3500);
},
});
i also tried the get method on the previewMode object, but that surprisingly returned the markdown itself.
view.previewMode.rerender(true);
const dom = view.previewMode.get();
navigator.clipboard.writeText(dom);
new Notice(html saved to the clipboard, 3500);
i tried using find selecting the root .mardown-reading-view and i get the same clipping issue. i noticed if i scroll whatever is in view is what’s returned.
Although I havent tried to read what is returned by MarkdownRenderer.render() API, but I have used it a lot to render HTML of the part of Raw text I wanted to render inside any Modal or View. Since I am appending it inside the HTML DIV, so i believe it is returning HTML code. But You can try it if that works.
The only issue will be you will need to pass the parent MD file and the content yourself to the API. (Well, this could be even a feature, like the user can select a part of the content from the view, and then right click to get the HTML for the same and you can get that specific part as HTML inside the clipboard)
i was reading this actually last night, but i couldn’t figure out what component i needed to pass. your example of creating a blank one is very helpful. i’ll give it a go, thanx!
@mnaoumov that’s a great solution and works if you want to just render some markdown. but i want to get all the rendered results of my plugins as well. things like shiki, expressive code, dataview tablets, etc.
i’ve done a bunch more testing, trying a new approach, this code ALMOST works:
...
async onload() {
this.addCommand({
id: "md2html-clip",
name: "note html to clipboard",
callback: () => {
const html = this.app.workspace.getActiveViewOfType(MarkdownView)?.contentEl.innerHTML;
if (html !== "") {
navigator.clipboard.writeText(html);
new Notice("html copied to the clipboard", 3456);
}
},
});
....
the problem is it only returns what’s viewable on the screen at the time.
i tired adding:
@mnaoumov i did indeed (i did max-1) and it didn’t seem to help.
what did help though, was adding a sleep(x) in between the 1st measure() and getting the innerHTML.
it still seems to work better if you manually scroll around the document and get it all rended 1st. trying to force it hasn’t gottem me anywhere. but that’s ok. doing it this way still works.
thanx again for all your help on this. i gave you a shoutout on github
while this get’s the full document (in live preview mode), only the originally visible parts are rendered. the rest is markdown still. in reading mode it doesn’t scroll, so it has no effect. so i left this out of the last release.
weird that my LSP didn’t tell me that sleep was async. thanks for that again my friend. I was trying increasingly larger values, since like you said, it wasn’t doing anything.