I would like to write a plugin which allows me to toggle between displaying only highlights in a note or all text of the note. However, I am not familiar with Joplin plugins and ChatGPT keeps sending me into the woods.
So my questions:
ChatGPT asserts that this is only possible for the Markdown Viewer, but not in the Rich Text Editor. Is that true? I would really like to have this functionality in the latter context.
But all my attempts to at least get this working in the Markdown Viewer have failed until now. I am attempting to add a class to a container element in the viewer, which then forces only highlighted texts to be shown. Is this functionality at all possible using a plugin?
I have CSS which in the Rich Text Viewer gives me the highlights-only view I am looking for. But I can only enable it there, or not. What I need is a script that allows me to read a Joplin setting highlightsOnlyMode, to be set with a button, and depending on that value wrap the html in a div.highlights-only.
Is there any way to achieve this?
My current contentScript:
module.exports = {
default: function (context) {
return {
plugin: function (markdownIt) {
const defaultRender = markdownIt.renderer.render.bind(markdownIt.renderer);
markdownIt.renderer.render = function (tokens, options, env) {
let html = defaultRender(tokens, options, env);
// THIS SHOULD BE CONFIGURABLE WITH SETTING highlightsOnlyMode:
html = "<div class='highlights-only'>" + html + "</div>";
return html;
};
}
};
}
};
For the markdown editor, in a codemirror content script you might be able to use codemirror's foldEffect to fold all lines that don't have highlights:
doing this in the rich text editor could be more difficult though (not sure if its even possible, its generally not as extensible via plugins as the markdown editor)
Thank you! I already have CSS that just works fine to hide all paragraphs etc. that don’t have mark elements. But the problem is that I only can apply this static and binary: either enabled, or not.
To get it configurable with a Joplin setting is my problem. ContentScripts are sandboxed, so can’t access the joplin context, if I’m right. So I need some trick that would cause a change in the editor’s html depending on a Joplin setting. But maybe I’m asking for something impossible…
I have a few plugins with content scripts that adhere to configurable settings, though I've only tried this with a codemirror content script (not with a renderer content script)
you can send a message from the content script to the main plugin to read the plugin settings, example:
if you need it to change on demand (e.g. from a toolbar button) that could be the hard part as you mentioned, since the note viewer might not react if the markdown source doesn't change
I now have a solution, although not ideal: I can toggle the setting and depending on its value the highlights-only setting will do it’s work as soon as I visit a next note. From then on it remains effective, until I toggle the setting, visit a new note, etc. Is there a way to force a refresh of the current note? Then I wouldn’t have to visit a new note.
My code to achieve this (so contentScript.js is loaded conditionally):
await joplin.commands.register({
name: 'toggleHighlightView',
label: 'Toggle highlights-only view',
iconName: 'fa fa-eye',
execute: async () => {
const current = await joplin.settings.value('highlightsOnlyMode');
const newValue = !current;
await joplin.settings.setValue('highlightsOnlyMode', newValue);
if (newValue) {
alert("global hilights-only mode activated; visit a new note to see it in effect")
// --- MarkdownIt content script ---
await joplin.contentScripts.register(
ContentScriptType.MarkdownItPlugin,
'highlightView',
'./contentScript.js'
);
}
else {
alert("global hilights-only mode de-activated")
}
}
});
I spoke too soon: once the script has been registered, it can’t be unregistered anymore. So I can activate highlights only mode and then see that in effect in all notes during the session, but I can’t undo it. For that I have to set the setting to false and then restart Joplin. Only then I can see my full notes again. So still not ideal.
I now have a solution that works: upon each change of the setting I load a new script, that either adds the html container that triggers the highlights-only mode (if setting enabled), or removes that additional html if the setting is disabled. Each new script instance gets a unique id. In this way it works like some kind of decorator pattern. Probably not wise to repeat this procedure very often, but, hey, it works!
let scriptIndex = 1;
//.....
if (newValue) {
alert("global hilights-only mode ACTIVATED; visit a new note to see it in effect")
await joplin.contentScripts.register(
ContentScriptType.MarkdownItPlugin,
'highlightView' + scriptIndex,
'./contentScript.js'
);
}
else {
alert("global hilights-only mode DE-ACTIVATED; visit a new note to see it in effect")
await joplin.contentScripts.register(
ContentScriptType.MarkdownItPlugin,
'highlightViewUndo' + scriptIndex,
'./contentScriptUndo.js'
);
}
scriptIndex = scriptIndex + 1;
I ensured that headings will always be visible (for better overview of the content).
Also, when a note doesn’t have mark elements, its text will be visible, even when highlights-only mode is activated.
It seems that my scripts don’t modify the content of the note at all, so it’s only about the presentation of that content in the Html Editor.
My scripts assume that Joplin always uses simple paragraphs without classes etc. in this editor. I don’t know for sure whether that assumption is correct.
See below an example of a full note text and that same text after activating the highlights-only mode. Should this plugin be interesting to anyone else, then I can post it.
I have now published the plugin to npmjs.com. Now we have to wait for it to become available, I guess. The repository for this plugin can be found on GitHub.