Homepage    |    GitHub    |    API    |    FAQ

Help with CodeMirror.defineExtension syntax

I'm using v1.8.1 to write a new plugin.

In index.ts I have registered a new CodeMirror command.

await joplin.commands.register({
            name: 'scrollIntoView',
            label: 'Scroll the note to a set location',
            execute: async () => {

            },
        });

I'm calling it from an onclick event from within the new plugin.

joplin.commands.execute('editor.execCommand', {
    name: 'scrollIntoView',
    args: [{line: 21, ch: 21}]
});

The request is being recognised in a context script that defines the extension

 function plugin(CodeMirror) {
    CodeMirror.defineExtension('scrollIntoView', function(something) {
        console.log(something);
    });
 });

This is correctly sends the line and character values to the log .

My question is how do I call the CodeMirror function?

I've tried prefixing the 'scrollIntoView' function with nothing, 'cm.' and 'CodeMirror.'. But none work?

Do I need to define options for this call?

Obviously I'm trying to scroll the editor to a given line.

When you define the the scrollIntoView extension you're overwriting the cm.scrollIntoView function.
Just remove this function

CodeMirror.defineExtension('scrollIntoView', function(something) {
        console.log(something);
    });

and your code will work.

For future reference, when you're within a CodeMirror extension, you can access the active cm instance using the this variable. For example this.scrollIntoView(...). That won't work in your case though because you've overwritten the extension.

Thank you. I've removed the function as suggested, but the note will still not scroll as anticipated.

Should I able to use this CodeMirror call?

		await joplin.commands.register({
			name: 'editor.scrollCommand',
			label: 'Scroll',
			iconName: 'fas fa-link',
			execute: async () => {
				await joplin.commands.execute('editor.execCommand', {
					name: 'scrollIntoView',
					args: [{line: 5, ch:0}],
				});
		  },
		});
		await joplin.views.menuItems.create('scrollCommandContext', 'editor.scrollCommand', MenuItemLocation.EditorContextMenu, { accelerator: 'Ctrl+Enter' });

I used the above code to test and it works fine. Maybe you can share your full code and I can take a look?

Thank you, I appreciate your help. I've created a new plugin and only used your code, and have now manage to make it scroll, although I'll have to investigate what was stopping it in my previous attempt.

I have replaced the menu option with a button to make it scroll from a button click instead -

await joplin.views.toolbarButtons.create('scrollCommandContext', 'editor.scrollCommand', ToolbarButtonLocation.NoteToolbar);

So far, so good. Now am I wrong in thinking that I should be able to get the note to scroll with the CodeMirror editor closed? What I am trying achieve here is similar to scrollToHash which is available to plugins, but scroll to a particular line is not?

I don't really follow what you're asking. You want to scroll to a specific line in the editor when it's closed? Why not use scrollToHash if it's available.

Because scrollToHash only works if I have hashes in the document to scroll to. My documents are legal texts which I cannot alter, so I cannot make visible changes to the note by inserting hashes in them.

I have tried putting hashes in a hidden <!-- comment --> but it doesn't work. A hidden span doesn't work either <span style="display:none;"># location one</span>.

Ideally, I'd like scroll to line or even x,y (if I can calculate the line number). I'm sure other plugins at some stage in the future will need to be able to scroll a set position in a note?

I mistakenly believed that the CodeMirror scrollIntoView may still work even if not visible i.e it was only hidden.

I see now, I don't think what you're trying to do is possible.
However, there were some fixes to anchor links in v1.8.1 (the current pre-release) that should make your initial attempt using hashes work.

The below example works for me.

[Link to paragraph 13](#paragraph13)

Distinctio reiciendis velit dolor ut placeat est. Distinctio nostrum non maiores molestias. Molestiae ipsum nesciunt facere rerum est deserunt maiores at. Ducimus corrupti necessitatibus nihil facilis laboriosam blanditiis adipisci. Rerum magni nulla totam voluptatibus qui dolores.

Molestiae in assumenda vitae quaerat harum molestiae nisi. Error porro unde et modi culpa. Omnis est aliquam distinctio quibusdam. Voluptas accusamus omnis accusamus molestias facilis harum. Qui sequi ratione quidem suscipit.

Qui voluptatem eos optio delectus perspiciatis nemo dolorem. Voluptas vel dolore et corrupti libero aut consequatur. Hic consequuntur rerum nulla voluptas sapiente et cupiditate. Illo aspernatur nam consequatur rem tempora.

Repellendus sit atque nihil dolorem voluptatem sed. Ad molestias ut quae. Deserunt ipsa sint sed. Sint illo delectus iure delectus qui rem.

Sed aut incidunt et molestiae reiciendis qui ullam. Et minus neque maiores ut aut. Et id quisquam ducimus dolorem. Praesentium perferendis dolor enim eum.


Distinctio reiciendis velit dolor ut placeat est. Distinctio nostrum non maiores molestias. Molestiae ipsum nesciunt facere rerum est deserunt maiores at. Ducimus corrupti necessitatibus nihil facilis laboriosam blanditiis adipisci. Rerum magni nulla totam voluptatibus qui dolores.

Molestiae in assumenda vitae quaerat harum molestiae nisi. Error porro unde et modi culpa. Omnis est aliquam distinctio quibusdam. Voluptas accusamus omnis accusamus molestias facilis harum. Qui sequi ratione quidem suscipit.

Qui voluptatem eos optio delectus perspiciatis nemo dolorem. Voluptas vel dolore et corrupti libero aut consequatur. Hic consequuntur rerum nulla voluptas sapiente et cupiditate. Illo aspernatur nam consequatur rem tempora.

Repellendus sit atque nihil dolorem voluptatem sed. Ad molestias ut quae. Deserunt ipsa sint sed. Sint illo delectus iure delectus qui rem.

Sed aut incidunt et molestiae reiciendis qui ullam. Et minus neque maiores ut aut. Et id quisquam ducimus dolorem. Praesentium perferendis dolor enim eum.

Distinctio reiciendis velit dolor ut placeat est. Distinctio nostrum non maiores molestias. Molestiae ipsum nesciunt facere rerum est deserunt maiores at. Ducimus corrupti necessitatibus nihil facilis laboriosam blanditiis adipisci. Rerum magni nulla totam voluptatibus qui dolores.

Molestiae in assumenda vitae quaerat harum molestiae nisi. Error porro unde et modi culpa. Omnis est aliquam distinctio quibusdam. Voluptas accusamus omnis accusamus molestias facilis harum. Qui sequi ratione quidem suscipit.

<a id="paragraph13"></a>Qui voluptatem eos optio delectus perspiciatis nemo dolorem. Voluptas vel dolore et corrupti libero aut consequatur. Hic consequuntur rerum nulla voluptas sapiente et cupiditate. Illo aspernatur nam consequatur rem tempora.

Repellendus sit atque nihil dolorem voluptatem sed. Ad molestias ut quae. Deserunt ipsa sint sed. Sint illo delectus iure delectus qui rem.

Sed aut incidunt et molestiae reiciendis qui ullam. Et minus neque maiores ut aut. Et id quisquam ducimus dolorem. Praesentium perferendis dolor enim eum.

Yes, I'm aware of the fix you provided regarding a link only working once.

It is a possible solution, but would involve inserting multiple links somewhere into the document which again would be visible. I also wanted to (temporarily) highlight the scrolled to section, but that's another story.

Perhaps one day the plugin system will be developed sufficiently. Thanks anyway.

It won't be visible in the rendered view, but will be present in the editor view.

No, the target won't be visible, but the anchor is unfortunately. Not only that I'd have to return to where the links are located to click on the next one.

It's a real shame because I really really like using Joplin, and its developing into a great app, but the functionality around the use of tags could be sooo much better, certainly for my needs.

I don't need or use the synchronisation feature of Joplin, so I think I'm going have to consider coding a standalone web based app to replicate what I need it to do.

Isn't this where your plugin would come in?