I need some help with my first plugin, which is a fork from a plugin that adds a third state to the checkbox and gives it a new colour. However, I want to add more states to the checkbox. I am pretty sure I can figure out visual part of changing the checkbox (using decorations/view plugin (right??)). My struggle is however more to do with editing the MD source.
The thing I noticed when messing around with the code from the original plugin was that this plugin only edits the DOM and not the actual MD source. It uses a CSS style to show a different coloured checkbox as the āthirdā state and edits the dataset.task variable in the DOM to be ā/ā (forgive me if I am using the wrong terminology, I am not super familiar with JS and web tech). I would really like to directly edit the MD source of the checkboxes to signify different states of checkboxes so that these changes will sync nicely across my devices. How could I do this? After reading the docs I came across replaceRange but I am not sure how to access the EditorPosition inside the the checkbox. I would like to be able to edit it without having to move the cursor there. I found this method on the CodeMirror docs posAtDOM which I guess allows me to access the EditorPosition from a particular html node? But like I said I am not super familiar with web tech and could not figure out how to connect the codemirror method with the obsidian API.
Any help or info to send me in the right direction would be much appreciated!! If you have any questions, please let me know, and I will do my best to answer them.
Thanks!
Matt
(edit) Not sure why this has been flagged as spam. I am just trying to get some help for stuff that I couldnāt find in other forum posts nor in the obsidian docs. I have removed the links to github in case that is seen as āpromotionalā. It would be appreciated if people could teach me what is wrong with my post rather than flagging it as spam. Bunch of salty mfs. Help a brother outā¦
Assuming you can get a proper position info from posAtDOM, you can use this method to convert that position into EditorPosition.
But Obsidian APIās Editor interface is just a wrapper for CodeMirror, so you can also edit the document directly with CodeMirror. (But CodeMirror takes some time to learn)
I am trying to figure out what I need to import/call to use the code mirror Editor rather than the obsidian Editor API. Iāve tried to look at the view plugin docs but the example code will not start⦠It gives me a type error for the constructor function.
Should I create a separate topic to report this as a bug? Not sure if there is a problem on my end or if there is something wrong with the example. Iāve literally just copied the example code from View Plugins
I will keep plodding along and updating here if I find anything
My guess is that you may be forgetting to register the view plugin.
// in the `onload` method of your Obsidian plugin
this.registerEditorExtension(examplePlugin);
One more important thing, you cannot edit the document via view plugins. View plugins only manipulate how the current state is displayed to users, and they cannot update the state itself.
For example, change the update method of the example view plugin to the following:
update(update: ViewUpdate) {
update.view.dispatch({
changes: {from: 0, insert: "Hello world!"} // insert "Hello world!" at the beginning of the document
})
}
Then, you will see this error message:
Error: Calls to EditorView.update are not allowed while an update is in progress
Your suggestion indeed fixed my problem. Might be worth adding that to the view plugin docs as I could not see it anywhere.
I have managed to edit the document using replaceRange but now my issue is how do I extract either the offset or other position info from a DOM event? Because if I understand it correctly, I am interacting with the DOM when I click somewhere in the editor. So when I click on the checkbox, how to I find the position info? I had assumed posAtDOM would give me that info but I have yet to manage to get that to work
I am trying to edit the source MD as I click on a checkbox, rather than add a command.
Anyway, thanks for the great suggestions! These will definitely help me down the line
In fact, itās mentioned on another page of the editor extension section of the docs, as I linked in the previous reply. But I agree itās better to include it in the view plugin page as well.
So when I click on the checkbox, how to I find the position info?
EditorView has another method called posAtCoords, which gives position info from the given screen coordinates.
When you click a dom, it triggers click event and this event object contains the screen coordinate of the clicked position. So you can
I am trying to edit the source MD as I click on a checkbox, rather than add a command.
OK, then register the editorCallback of the command as a DOM event handler to your plugin. I havenāt tested but something like this will work.
this.registerDomEvent(window, 'click', (event) => {
// check if the clicked dom is a checkbox
// @ts-ignore
const editorView = this.app.workspace.activeEditor?.editor?.cm;
if (!editorView) return;
...
})
The problem with this is that it never return the position within the brackets, only the position before or after the brackets.
Before the brackets:
After the brackets:
If I force the correct position using the offset, then I can edit between the brackets. However, it appends a space, so I add the end position as well:
Any codemirror wizards out there who can tell me what is going wrong? I also still donāt understand why I canāt use view.editor.posAtDOM but I can use view.editor.posAtCoords. Both of them are mentioned in the codemirror docs (and not in the obsidian docs), but when I try to use posAtDOM it is not recognised as a function.
When @ush linked to the codemirror docs I kind of assumed that I would be able to use all the functions mentioned on that page (which includes posAtDOM), but that doesnt seem to be the case. What am I missing?
Hey view.editor isnāt a CodeMirror editor view itself, but view.editor.cm is (as mentioned here).
I really recommend you read through the docs first. Also, looking over my sample code above again will help.
As I said, Editor is a wrapper of the CodeMirror editor. So Editor and EditorView arenāt the same. When editor is an Editor instance, you can access the associated EditorView by editor.cm.
Obsidian uses CodeMirror (CM) as the underlying text editor, and exposes the CodeMirror editor as part of the API. Editor serves as an abstraction to bridge features between CM6 and CM5 (legacy editor, only available on desktop). By using Editor instead of directly accessing the CodeMirror instance, you ensure that your plugin works on both platforms.
To manipulate the Markdown source in Obsidian plugins, you can use the editor API, particularly the editor.replaceRange method. Hereās a simple example of how you might use it:
const { Editor } = require(āobsidianā);
class YourPlugin {
// ⦠other plugin code
onInit() {
// Access the editor
this.editor = this.app.workspace.activeLeaf.view.sourceMode.cm;
// Replace a range in the Markdown source
this.replaceCheckboxState();
}
replaceCheckboxState() {
// Find the line number and position where you want to make changes
const lineNumber = 1; // replace with your desired line number
const line = this.editor.getLine(lineNumber);
const position = line.indexOf("[ ]");
// Replace the checkbox state at the specified position
this.editor.replaceRange("x", { line: lineNumber, ch: position }, { line: lineNumber, ch: position + 3 });
}