Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow plugins to customise note list items #5389

Closed
9 tasks done
laurent22 opened this issue Aug 27, 2021 · 6 comments · Fixed by #8897
Closed
9 tasks done

Allow plugins to customise note list items #5389

laurent22 opened this issue Aug 27, 2021 · 6 comments · Fixed by #8897
Labels
plugins Anything related to Joplin's plugin system spec Fully developed spec that can serve as a starting point for a project

Comments

@laurent22
Copy link
Owner

laurent22 commented Aug 27, 2021

The goal of this feature is to allow plugins to customise the note list and in particular the way each note is rendered. Then for example this kind of features could be done as plugins:

  • Display the note as a thumbnail
  • Display an excerpt of the note body below the title
  • Display tags
  • Display various buttons that could be clicked on

As part of this feature, it should also be set the note list flow:

  • Top to bottom (as now)
  • Left to right (would be useful to display thumbnails for example)

All that should be done in a backward compatible way, so that the note list by default still looks like it does now.

Implementation

The app would still be responsible for displaying the note list and its items. This is necessary because it needs to be optimised so that only the visible notes are being rendered. That allows having thousands of notes inside a notebooks without any slow down.

The part that will be customisable is the the note list item. Currently it is shows the note title and, optionally, a checkbox on the left:

For maximum flexibility, the API should let plugins define the note list items as HTML. This could be done like so:

  • The plugin registers a note list item renderer, which provides some HTML based on the note to be rendered
  • There should be some way for the plugin to specify the width and height of the item, so that the app knows how many fit within the note list panel.
  • The app gets the HTML for all the notes currently visible, and display them.

Interaction

Allowing the plugin to listen to mouse clicks or keyboard events on the items might be a bit tricky, due to the process boundaries between plugin and app. Perhaps it will require a custom solution - for example, the app could listen to event, then call an event handler on the plugin when something has been clicked.

Plugin conflicts

The above solution would allow only one plugin at a time to modify the note list items. It's not ideal but it's not clear how it could be done otherwise.

Example 1

interface NoteView {
	html: string;
}

await joplin.views.noteList.registerNoteRenderer('my-id', {
	flow: 'leftToRight',

	itemSize: {
		width: 500,
		height: 300,
	},

	onRenderNotes: async (notes:any[]) => {
		const output:Record<string, NoteView> = {};

		for (const note of notes) {
			const noteTags = await joplin.data.get('notes/' + note.id + '/tags');
			output[note.id] = {
				html: `<div>${note.title}<br/>${note.created_time}<br/><a id="tag-0" href="#">${noteTags[0]}</a></div>`,
			};
		}
		
		return output;
	},

	onItemClick = async (item:any, elementId:string) => {
	  // For example, if the tag is clicked above, "elementId"
	  // would be "tag-0".
		console.info('Item element was clicked: ' + elementId);
	},
})

Example 2

This other version uses a different approach which may offer better performances:

  • The plugin developer specifies what dependencies are needed for rendering
    • If they haven't changed between render, we just use the cached version we have
  • A Mustache template is also provided - that's the HTML used to render the list item
    • It contains placeholder that are filled at render time
  • The onRenderNote method returns the values for the template placeholders.

The advantage is that we no longer have a method to render the whole, but only each individual items. The inconvenient is that when the list is created we have to call onRenderNote multiple times, which may be slow over IPC. Should investigate if it can be called multiple times plugin-side, then the complete result (all the rendered items) is sent back to the host in one call. If that can be done, this approach should be better.

await joplin.views.noteList.registerNoteRenderer('my-id', {
	flow: 'leftToRight',

	itemSize: {
		width: 500,
		height: 300,
	},

	dependencies: [
		'noteTitle',
		'noteCreatedTime',
		'noteTags',
	],

	itemTemplate: `
		<div>
			<div>{{title}}</div>
			<div>Created: {{date}}</div>
			<div>{#tagTitles}}<span class="tag">{{.}}</span>{{/tagTitles}}</div>
		</div>
	`,

	onRenderNote: async (context:Context, noteTitle:string, noteCreatedTime:number, noteTags:TagEntity[]) => {
		return {
			title: noteTitle,
			date: dayjs(noteCreatedTime).format('DD/MM/YYYY'),
			tagTitles: noteTags.map(t => t.title),
		};
	},
})

Suggested features

Examples of features that we'd like to support. We should check if they can be implemented with the plugin API we provide.

  • Display modification date, location, number of edits (Number of edits would be computed separately so we need to think how it could be displayed)
  • Display tags
  • Snippet of note
  • show URL for web clippings
  • number of checked & unchecked check boxes in a note
  • attachments marker like in outlook
  • Display if a note has recent changes that haven’t been pushed to the server yet.
  • Display condition based “groupper” line. For example: (notes) viewed this week, (notes) edited today, (notes that) have attachments, (notes that) link outside of its notebook, etc. (see example) - would be out of scope for this first version
  • Rename note by double clicking on it, i.e. display renaming form in the notelist - displaying a working text input is possible, but handling the different display after double-click means supporting state, which is for a future version

Other ideas

Render list item content via filters

  • In order to allow multiple plugins to modify the note item content, we could make the plugins act as filters, which modify the HTML content. For example it starts with <div class="title">Note title</div>, then plugin 1 change this by adding the date below: <div class="title">Note title</div><div class="date">21/08/21</div>, then another plugin removes the title tag and replace it by a thumbnail <div class="title"><img src="..."/></div><div class="date">21/08/21</div>, etc.
    • Advantage is that multiple plugins can modify the content
    • Disadvantage is that each plugin will have to be careful about how they change it - for example they shouldn't expect that a particular is going to be present, since it might have been removed by another plugin. So in a way conflicts are still possible.

Plugin defines a view instead of a renderer

Perhaps plugins could define a view instead of a renderer, then it's up to the user what view they choose. The chosen view will be fully responsible for rendering the note list content, and so no conflicts are possible.

@laurent22 laurent22 added spec Fully developed spec that can serve as a starting point for a project plugins Anything related to Joplin's plugin system labels Aug 27, 2021
@prashantkamdar
Copy link

I came here from this thread: https://discourse.joplinapp.org/t/include-some-of-note-body-in-note-list/3874/39

Having a small preview of the note will be an amazing feature!

@MarleneMayr
Copy link

YES! I would love thumbnails on notes.

@7aklhz
Copy link

7aklhz commented Jun 3, 2022

+1 for preview of note !!

@laurent22
Copy link
Owner Author

Another case we'd like to support with the note list update: https://discourse.joplinapp.org/t/is-joplin-a-good-alternative-for-teams-wiki/30489/3?u=laurent

@nokoa77
Copy link
Sponsor

nokoa77 commented Aug 7, 2023

I would like a plugin that could display additional info in columns in the note list, eg. : modification date, location, number of edits, ...

@CrazyEyesEddie
Copy link

I'm happy either way. Stay with the same system, or implement a new system. I doubt I'd use a display of cards (I didn't when I used Evernote), but maybe a list with snippets and tags would be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugins Anything related to Joplin's plugin system spec Fully developed spec that can serve as a starting point for a project
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants